1.动态代理的特点
字节码随用随创建 随用随加载;
它与静态代理的区别也在于此,因此静态代理是字节码一上来就创建好,并且完成加载。
装饰者模式就是静态代理的一种体现
2、动态代理常用的两种方式
基于接口的动态代理
JDK官方提供的的Proxy类
要求: 被代理类最少要实现一个接口,如果没有,则不能使用
.getClassLoader()类加载器, 用于加载代理对象字节码的,和被代理对象使用相同的类加载器
InvocationHandler()用于增强的代码
它是让我们写如何代理, 我们一般都是写一个该接口的实现类 通常情况下是匿名内部类
final helloAspectImpl helloAspect1 = new helloAspectImpl();//此处+ final 修饰是因为从内部类中访问本地变量helloAspect1; 需要被声明为最终类型
helloAspect helloAspect2= (helloAspect) Proxy.newProxyInstance(helloAspect1.getClass().getClassLoader(), helloAspect1.getClass().getInterfaces(), new InvocationHandler() {
/**
* 执行被代理对象的任何方法,都会经过该方法。
* 此方法有拦截的功能。
*
* 参数:
* proxy:代理对象的引用。不一定每次都用得到
* method:当前执行的方法对象
* args:执行方法所需的参数
* 返回值:
* 当前执行方法的返回值
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
Float arg = (Float) args[0];
Object result;
if ("test".equals(name)) {
result = method.invoke(helloAspect1,arg/2);
} else {
result = method.invoke(helloAspect1,arg);;
}
return result;
}
});
helloAspect2.test1(100f);
}
基于子类的动态代理
提供者 第三方的cglib
要求: 被代理对象不能为最终类()
用到的类: Enhaner
用到的方法:create
方法的参数: Class 被代理对象的字节码 Callback 如何代理
final helloAspectImpl helloAspect1 = new helloAspectImpl();//此处+ final 修饰是因为从内部类中访问本地变量helloAspect1; 需要被声明为最终类型
helloAspect o =(helloAspect) Enhancer.create(helloAspect1.getClass(), new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String name = method.getName();
Float arg = (Float) objects[0];
Object result;
if ("test".equals(name)) {
result = method.invoke(helloAspect1,arg/2);
} else {
result = method.invoke(helloAspect1,arg);;
}
return result;
}
});
o.test(100f);