首页 » 99链接平台 » 设计模式之动态代理(代理对象动态方法模拟)

设计模式之动态代理(代理对象动态方法模拟)

神尊大人 2024-11-03 07:38:19 0

扫一扫用手机浏览

文章目录 [+]

而AOP指的是面向切面编程,定义一个切面,用切面去切相应的方法,就可以织入增强的逻辑。
相应的方法是指核心的业务逻辑,切面逻辑使用代理模式来实现。

关于AOP的单元测试查看SpringAOP面向切面编程功能测试

什么是代理模式?

代理代表某个真实的对象,代理提供了对真实对象另外的访问方式——即通过代理对象访问真实对象。
真实对象又可称目标对象。

设计模式之动态代理(代理对象动态方法模拟) 99链接平台
(图片来自网络侵删)

这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

涉及到的编程原则就是开闭原则:不要随意去修改别人已经写好的代码或者方法,如果需要修改,可以通过代理的方式来扩展该方法。

举个例子:假设我们想邀请一位明星,那么并不是直接对接明星,而是联系明星的经纪人来达到同样的目的。
明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决。
这就是代理思想在现实中的一个例子。

静态代理

静态代理,简单点来说就是在程序运行之前,代理类和被代理类的关系已经确定。
静态代理的实现首先要定义一个公共的接口,然后代理类和被代理类都实现这个接口,如下:

//接口public interface IUserDao { void save(); String find();}

//目标对象public class UserDao implements IUserDao{private ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();@Overridepublic void save() {System.out.println("模拟保存用户");concurrentHashMap.put("1", "张三");}@Overridepublic String find() {System.out.println("模拟查找用户");return concurrentHashMap.get("1");}}

//代理对象public class UserDaoProxy implements IUserDao{private UserDao ud = new UserDao();@Overridepublic void save() {System.out.println("代理操作,开启事务");//模拟的增强处理ud.save();System.out.println("代理操作,关闭事务");//模拟的增强处理}@Overridepublic String find() {return ud.find();}}

静态代理最大的缺点:我们得为每一个服务创建代理类,工作量太大不易管理;同时接口一旦发生改变,代理类也得相应修改。

动态代理

在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。
真正的代理对象由JDK在运行时为我们动态的来创建。

JDK动态代理:Java为我们创建了Proxy类,动态生成的代理类有一个共同的父类叫Proxy,我们需要告诉Proxy做什么。
我们不能像静态代理那样把自己的代码放在Proxy类,因为Proxy类不是我们自己创建的。
Java提供了动态处理器InvocationHandler接口。

InvocationHandler的工作是响应代理的任何调用,它是代理收到方法调用后,请求做实际工作的对象。

JDK实现动态代理,是通过Proxy的静态方法newProxyInstance来创建代理对象的,该方法有三个参数:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

ClassLoader loader:指定当前目标对象使用的类加载器

Class<?>[] interfaces:目标对象实现的接口的集合,使用泛型方式确认类型

InvocationHandler h:指定动态处理器,执行目标对象的方法时,会触发事件处理器的invoke方法,会把当前执行目标对象的方法作为参数传入

public void useJDKProxy() { System.out.println("-------useJDKProxy-------"); final UserDao ud = new UserDao(); // 生成代理对象 IUserDao iud = (IUserDao) Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), / 因为InvocationHandler是个接口,所以可以使用匿名内部类的方式进行实现 / new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy================"+proxy.getClass().getName());//模拟的增强处理 Object result = null; result = method.invoke(ud, args); System.out.println(method.getName()+"================"+result);//模拟的增强处理 return result; } }); iud.save(); iud.find(); }

执行结果:

-------useJDKProxy-------proxy================com.sun.proxy.$Proxy0模拟保存用户save================nullproxy================com.sun.proxy.$Proxy0模拟查找用户find================张三

从输出可以看出JDK生成的代理对象名称为:com.sun.proxy.$Proxy0,关于动态生成代理的名称,debug调用栈到Proxy.ProxyClassFactory.apply:

以下两行代码就是生成代理对象名称的源码:

private static final String proxyClassNamePrefix = "$Proxy";String proxyName = proxyPkg + proxyClassNamePrefix + num;

CGLIB代理

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,需要通过CGLib实现动态代理。

CGLib创建代理对象是通过net.sf.cglib.proxy.Enhancer实现的,代理收到方法调用后,请求做实际工作的对象是MethodInterceptor。

public class CglibProxy implements MethodInterceptor { private Object target; public Object getInstance(final Object target) { this.target = target; Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(this.target.getClass());//设置目标对象 enhancer.setCallback(this);//设置代理拦截器MethodInterceptor return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("obj============="+obj.getClass().getName());//模拟的增强处理 System.out.println("method============="+method.getName()); System.out.println("proxy============="+proxy.getSignature()); Object result=proxy.invokeSuper(obj, args);//目标方法 System.out.println("方法执行返回============="+result);//模拟的增强处理 return result; }}

执行结果:

--------useCGlibProxy--------obj=============proxy.staticProxy.UserDao$$EnhancerByCGLIB$$d229b515method=============saveproxy=============save()V模拟保存用户方法执行返回=============nullobj=============proxy.staticProxy.UserDao$$EnhancerByCGLIB$$d229b515method=============findproxy=============find()Ljava/lang/String;模拟查找用户方法执行返回=============张三

CGlib生成的代理对象包含一个子对象EnhancerByCGLIB字样在名称里面。
debug调用栈

Enhancer.create()->Enhancer.createHelper()->AbstractClassGenerator.create(Object key)->DefaultGeneratorStrategy.generate(ClassGenerator cg)->Enhancer.generateClass()->AbstractClassGenerator.getClassName()->AbstractClassGenerator.getClassName()->DefaultNamingPolicy.getClassName(final ClassLoader loader),有一个变量bese定义了cglib代理类名称,如下:

String base = prefix + "$$" + source.substring(source.lastIndexOf('.') + 1) + getTag() + "$$" + Integer.toHexString(key.hashCode()); //变量值 prefix=proxy.staticProxy.UserDao source=net.sf.cglib.proxy.Enhancer key=proxy.staticProxy.UserDao protected String getTag() { return "ByCGLIB"; } base=proxy.staticProxy.UserDao$$EnhancerByCGLIB$$3b964c77

#程序员#

标签:

相关文章

语言的世界之旅,分类法下的语言奥秘

在人类文明的浩瀚长河中,语言作为一种独特的交流工具,承载着人类思想、文化和情感的传递。语言学家们通过对语言的深入研究,将语言进行了...

99链接平台 2025-01-01 阅读2 评论0

跨语言视角下的“发财”文化现象介绍

“发财”一词,在各个语言中都有其独特的表达方式和内涵。从汉语到英语,从阿拉伯语到日语,发财文化在全球范围内都有着广泛的影响力。本文...

99链接平台 2025-01-01 阅读1 评论0

网络透传协议,构建高效信息传输的基石

随着信息技术的飞速发展,网络通信已经成为现代社会不可或缺的一部分。而在众多网络通信协议中,网络透传协议因其高效、稳定、安全的特点,...

99链接平台 2025-01-01 阅读1 评论0