0%

动态代理

动态代理

什么是动态代理

代理类在程序运行时创建的代理方式被称之为动态代理。这中代理类非同与手动指定,而是在代码中配置动态生成的。

相比较于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。不过其代理对象必须某个接口的实现,他是通过在运行期间创建一个接口的实现类来实现目标的代理。

使用动态代理

InvocationHandler 接口

在使用动态代理时,需要定义一个Handler充当代理类动向的处理器,当我们调用代理类的当法时候会自动执行到Handler的Invoke方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public interface InvocationHandler {


/**
* @param proxy 代理方法被调用的代理实例
* @param method 调用的代理类方法
* @param args 方法参数
* @return 返回一个代理对象的处理器
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;

}

生成代理类

Java提供了Proxy.newProxyInstance来生成对应的代理类。

1
2
3
4
5
6
7
8
9
10

/**
* @param loader classLoader
* @param interfaces 方法所继承的接口
* @param h 执行器
* @return 代理对象
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h);

执行方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

public class Test {

@Tset
public void test() {
String target = "";
String method = ""
Class<?> aClass = Class.forName(target);
InvocationHandler handler = new DefaultInvocationHandler(aClass);
Object o = Proxy.newProxyInstance(aClass.getClassLoader(),
new Class<?>[]{aClass},
handler);
Method me = o.getClass().getDeclaredMethod(method);
me.invoke(o);
}
}

~~~


## 为接口动态生成代理方法
在研究feign的源码的时候,发现feign仅仅就声明了一个接口,并没有对应的实现方法。

其原理也是通过代理模式为接口自动生成了一个执行器。我自己也大致模拟了一下,假如class对象是interface的话,自动为其创建一个代理类。如果有default方法则执行default方法,否则在找不到实现方法的时候不执行。

Class<?> aClass = Class.forName(target);

if (aClass.isInterface()) {
InvocationHandler handler = new DefaultInvocationHandler(aClass);
Object o = Proxy.newProxyInstance(aClass.getClassLoader(),
new Class<?>[]{aClass},
handler);
Method me = o.getClass().getDeclaredMethod(method);
return me.invoke(o);
}

static class DefaultInvocationHandler implements InvocationHandler {

private final Class target;

DefaultInvocationHandler(Class target) {
    this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // if method is default,don't rewrite
    if (method.isDefault()) {
        Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
                .getDeclaredConstructor(Class.class, int.class);
        constructor.setAccessible(true);

        Class<?> declaringClass = method.getDeclaringClass();
        int allModes = MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE;

        return constructor.newInstance(declaringClass, allModes)
                .unreflectSpecial(method, declaringClass)
                .bindTo(proxy)
                .invokeWithArguments(args);
    }

    return null;
}

}

~~~