摘要:实际开发中的,通用异常处理,通用日志处理,事物处理都可以用到动态代理。四总结优点动态代理类简化了代码编程工作,提高了软件的可扩展性。
JDK的动态代理
一、静态代理
了解动态代理前,有必要先讲解下静态代理。
举个例子:银行开通了短信业务,在你取钱,存钱,转账后都会 给你发送短信,我们来模拟下业务场景。
静态代理的实现
下面来模拟下业务代码
1.定义IBankCardService接口
/** * 银行卡操作接口 * @author yizl * */ public interface IBankCardService { /** * 存钱 * @param cardId */ public void putInMoney(String cardId); /** * 取钱 * @param cardId */ public void outMoney(String cardId); /** * 查询余额 * @param cardId */ public String getMoney(String cardId); }
2.接口实现(BankCardServiceImpl)
/** * 银行卡操作实现类 * @author yizl * */ public class BankCardServiceImpl implements IBankCardService { @Override public void putInMoney(String cardId) { System.out.println("开始往银行卡账号为:"+cardId+" 存钱"); } @Override public void outMoney(String cardId) { System.out.println("向银行卡账号为:"+cardId+" 取钱"); } @Override public String getMoney(String cardId) { System.out.println("查询银行卡账号为:"+cardId+" 的余额"); return null; } }
3.编写代理类
假设项目经理有个需求:在每次业务操作后都需要向用户发送短信.
在不修改已有的实现类的前提下怎么实现这个需求.
1.我们写一个代理类,让它与银行卡操作实现类的接口相同.
2.在代理类的构造器中,传入银行卡操作实现类,在代理类的方法内部仍然调用银行卡操作实现类的方法.
代理类
/** * 代理银行卡操作实现类 * @author yizl * */ public class ProxyBankCardServiceImpl implements IBankCardService { private IBankCardService bankCardService; public ProxyBankCardServiceImpl(IBankCardService bankCardService) { this.bankCardService=bankCardService; } @Override public void putInMoney(String cardId) { bankCardService.putInMoney(cardId); System.out.println("向客户发送短信"); } @Override public void outMoney(String cardId) { bankCardService.outMoney(cardId); System.out.println("向客户发送短信"); } @Override public String getMoney(String cardId) { bankCardService.getMoney(cardId); System.out.println("向客户发送短信"); return null; } }
4.调用代理类
public class ProxyTest { public static void main(String[] args) { IBankCardService bankCardService =new BankCardServiceImpl(); IBankCardService proxyBankCard=new ProxyBankCardServiceImpl(bankCardService); proxyBankCard.putInMoney("9527"); } } 打印结果: 开始往银行卡账号为:9527的账户存钱 向客户发送短信
可以看出,代理类的作用:代理对象=增强代码+目标对象
代理类只对银行卡操作实现类进行增强,每个方法都添加发送短信业务,真正业务还是在银行卡操作实现类中在进行。
静态代理的缺点
我们发现静态代码其实很麻烦,有点脱裤子放屁的意思.
静态代理的缺点:
1.要为每一个目标类都要编写相应的代理类,会有很多代理类。 2.接口改了,目标类和代理类都要跟着改。
二、动态代理
我们只想写增强的代码,不需要写代理类,增强代码还可以复用到不同的目标类。这时动态代理横空出世了。
动态代理实现
1、获取代理类方式一
1.JDK提供了 java.lang.reflect.Proxy类有一个getProxyClass(ClassLoader, interfaces)静态方法,传入类加载器,和接口,就可以得到代理类的Class对象.
2.得到了代理类的class对象,通过代理类的class对象得到构造器,java.lang.reflect.InvocationHandler类中,每一个动态代理类都要实现InvocationHandler接口,动态代理对象调用一个方法时,就会转到实现InvocationHandler接口类的invoke方法.
3.得到代理类,实行调用.
public class ProxyTest { public static void main(String[] args) throws Exception { //目标对象 IBankCardService bankCard=new BankCardServiceImpl(); //获取代理对象 IBankCardService proxyBank = (IBankCardService) getProxy(bankCard); //调用方法 proxyBank.getMoney("9527"); } /** * 获取代理类 * @param target 目标类 * @return * @throws SecurityException * @throws NoSuchMethodException */ private static Object getProxy(Object target) throws Exception { //得到代理类大class Class proxyClass = Proxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces()); //创建代理类的构造函数,构造函数的方法必须传入InvocationHandler接口的实现类 Constructor constructor=proxyClass.getConstructor(InvocationHandler.class); //获取代理类 Object proxy =constructor.newInstance(new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用目标文件的方法 Object resulet = method.invoke(target,args); //增强方法 System.out.println("向客户发送短信"); return resulet; } }); return proxy; } } 打印结果: 查询银行卡账号为:9527的账户 的余额 向客户发送短信
2、获取代理类方式二
实际变成中不会使用getProxyClass(),因为JDK的Proxy类提供了更好用的方法newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler h),直接传入InvocationHandler 实现类就可以的到代理类.
1.代理类的调用处理程序实现
/** * 发送短信调用类 * @author yizl * */ public class SendMessageInvocation implements InvocationHandler { /** * 目标类 */ private Object obj; /** * 通过构造方法传参 * @param obj */ public SendMessageInvocation(Object obj) { this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //调用目标文件的方法 Object resulet = method.invoke(obj,args); //增强方法 System.out.println("向客户发送短信"); return resulet; } }
2.获取代理类,调用取钱方法
public class ProxyTest { public static void main(String[] args) throws Exception { // 获取银行卡操作实现类 IBankCardService bankCard = new BankCardServiceImpl(); // 获取银行卡操作类的代理类 IBankCardService proxyBank = (IBankCardService)Proxy.newProxyInstance(bankCard.getClass().getClassLoader(), bankCard.getClass().getInterfaces(),new SendMessageInvocation(bankCard)); proxyBank.outMoney("9527"); } } 打印结果: 向银行卡账号为:9527的账户取钱 向客户发送短信
用JDK提供的代理类,很完美的解决了,不写代理类,直接写增强方法,直接就获取到目标的代理类。
三、动态代理的应用
设计模式中有一个设计原则是开闭原则:软件中对于扩展是开放的,对于修改是封闭的。再不改变源码的情况下,拓展它的行为。 工作中接收了很多以前的代码,里面的逻辑让人摸不透,就可以使用代理类进行增强。 Spring的AOP就是Java的动态代理来实现的切面编程。 RPC框架,框架本身不知道要调用哪些接口,哪些方法。这是框架可以一个创建代理类给客户端使用。 实际开发中的,通用异常处理,通用日志处理,事物处理都可以用到动态代理。
四、总结
优点:
动态代理类简化了代码编程工作,提高了软件的可扩展性。
缺点:
JDK动态代理只能代理有接口的实现类,没有接口的类就不能用JDK的动态代理。(Cglib动态代理可以对没有接口的类实现代理)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/77763.html
摘要:要明白,动态代理类的存在意义是为了拦截方法并修改逻辑而动态代理的局限性之一就是只能拦截接口所声明的方法。因为动态代理类是继承自业务类,所以该类和方法不能声明成无法继承或重写。者最终都是生成了一个新的动态代理类对象。 动态代理 1、先谈静态代理 对于静态代理,我们已经很熟悉了。我们拥有一个抽象类,真实类继承自抽象类并重写其业务方法,代理类持有真实类的对象实例,在重写业务方法中通过调用真实...
摘要:动态代理的核心是接口和类。以上结果说明它生成的代理类为,说明是代理。测试前提实现接口测试类使用接口方式注入代理方式必须以接口方式注入测试配置为,运行结果如下实际校验逻辑。。。。 本文也同步发布至简书,地址:https://www.jianshu.com/p/f70... AOP设计模式通常运用在日志,校验等业务场景,本文将简单介绍基于Spring的AOP代理模式的运用。 1. 代理模...
摘要:与静态代理对比,动态代理是在动态生成代理类,由代理类完成对具体方法的封装,实现的功能。本文将分析中两种动态代理的实现方式,和,比较它们的异同。那如何动态编译呢你可以使用,这是一个封装了的库,帮助你方便地实现动态编译源代码。 发现Java面试很喜欢问Spring AOP怎么实现的之类的问题,所以写一篇文章来整理一下。关于AOP和代理模式的概念这里并不做赘述,而是直奔主题,即AOP的实现方...
摘要:值得一提的是由于采用动态创建子类的方式生成代理对象,所以不能对目标类中的方法进行代理。动态代理中生成的代理类是子类,调试的时候可以看到,打开源码可看到实现了和也就实现方法。 前面讲到了动态代理的底层原理,接下来我们来看一下aop的动态代理.Spring AOP使用了两种代理机制:一种是基于JDK的动态代理,一种是基于CGLib的动态代理. ①JDK动态代理:使用JDK创建代理有一个限制...
阅读 2622·2023-04-26 00:07
阅读 2431·2021-11-15 11:37
阅读 638·2021-10-19 11:44
阅读 2163·2021-09-22 15:56
阅读 1716·2021-09-10 10:50
阅读 1497·2021-08-18 10:21
阅读 2565·2019-08-30 15:53
阅读 1630·2019-08-30 11:11