[java] (인터페이스가 아닌) 추상 클래스의 프록시를 생성하기위한 java.lang.reflect.Proxy의 대안

문서 에 따르면 :

[ java.lang.reflect.] Proxy는 동적 프록시 클래스 및 인스턴스를 생성하기위한 정적 메서드를 제공하며 이러한 메서드에 의해 생성 된 모든 동적 프록시 클래스의 수퍼 클래스이기도합니다.

(동적 프록시 생성을 담당 하는) newProxyMethod메서드 에는 다음과 같은 서명이 있습니다.

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                             throws IllegalArgumentException

불행히도 이것은 특정 인터페이스를 구현하는 대신 특정 추상 클래스 를 확장 하는 동적 프록시를 생성하는 것을 방지 합니다. 이것은 “모든 동적 프록시의 수퍼 클래스”를 고려 하여 다른 클래스가 수퍼 클래스가되는 것을 방지 하므로 의미 가 있습니다.java.lang.reflect.Proxy

따라서 특정 추상 클래스에서 상속java.lang.reflect.Proxy 하는 동적 프록시를 생성 하여 추상 메서드에 대한 모든 호출을 호출 핸들러로 리디렉션 할 수 있는 대안이 있습니까?

예를 들어 추상 클래스가 있다고 가정합니다 Dog.

public abstract class Dog {

    public void bark() {
        System.out.println("Woof!");
    }

    public abstract void fetch();

}

다음을 수행 할 수있는 수업이 있습니까?

Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);

dog.fetch(); // Will be handled by the invocation handler
dog.bark();  // Will NOT be handled by the invocation handler



답변

Javassist (참조 ProxyFactory) 또는 CGLIB를 사용하여 수행 할 수 있습니다 .

Javassist를 사용한 Adam의 예 :

나는 (Adam Paynter) Javassist를 사용하여이 코드를 작성했습니다.

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Dog.class);
factory.setFilter(
    new MethodFilter() {
        @Override
        public boolean isHandled(Method method) {
            return Modifier.isAbstract(method.getModifiers());
        }
    }
);

MethodHandler handler = new MethodHandler() {
    @Override
    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        System.out.println("Handling " + thisMethod + " via the method handler");
        return null;
    }
};

Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
dog.bark();
dog.fetch();

다음 출력을 생성합니다.

씨!
메소드 핸들러를 통해 public abstract void mock.Dog.fetch () 처리


답변

이러한 경우에 할 수있는 일은 추상 클래스의 기존 메서드로 호출을 리디렉션하는 프록시 처리기를 갖는 것입니다.

물론 코드를 작성해야하지만 매우 간단합니다. 프록시를 만들려면 그에게 InvocationHandler. 그런 다음 invoke(..)호출 핸들러 의 메서드 에서 메서드 유형 만 확인하면 됩니다. 그러나주의하십시오. 추상 클래스의 선언 된 유형이 아닌 핸들러에 연결된 기본 객체에 대해 메서드 유형을 확인해야합니다.

개 클래스를 예로 들어 보면 호출 핸들러의 invoke 메소드 다음과 같을 수 있습니다 (.. well …이라는 기존의 연관된 dog 하위 클래스 포함 dog).

public void invoke(Object proxy, Method method, Object[] args) {
    if(!Modifier.isAbstract(method.getModifiers())) {
        method.invoke(dog, args); // with the correct exception handling
    } else {
        // what can we do with abstract methods ?
    }
}

하지만 궁금해하는 점이 dog있습니다. 객체에 대해 이야기했습니다 . 그러나 Dog 클래스는 추상이므로 인스턴스를 만들 수 없으므로 기존 하위 클래스가 있습니다. 또한 Proxy 소스 코드를 철저히 조사한 결과 인터페이스를 나타내지 않는 Class 객체에 대해 Proxy를 생성 할 수 없음을 (Proxy.java:362에서) 발견 할 수 있습니다.

그래서 현실 과는 별도로 하고 싶은 일이 완벽하게 가능합니다.


답변