ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

JDK的动态代理

JDK的动态代理 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 的余额);returnnull;}}3.编写代理类假设项目经理有个需求:在每次业务操作后都需要向用户发送短信.在不修改已有的实现类的前提下怎么实现这个需求.1.我们写一个代理类,让它与银行卡操作实现类的接口相同.2.在代理类的构造器中,传入银行卡操作实现类,在代理类的方法内部仍然调用银行卡操作实现类的方法.代理类/** * 代理银行卡操作实现类 * author yizl * */ public class ProxyBankCardServiceImpl implements IBankCardService{private IBankCardService bankCardService;public ProxyBankCardServiceImpl(IBankCardService bankCardService){this.bankCardServicebankCardService;}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(向客户发送短信);returnnull;}}4.调用代理类public class ProxyTest{public static void main(String[]args){IBankCardService bankCardServicenew BankCardServiceImpl();IBankCardServiceproxyBankCardnew ProxyBankCardServiceImpl(bankCardService);proxyBankCard.putInMoney(9527);}}打印结果: 开始往银行卡账号为:9527的账户存钱 向客户发送短信可以看出,代理类的作用:代理对象增强代码目标对象代理类只对银行卡操作实现类进行增强每个方法都添加发送短信业务真正业务还是在银行卡操作实现类中在进行。静态代理的缺点我们发现静态代码其实很麻烦,有点脱裤子放屁的意思.静态代理的缺点二、动态代理我们只想写增强的代码不需要写代理类增强代码还可以复用到不同的目标类。这时动态代理横空出世了。动态代理实现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{//目标对象 IBankCardServicebankCardnew 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 proxyClassProxy.getProxyClass(target.getClass().getClassLoader(), target.getClass().getInterfaces());//创建代理类的构造函数,构造函数的方法必须传入InvocationHandler接口的实现类 ConstructorconstructorproxyClass.getConstructor(InvocationHandler.class);//获取代理类 Object proxyconstructor.newInstance(newInvocationHandler(){Override public Object invoke(Object proxy, Method method, Object[]args)throws Throwable{//调用目标文件的方法 Object resuletmethod.invoke(target,args);//增强方法 System.out.println(向客户发送短信);returnresulet;}});returnproxy;}}打印结果: 查询银行卡账号为: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.objobj;}Override public Object invoke(Object proxy, Method method, Object[]args)throws Throwable{//调用目标文件的方法 Object resuletmethod.invoke(obj,args);//增强方法 System.out.println(向客户发送短信);returnresulet;}}2.获取代理类调用取钱方法public class ProxyTest{public static void main(String[]args)throws Exception{// 获取银行卡操作实现类 IBankCardService bankCardnew 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动态代理可以对没有接口的类实现代理
返回列表