Spring框架——自动代理

Spring框架中的面向切面思想在实现的过程中,核心的技术就是动态代理

目的:

在实际开发中,通常为目标类的所有业务方法附加通用性的增强功能,比如日志功能、事务处理等。最简单的方式,将表示增强功能的代码直接添加到业务方法中。

将表示增强功能的代码直接添加到业务方法中被称为:代码侵入

增强代码侵入业务代码所产生的问题:

     1)业务方法的核心功能不突出;

     2)增强代码与业务代码耦合在一起,不利于日后的维护

如何改进呢:

使用代理模式将增强代码与业务代码分离。

静态代理传送:

 设计模式(十八)——代理模式

动态代理

首先看看静态代理的不足:

静态代理类的每个代理方法中,含有相同的增强代码,比如含有时间点记录的代码

如果目标对象含有很多的业务方法,比如几十个业务方法,会造成代理方法中含有大量的相同代码,产生代码冗余

 动态代理用到InvocationHandler接口

InvocationHandler接口中只有一个invoke方法,即

  Object invoke(Object proxy, Method method, Object[] args)

invoke方法的作用,以反射的方式将代理方法的调用解析为统一的形式:

   invoke(proxy,method, null);

在代理方法中,以反射的方式,通过调用InvocationHanler对象的invoke方法,实现代理方法的调用委派。

如何让JVM动态创建代理对象呢?

需要使用JavaSE JDK中的Proxy类。

Proxy类位于java.lang.reflect包下,是JVM所创建的动态代理类的父类。

Proxy类提供了如下的静态方法,用于通知JVM执行时,动态生成代理类(Proxy的子类),并创建代理对象;

     static Object newProxyInstance

              (ClassLoader  loader,

Class<?>[ ]    interfaces,

                                          InvocationHandler      h)

Proxy类的封装

采用工厂模式封装动态代理对象的创建过程:

   (1)定义一个获得动态代理对象的静态方法

       geDynamicProxy(IStringProcessing target)

       其中参数类型是业务接口

   (2)根据传递进来的目标对象,首先创建

        InvocationHandler对象并设置它和目标对象

        的依赖关系,然后再调用Proxy类的静态方法

        newProxyInstanc(),生成动态代理对象;

Demo:

已经实现一个接口中两个方法,现在想需要统计两个方法执行的时间。要求不能代码侵入,代理执行不能代码冗余

 

  1 /*
  2  * 接口
  3  */
  4 public interface IString {
  5     public void addString();//拼接字符串
  6     public void buildString();//缓存字符串
  7 }
  8 
  9 
 10 public class StringPro implements IString {
 11     private final int AMOUNT=30000;
 12     @Override
 13     public void addString() {
 14         //核心业务代码
 15         System.out.println("adding string ...");
 16         String s="";
 17         for(int i=0;i<AMOUNT;i++){
 18             s+="A";
 19         }
 20     }
 21     
 22     @Override
 23     public void buildString() {
 24         //核心业务代码
 25         System.out.println("building string ...");
 26         StringBuilder builder=new StringBuilder();
 27         for(int i=0;i<AMOUNT;i++){
 28             builder.append("A");
 29         }
 30     }
 31 
 32 }
 33 
 34 
 35 import java.lang.reflect.InvocationHandler;
 36 import java.lang.reflect.Method;
 37 import java.util.Date;
 38 
 39 /*
 40  * 添加增强代码,并通过InvocationHandler减少冗余代码
 41  */
 42 public class LoginHandler implements InvocationHandler {
 43     private Object target;
 44     
 45     public Object getTraget() {
 46         return target;
 47     }
 48 
 49     public void setTraget(Object target) {
 50         this.target = target;
 51     }
 52     
 53     public LoginHandler(){}
 54     @Override
 55     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 56         long start = System.currentTimeMillis();
 57         System.out.println(new Date(start) + "开始:");
 58 
 59         // 核心业务代码
 60         
 61         /*
 62          * 重点在这里:调用关联的target对象,而不是invoke方法传入的proxy对象,
 63          * 通过这种替换可以实现调用对目标代码的增强,而不是代理对象。
 64          */
 65         Object result = method.invoke(target, args);
 66         // 增强代码
 67         long end = System.currentTimeMillis();
 68         System.out.println(new Date(end) + "结束,耗时:" + (end - start));
 69         return result;
 70     }
 71 
 72 }
 73 
 74 
 75 
 76 import java.lang.reflect.Proxy;
 77 
 78 public class ProxyFactory {
 79     public static Object getDynamicProxy(IString target){
 80         LoginHandler l = new LoginHandler();
 81         l.setTraget(target);
 82         //通过Proxy对象的静态方法创建代理对象
 83         Object proxyObject = Proxy.newProxyInstance(
 84                 target.getClass().getClassLoader(),
 85                 target.getClass().getInterfaces(), l);
 86         return proxyObject;
 87     }
 88 }
 89 
 90 
 91 
 92 
 93 import proxy.IString;
 94 import proxy.ProxyFactory;
 95 import proxy.StringPro;
 96 
 97 
 98 public class TestIoc {
 99     private static final String LOCATION = "applicationContext.xml";
100     public static void main(String[] args) {
101         IString is = new StringPro();
102         IString dproxy =  (IString) ProxyFactory.getDynamicProxy(is);
103         System.out.println(dproxy.getClass().getName());
104         dproxy.addString();
105         System.out.println();
106         dproxy.buildString();
107     }
108 }

 

 

转载于:https://www.cnblogs.com/cxy2016/p/8506161.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值