zoukankan      html  css  js  c++  java
  • AOP (Aspect-OrientedProgramming)面向切面编程

    AOP

     OOP 面向对象编程 适合自上向下,却不适合自左向右

    AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。

    横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。

    Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

    正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。

    一般应用:日志记录、事物控制、权限控制

     一、基础定义

    • 切面(Aspect): 就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。宏观上要关注的编程方面,比如安全管理方面,日志记录方面,而这些都只是宏观上的,没有任何代码实现,就好像这样说:我这个系统要一个安全管理系统等等,就是大至上需要这个切面功能。
    • 通知(Advice):是切面的具体实现。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。
    • 连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持方法级的连接点。
    • 切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。
    • 目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。这些对象中已经只剩下干干净净的核心业务逻辑代码了,所有的共有功能代码等待AOP容器的切入。
    • 代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。
    • 织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期,当然不同的发生点有着不同的前提条件。譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态实现。

    动态代理:

    IUserServ接口代码

    1. public interface IUserServ {  
    2.     List<User> findAllUser();  
    3.     int deleteUserById(User user);  
    4.     int saveUser(User user);  
    5. }

    UserServImpl实现类代码

    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;  

                       }  

    1.     public int saveUser(User user) {  
    2.        System.out.println("*******执行添加方法********");  
    3.          return 0;  
    4.      }  
    5. }

    LogHandler类代码

    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.        

      //日志管理方法   

    1.      private void beforeLog(){  
    2.          System.out.println("开始执行");  
    3.      }  

           

    1.      private void afterLog(){  
    2.          System.out.println("执行完毕");  
    3.      }  
    4.    

     }  

    ActionTest测试类代码:

    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. }  

    动态代理类:

    (1)实现InvocationHandler接口

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

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

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

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

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

    Spring AOP使用(2.x版本之后)

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

    LogAdvice中                                             

    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中

     

     

    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>  

    测试类:

      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. }  
  • 相关阅读:
    数据结构基础(二)排序算法
    数据结构基础(一) 时间空间复杂度分析
    347. Top K Frequent Elements, O(N) solution
    409. Longest Palindrome
    556. Next Greater Element III
    CH0103 最短Hamilton路径(状压DP)
    牛客OI周赛13-提高组A-0还是1(简单DP)
    Codeforces Round #678 (Div. 2) C. Binary Search(二分查找/思维/排列组合)
    Codeforces Round #677 (Div. 3) A-E
    函数实现复合命题的计算及判断两个命题是否等值——中缀表达式转后缀表达式
  • 原文地址:https://www.cnblogs.com/daodan/p/4000323.html
Copyright © 2011-2022 走看看