zoukankan      html  css  js  c++  java
  • 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 }

  • 相关阅读:
    Win10 JDK 配置
    Java Selenium
    Java Selenium
    Eclipse配置Github -分享你的代码
    TestNG-详解preserve-order的作用与测试case的执行顺序
    Java
    VirtualBox 在Win10上的蓝屏问题
    SQL _ Create Procedure
    LINQ 学习路程 -- 查询语法 LINQ Query Syntax
    LINQ 学习路程 -- 开篇
  • 原文地址:https://www.cnblogs.com/cxy2016/p/8506161.html
Copyright © 2011-2022 走看看