代理模式。静态代理,动态代理,CGLib代理
参考:https://www.cnblogs.com/puyangsky/p/6218925.html
代理模式
3个组成部分:1、接口 2、接口实现类 3、代理类
静态代理
接口类
1 2 3 | interface Person { void speak(); } |
接口实现类:
1 2 3 4 5 6 7 8 9 10 11 | class Actor implements Person { private String content; public Actor(String content) { this .content = content; } @Override public void speak() { System.out.println( this .content); } } |
代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Agent implements Person { private Actor actor; private String before; private String after; public Agent(Actor actor, String before, String after) { this .actor = actor; this .before = before; this .after = after; } @Override public void speak() { //before speak System.out.println( "Before actor speak, Agent say: " + before); //real speak this .actor.speak(); //after speak System.out.println( "After actor speak, Agent say: " + after); } }<br> |
测试类:
1 2 3 4 5 6 7 | public class StaticProxy { public static void main(String[] args) { Actor actor = new Actor( "I am a famous actor!" ); Agent agent = new Agent(actor, "Hello I am an agent." , "That's all!" ); agent.speak(); } } |
结果:
静态代理的核心思想:代理类中包含接口实现类,在代理类中调用接口。
动态代理
首先介绍一下最核心的一个接口和一个方法:
首先是java.lang.reflect包里的InvocationHandler接口:
1 2 3 4 | public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } |
我们对于被代理的类的操作都会由该接口中的invoke方法实现,其中的参数的含义分别是:
- proxy:被代理的类的实例
- method:调用被代理的类的方法
- args:该方法需要的参数
代理类实现InvocationHandler接口,通过 invoke方法调用实际的接口实现类方法
另外一个很重要的静态方法是java.lang.reflect包中的Proxy类的newProxyInstance方法:
1 2 3 4 | public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException |
其中的参数含义如下:
- loader:被代理的类的类加载器 。interfaceClazz.getClassLoader(),即接口类的类加载器
- interfaces:被代理类的接口数组。new Class[]{interfaceClazz},即接口类
- invocationHandler:就是刚刚介绍的调用处理器类的对象实例。就是代理类实例
接口:
1 2 3 | public interface Fruit { public void show(); } |
接口实现类:
1 2 3 4 5 6 | public class Apple implements Fruit{ @Override public void show() { System.out.println( "<<<<show method is invoked" ); } } |
代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class DynamicAgent { //实现InvocationHandler接口,并且可以初始化被代理类的对象 static class MyHandler implements InvocationHandler { private Object proxy; public MyHandler(Object proxy) { this .proxy = proxy; } //自定义invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( ">>>>before invoking" ); //真正调用方法的地方 Object ret = method.invoke( this .proxy, args); System.out.println( ">>>>after invoking" ); return ret; } } //返回一个被修改过的对象 public static Object agent(Class interfaceClazz, Object proxy) { return Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz}, new MyHandler(proxy)); } } |
测试:
1 2 3 4 5 6 7 | public class ReflectTest { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { //注意一定要返回接口,不能返回实现类否则会报错 Fruit fruit = (Fruit) DynamicAgent.agent(Fruit. class , new Apple()); fruit.show(); } } |
结果:
缺点:必须实现接口
CGLIB库的方法 核心:动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
CGlib是一个字节码增强库,为AOP等提供了底层支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | 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 CGlibAgent implements MethodInterceptor { private Object proxy; public Object getInstance(Object proxy) { this .proxy = proxy; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass( this .proxy.getClass()); // 回调方法 enhancer.setCallback( this ); // 创建代理对象 return enhancer.create(); } //回调方法 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println( ">>>>before invoking" ); //真正调用 Object ret = methodProxy.invokeSuper(o, objects); System.out.println( ">>>>after invoking" ); return ret; } public static void main(String[] args) { CGlibAgent cGlibAgent = new CGlibAgent(); Apple apple = (Apple) cGlibAgent.getInstance( new Apple()); apple.show(); } } |
参考:https://www.jianshu.com/p/829e93528d56
被代理类:
1 2 3 4 5 6 7 8 9 | public class HelloServiceImpl { public void sayHello(){ System.out.println( "Hello Zhanghao" ); } public void sayBey(){ System.out.println( "Bye Zhanghao" ); } } |
代理类,实现
1 2 3 4 5 6 7 8 9 | public class HelloMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println( "Before: " + method.getName()); Object object = methodProxy.invokeSuper(o, objects); System.out.println( "After: " + method.getName()); return object; } } |
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class Client { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/zhanghao/Documents/toy/spring-framework-source-study/" ); Enhancer enhancer = new Enhancer(); //继承被代理类 enhancer.setSuperclass(HelloServiceImpl. class ); //设置回调 enhancer.setCallback( new HelloMethodInterceptor()); //设置代理类对象 HelloServiceImpl helloService = (HelloServiceImpl) enhancer.create(); //在调用代理类中方法时会被我们实现的方法拦截器进行拦截 helloService.sayBey(); } } result: Before: sayBey Bye Zhanghao After: sayBey |
核心思想:代理类实现MethodInterceptor结果。通过Enhancer将被代理类设置成超类,代理类设置为回调,通过create()创建实例,通过实例调用方法,即完成调用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)