daodan

导航

 

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. }  
posted on 2016-11-30 16:31  daodan  阅读(314)  评论(0编辑  收藏  举报