zoukankan      html  css  js  c++  java
  • Spring AOP动态代理原理与实现方式

    AOP:面向切面、面向方面、面向接口是一种横切技术
    横切技术运用:
    1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物   
    2.日志处理:
    3.安全验证: Spring AOP---OOP升级  
      

    静态代理原理:目标对象:调用业务逻辑    代理对象:日志管理
    表示层调用--->代理对象(日志管理)-->调用目标对象

    动态代理原理:spring AOP采用动态代理来实现
    (1)实现InvocationHandler接口

    (2)创建代理类(通过java API)

    Proxy.newProxyInstance(动态加载代理类,代理类实现接口,使用handler);

    (3)调用invoke方法(虚拟机自动调用方法)

    日志处理
     //调用目标对象
     method.invoke("目标对象","参数");
     日志处理

    通过代理对象--(请求信息)-->目标对象---(返回信息)----> 代理对象

    Spring 动态代理中的基本概念

    1、关注点(concern)
       一个关注点可以是一个特定的问题,概念、或者应用程序的兴趣点。总而言之,应用程序必须达到一个目标
       安全验证、日志记录、事务管理都是一个关注点
       在oo应用程序中,关注点可能已经被代码模块化了还可能散落在整个对象模型中
    2、横切关注点(crosscutting concern)
       如何一个关注点的实现代码散落在多个类中或方法中
    3、方面(aspect)
       一个方面是对一个横切关注点模块化,它将那些原本散落在各处的,
       用于实现这个关注点的代码规整在一处
    4、建议(advice)通知
       advice是point cut执行代码,是方面执行的具体实现
    5、切入点(pointcut)
       用于指定某个建议用到何处
    6、织入(weaving)
       将aspect(方面)运用到目标对象的过程
    7、连接点(join point)
      程序执行过程中的一个点 

    通知类型:
      try{
        //前置通知
             //环绕通知
                //调用目标对象方法
             //环绕通知
        //后置通知
      }catch(){
        //异常通知
      }finally{
        //终止通知
      }

    流程图

    一.静态代理原理实例:

    项目结构图:                                                                    

    IUserServ接口代码

    [java] view plain copy
     
    1. public interface IUserServ {  
    2.     List<User> findAllUser();  
    3.     int deleteUserById(User user);  
    4.     int saveUser(User user);  
    5. }  


    UserServImpl实现类代码

    [java] view plain copy
     
    1. public class UserServImpl implements IUserServ {  
    2.     public int deleteUserById(User user) {  
    3.         System.out.println("******执行删除方法******");  
    4.         return 0;  
    5.     }  
    6.     public List<User> findAllUser() {  
    7.         System.out.println("*******执行查询方法*******");  
    8.         return null;  
    9.     }  
    10.     public int saveUser(User user) {  
    11.         System.out.println("*******执行添加方法********");  
    12.         return 0;  
    13.     }  
    14. }  

    UserServProxyImpl实现类代码

    [java] view plain copy
     
    1. //代理类:完成日志输出  
    2. public class UserServProxyImpl implements IUserServ {  
    3.     // 访问目标对象(UserServImpl)  
    4.     // 代理对象(UserServProxyImpl)  
    5.     // 创建目标对象  
    6.     private IUserServ iuserServ ;//= new UserServImpl();  
    7.   
    8.     public UserServProxyImpl(IUserServ iuserServ){  
    9.         this.iuserServ = iuserServ;  
    10.     }  
    11.     public int deleteUserById(User user) {  
    12.         beforeLog();  
    13.         //调用目标对象里方法  
    14.         iuserServ.deleteUserById(user);  
    15.         afterLog();  
    16.         return 0;  
    17.     }  
    18.   
    19.     public List<User> findAllUser() {  
    20.         beforeLog();  
    21.         //调用目标对象里方法  
    22.         iuserServ.findAllUser();  
    23.         afterLog();  
    24.         return null;  
    25.     }  
    26.   
    27.     public int saveUser(User user) {  
    28.         beforeLog();  
    29.         //调用目标对象里方法  
    30.         iuserServ.saveUser(user);  
    31.         afterLog();  
    32.         return 0;  
    33.     }  
    34.   
    35.     private void beforeLog() {  
    36.         System.out.println("开始执行");  
    37.     }  
    38.       
    39.     private void afterLog() {  
    40.         System.out.println("执行完毕");  
    41.     }  
    42. }  

    ActionTest测试类代码

    [java] view plain copy
     
    1. public class ActionTest {  
    2.     public static void main(String[] args) {  
    3.         //用户访问代理对象---信息->目标对象  
    4.         IUserServ iuserServ = new UserServProxyImpl(new UserServImpl());  
    5.         iuserServ.findAllUser();  
    6.     }  
    7. }  

    运行结果:

    开始执行
    *******执行查询方法*******
    执行完毕
    二.动态代理实例

    项目结构图:

    IUserServ接口代码与UserServImpl实现类代码和上述代码相同

    LogHandler类代码

    [java] view plain copy
     
    1. public class LogHandler implements InvocationHandler {  
    2.     //目标对象  
    3.     private Object targetObject;  
    4.     /** 
    5.      * 创建动态代理类 
    6.      * @return object(代理类) 
    7.      */  
    8.     public Object createProxy(Object targetObject){  
    9.         this.targetObject = targetObject;  
    10.         return Proxy.newProxyInstance(  
    11.                 targetObject.getClass().getClassLoader(),   
    12.                     targetObject.getClass().getInterfaces(), this);  
    13.     }  
    14.     @Override  
    15.     public Object invoke(Object proxy, Method method, Object[] args)  
    16.             throws Throwable {  
    17.         Object obj = null;  
    18.         try {  
    19.             beforeLog();  
    20.             //obj: 目标对象--->代理对象的返回值--->返回给调用者的信息  
    21.             //this.invoke("目标对象","代理对象给目标对象传递参数");  
    22.             //调用目标对象中方法  
    23.             obj = method.invoke(targetObject, args);  
    24.             afterLog();  
    25.         } catch (Exception e) {  
    26.             e.printStackTrace();  
    27.         }  
    28.         return obj;  
    29.     }  
    30.       
    31.     //日志管理方法  
    32.     private void beforeLog(){  
    33.         System.out.println("开始执行");  
    34.     }  
    35.       
    36.     private void afterLog(){  
    37.         System.out.println("执行完毕");  
    38.     }  
    39.   
    40. }  

    ActionTest测试类代码:

    [java] view plain copy
     
    1. public class ActionTest {  
    2.     public static void main(String[] args) {  
    3.         //创建代理对象iuserServ  
    4.         LogHandler handler = new LogHandler();  
    5.         IUserServ iuserServ = (IUserServ)handler.createProxy(new UserServImpl());  
    6.         iuserServ.deleteUserById(new User());  
    7.     }  
    8. }  

    运行结果:
    开始执行
    ******执行删除方法******
    执行完毕
    三.Spring AOP使用(2.x版本之前)

    项目结构图:



    IUserServ接口代码与UserServImpl实现类代码和上述代码相同

    配置步骤:

    1、配置目标对象(applicationContext.xml)

    [html] view plain copy
     
    1. <bean id="userServTarget" class="com.tarena.biz.impl.UserServImpl"/>   

     2、配置通知
    (a)前置通知(BeforeLogAdvice)

    [java] view plain copy
     
    1. public class BeforeLogAdvice implements MethodBeforeAdvice {  
    2.      /** 
    3.         * Method method:调用目标对象的方法 
    4.         * Object[] args:发送给目标对象的参数列表 
    5.         * Object target:目标对象 
    6.         */  
    7.     public void before(Method method, Object[] args, Object target)  
    8.             throws Throwable {  
    9.         beforeLog();  
    10.     }  
    11.     private void beforeLog(){  
    12.         System.out.println("开始执行");  
    13.     }  
    14. }  


    (b)后置通知(AfterLogAdvice)

    [java] view plain copy
     
    1. public class AfterLogAdvice implements AfterReturningAdvice {  
    2.       /** 
    3.         * Object returnValue:目标对象返回值 
    4.         *  Method method:目标对象方法名 
    5.         *  Object[] args:目标对象参数列表 
    6.         *  Object target:目标对象 
    7.         */  
    8.     public void afterReturning(Object returnValue, Method method,  
    9.             Object[] args, Object target) throws Throwable {  
    10.         afterLog();  
    11.     }  
    12.     private void afterLog(){  
    13.         System.out.println("执行完毕");  
    14.     }  
    15. }  

           

    (c)在spring容器中,让容器管理通知(applicationContext.xml)

    [html] view plain copy
     
    1. <!-- 定义通知 -->  
    2.         <!-- 前置通知 -->  
    3.         <bean id="beforeLogAdvice" class="com.tarena.advice.BeforeLogAdvice"/>  
    4.         <!-- 后置通知 -->  
    5.         <bean id="afterLogAdvice" class="com.tarena.advice.AfterLogAdvice"/>  


    3、配置代理对象(applicationContext.xml)  

    [html] view plain copy
     
    1. <!-- 代理类作用: 生成代理类,织入通知 -->    
    2.   <bean id="userServProxy"   
    3.    class="org.springframework.aop.framework.ProxyFactoryBean">  
    4.    <property name="interfaces">  
    5.    <!-- 可以添加多个接口 -->  
    6.     <list>  
    7.      <value>com.tarena.biz.IUserServ</value>  
    8.     </list>  
    9.    </property>  
    10.    <!-- 引入通知 -->  
    11.    <property name="interceptorNames">  
    12.     <list>  
    13.      <value>beforeLogAdvice</value>  
    14.      <value>afterLogAdvice</value>  
    15.     </list>  
    16.    </property>  
    17.    <!-- 目标对象 -->  
    18.    <property name="target" ref="userServTarget"/>  
    19.   </bean>  


     4.访问()
    Spring容器:通过代理对象调用-->织入通知--->目标对象
    程序员:访问代理对象   

    测试类(ActionTest):

    [java] view plain copy
     
    1. public class ActionTest {  
    2.     public static void main(String[] args) {  
    3.         ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");  
    4.         IUserServ iuserServ = (IUserServ)ac.getBean("userServProxy");  
    5.         iuserServ.deleteUserById(new User());  
    6.         iuserServ.findAllUser();  
    7.     }  
    8. }  

    运行结果:

    开始执行
    ******执行删除方法******
    执行完毕
    开始执行
    *******执行查询方法*******
    执行完毕
    四.Spring AOP使用(2.x版本之后)这种方式需要额外添加两个jar包,

    存放位置在spring-framework-2.5.6.SEC01libaspectj文件夹下。

    项目结构图


    IUserServ接口代码与UserServImpl实现类代码和上述代码相同

    LogAdvice中

    [java] view plain copy
     
    1. public class LogAdvice {  
    2.     public void beforeLog(){  
    3.         System.out.println("开始执行");  
    4.     }  
    5.     public void afterLog(){  
    6.         System.out.println("执行完毕");  
    7.     }  
    8. }  

    applicationContext.xml中

    [html] view plain copy
     
    1. <!-- spring2.x后 -->  
    2.     <!-- 目标对象 -->  
    3.     <bean id="userServImpl" class="com.tarena.biz.impl.UserServImpl"/>  
    4.     <!-- 通知 -->  
    5.     <bean id="logAdvice" class="com.tarena.advice.LogAdvice"/>  
    6.       
    7.     <aop:config>  
    8.         <aop:aspect id="logAspect" ref="logAdvice">  
    9.             <!-- 切入点 -->  
    10.             <aop:pointcut id="beforePointCut"   
    11.         expression="execution(* saveUser*(..))"/>  
    12.         <aop:pointcut id="afterPointCut"   
    13.         expression="execution(* saveUser*(..))"/>  
    14.               
    15.             <!-- 织入(通知作用于切入点) -->  
    16.             <aop:before method="beforeLog" pointcut-ref="beforePointCut"/>  
    17.             <aop:after method="afterLog" pointcut-ref="afterPointCut"/>  
    18.         </aop:aspect>  
    19.     </aop:config>  

    测试类:

    [java] view plain copy
     
    1. public class ActionTest {  
    2.     public static void main(String[] args) {  
    3.         ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");  
    4.         IUserServ iuserServ = (IUserServ)ac.getBean("userServImpl");  
    5.         iuserServ.deleteUserById(new User());  
    6.         iuserServ.findAllUser();  
    7.         iuserServ.saveUser(new User());  
    8.     }  
    9. }  

    运行结果
    ******执行删除方法******
    *******执行查询方法*******
    开始执行
    *******执行添加方法********
    执行完毕

    注:如果要在业务层所有的方法前后添加日志文件,则需要更改为以下配置

    [html] view plain copy
     
    1. <aop:pointcut id="beforePointCut"   
    2.         expression="execution(* com.tarena.biz.*.*(..))"/>  
    3.         <aop:pointcut id="afterPointCut"   
    4.         expression="execution(* com.tarena.biz.*.*(..))"/>  


    运行结果:

    开始执行
    ******执行删除方法******
    执行完毕
    开始执行
    *******执行查询方法*******
    执行完毕
    开始执行
    *******执行添加方法********
    执行完毕

  • 相关阅读:
    4.2网络层提供的两种服务
    4.1网络层概述
    MATLAB曲面插值及交叉验证
    python爬虫成长之路(二):抓取代理IP并多线程验证
    KNN识别图像上的数字及python实现
    python爬虫成长之路(一):抓取证券之星的股票数据
    YARN环境搭建 之 一:CentOS7.0系统配置
    高效学习方法总结
    《立委随笔:机器学习和自然语言处理》
    XenServer安装虚拟机先扩容存放ISO镜像文件
  • 原文地址:https://www.cnblogs.com/zedosu/p/6709913.html
Copyright © 2011-2022 走看看