Как реализовать декоратор оболочки в Java?
Проблема заключается в создании динамической расширенной версии существующих объектов.
Я не могу изменить объектClass
, Вместо этого я должен:
Class
делегировать все исходные вызовы метода для обернутого объектареализовать все методы, которые определены другим интерфейсомИнтерфейс для добавления к существующим объектам:
public interface EnhancedNode {
Node getNode();
void setNode(Node node);
Set getRules();
void setRules(Set rules);
Map getGroups();
void setGroups(Map groups);
}
СБайт Бадди Мне удалось создать подкласс и реализовать мой интерфейс. Проблема в делегировании обернутого объекта. Единственный способ сделать это, который я нашел, - это использовать рефлексию, которая слишком медленная (у меня большая нагрузка на приложение, и производительность критична).
Пока что мой код:
Class<? extends Node> proxyType = new ByteBuddy()
.subclass(node.getClass(), ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC)
.method(anyOf(finalNode.getClass().getMethods())).intercept(MethodDelegation.to(NodeInterceptor.class))
.defineField("node", Node.class, Visibility.PRIVATE)
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
.defineField("groups", Map.class, Visibility.PRIVATE)
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
.defineField("rules", Set.class, Visibility.PRIVATE)
.implement(EnhancedNode.class).intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
enhancedClass = (Class<N>) proxyType;
EnhancedNode enhancedNode = (EnhancedNode) enhancedClass.newInstance();
enhancedNode.setNode(node);
гдеNode
является объектом для подкласса / переносаNodeInterceptor
пересылает вызванные методы вgetNode
имущество.
Здесь кодNodeInterceptor
:
public class NodeInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@This EnhancedNode proxy,
@AllArguments Object[] arguments)
throws Exception {
Node node = proxy.getNode();
Object res;
if (node != null) {
res = method.invoke(method.getDeclaringClass().cast(node), arguments);
} else {
res = null;
}
return res;
}
}
Все работает, но метод перехвата слишком медленный, я планирую использовать ASM напрямую, чтобы добавить реализацию каждого метода Node, но я надеюсь, что есть более простой способ использования Byte Buddy.