Java 从静态代理到动态代理
先举个静态代理的例子,可能多少有些不恰当,不过本次学习记录,重点不在于通信协议。 比如你在一个机房里,你不能联网,只能连通过一台能连公网的代理机器上网。你发送了一个http请求,将由代理帮你上网。
首先有一个HttpMessage接口,InternetProxy(公网代理)和LANMessage(局域网发消息) 都实现HttpMessage接口。公网代理将代理LANMessage上网。实际上代理模式,增强了原来对象的方法,并且无侵入性,不需要修改原有代码。
1 public interface HttpMessage { 2 void sendMsg(String msg); 3 }
1 public class LANMessage implements HttpMessage { 2 @Override 3 public void sendMsg(String msg) { 4 System.out.println("lan send msg"); 5 } 6 }
1 public class InternetProxy implements HttpMessage { 2 3 //被代理的对象 4 LANMessage message; 5 6 @Override 7 public void sendMsg(String msg) { 8 before(); 9 message.sendMsg(msg); 10 after(); 11 } 12 13 void before() { 14 System.out.println("prepare internet msg"); 15 } 16 17 void after() { 18 System.out.println("after internet msg"); 19 } 20 }
上面只是一个静态代理增强对象的示例。当代码中有大量的 需要增强,甚至动态增强的代码时,这种代理类,会遍布项目中到处都是,并且当接口改变,代理类和实现类都要一并修改。所以有了动态代理。
jdk动态代理:
无需创建代理类,直接使用,会生成class文件,class文件也将被加载到内存中的Class对象,有了class对象,就有了类的所有信息,在调用方法的时候,动态代理相当于拦截了我们所有的调用,你可以在invoke中对目标对象和其方法进行增强。也应该不难想到,new instance 基本上就是通过拿到的class对象,来拿到其Contrustor 来构造对象。如果反编译生成的class文件,也可以看到在调用方法的时候,刚实现的invoke方法会被调用。 Class对象在手,天下我有~
1 public class TestProxy { 2 3 LANMessage msg=new LANMessage(); 4 @Test 5 public void fun(){ 6 HttpMessage message=(HttpMessage) Proxy.newProxyInstance(LANMessage.class.getClassLoader(), LANMessage.class.getInterfaces(), new InvocationHandler() { 7 @Override 8 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 9 System.out.println("before"); 10 Object res= method.invoke(msg,args); 11 System.out.println("after"); 12 return res; 13 } 14 }); 15 message.sendMsg("hello"); 16 } 17 }
CGLib方式:
该方式可代理任何类 不需要提供接口。其生成的class字节码文件,反编译后可以看到 它生成的是委托类的子类。
1 public class TestProxy { 2 3 LANMessage msg = new LANMessage(); 4 5 @Test 6 public void fun() { 7 8 CGLibProxy proxy=new CGLibProxy(); 9 HttpMessage msg=(HttpMessage) proxy.getProxy(LANMessage.class); 10 msg.sendMsg("hi"); 11 } 12 } 13 14 class CGLibProxy implements MethodInterceptor { 15 16 public Object getProxy(Class<?> clazz) { 17 return Enhancer.create(clazz, this); 18 } 19 20 @Override 21 public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable { 22 System.out.println("before"); 23 Object res = proxy.invokeSuper(o, args); 24 System.out.println("afert"); 25 return res; 26 } 27 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?