动态代理
特点:字节码随用随创建,随用随加载
作用:不修改源码的基础上对方法进行加强
分类:
1.基于接口的动态代理(JDK)
要求:被代理的类至少实现一个接口,否则不能被代理
创建代理对象:使用JDK中Proxy类的newProxyInstance方法
参数:
ClassLoader:类加载器
用于加载被代理对象字节码,写法固定
Class[]:字节码数组
用于让代理对象和被代理对象有相同的方法,写法固定
InvocationHandler:提供增强的代码
一般用匿名内部类实现该接口
2.基于子类的动态代理(cglib)
要求:被代理的类不能用final修饰
创建代理对象:使用第三方cglib库中Enhancer类中create方法
参数:
Class:字节码
被代理对象的字节码
Callback:提供增强的代码
一般用该接口的子接口MethodInterceptor实现匿名内部类
注意:在使用cglib架包进行动态代理时,还应导入asm架包,两个架包可能会不兼容
cglib-2.2.jar和asm-3.3.jar兼容
参考链接:https://juejin.im/post/5e8ad506e51d4547165507b2
视频讲解:https://www.bilibili.com/video/BV1Sb411s7vP?p=54
例子
一个男孩tom喜欢一个女孩,他可以直接对女孩说“I like you as much as I like Java”。但是男孩tom比较腼腆,所以他请女孩的闺蜜jane进行转告,此时,女孩的闺蜜jane就是男孩tom的“代理”。
男孩类
package com.test;
public class Boy {
//被代理的方法
public void say(String name,String word){
System.out.println(name+" say: '"+word+"'");
}
public void work(){
System.out.println("I can earn 300 yuan a day");
}
}
女孩类
package com.test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Girl {
public static void main(String[] args) {
//男孩Tom
Boy tom = new Boy();
tom.say("Tom","I like you as much as I like Java");
tom.work();
//使用基于cglib的动态代理
//女孩闺蜜Jane,相当于Tom的代理人,中间传话的
Boy jane = (Boy) Enhancer.create(tom.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
if("say".equals(method.getName())){
args[0] = "Jane";
args[1] = "Tom like you as much as he like Java";//重新组织语言
obj = method.invoke(tom,args);//被代理的是tom
}
return obj;
}
});
jane.say("Tom","I like you as much as I like Java");
jane.work();//并不输出任何内容,只增强say方法的功能
}
}
输出结果
**不使用代理
Tom say: 'I like you as much as I like Java'
I can earn 300 yuan a day
**使用代理
Jane say: 'Tom like you as much as he like Java'