上一篇: 对静态代理的理解
接上一篇,学习了静态代理后再来看看动态代理的机制。
在上一篇博客中,我们使用静态代理实现了在修改登录模块代码的情况下增加上报需求,但是有个缺点:新增登录方式必须新建代理类,例如要实现QQ登录,必须新建QQLogin、QQLoginProxy......,如果这种需求多来一点那代理类会爆炸,动态代理可以解决这个问题。
实现
新建动态代理类:
import org.springframework.cglib.proxy.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object realObject;
public DynamicProxyHandler(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理扩展逻辑
System.out.println("动态代理类 开始执行操作...");
System.out.println( "打印动态代理方法Method:" + method);
return method.invoke(realObject, args);
}
}
是用方法:
import org.springframework.cglib.proxy.Proxy;
public class Test {
public static void main(String[] args) {
//使用账号密码登录
Login realObject = new Login();
LoginInterface loginInterface = (LoginInterface) Proxy.newProxyInstance(LoginInterface.class.getClassLoader(), new Class[]{LoginInterface.class}, new DynamicProxyHandler(realObject));
loginInterface.print();
loginInterface.test();
//使用微信登录
WechatLogin wechatLogin = new WechatLogin();
LoginInterface loginInterface1 = (LoginInterface) Proxy.newProxyInstance(LoginInterface.class.getClassLoader(), new Class[]{LoginInterface.class}, new DynamicProxyHandler(wechatLogin));
loginInterface1.print();
}
}
打印结果:
动态代理类 开始执行操作...
打印动态代理方法Method:public abstract void com.demo.springcloud.client1.client1.LoginInterface.print()
专注于账号密码登录中...
动态代理类 开始执行操作...
打印动态代理方法Method:public abstract void com.demo.springcloud.client1.client1.LoginInterface.test()
测试打印方法...
动态代理类 开始执行操作...
打印动态代理方法Method:public abstract void com.demo.springcloud.client1.client1.LoginInterface.print()
专注于微信登录中...
一个动态代理实现就完成了,不需要再写什么LoginProxy和wechatLoginProxy这样的代理类,一个DynamicProxyHandler 就行了。
原理
代理类实现了InvocationHandler 类,重写方法
public Object invoke(Object proxy, Method method, Object[] args)
proxy: 我们所代理的那个真实对象
method: 我们所要调用真实对象的某个方法的Method对象
args: 调用真实对象某个方法时接受的参数
所以打印结果里,method打印为
Method:public abstract void com.demo.springcloud.client1.client1.LoginInterface.print()
Method:public abstract void com.demo.springcloud.client1.client1.LoginInterface.test()
调用哪个方法,就会动态传入哪个方法为参数并执行。
动态代理相对于静态代理优势有以下几点:
1.不再需要手动创建对应代理类,例如:LoginProxy、WechatLoginProxy
2.可以代理任意实现了LoginInterface接口的类对象,并执行接口的任意方法