• Spring4笔记6--Spring与AOP


    Spring与AOP:

      AOP的引入:

        主业务经常需要调用系统级业务(交叉业务),如果在主业务代码中大量的调用系统级业务代码,会使系统级业务与主业务深度耦合在一起,大大影响了主业务逻辑的可读性,降低了代码的可维护性,同时也增加了开发难度。

        所以,可以采用动态代理方式。动态代理是 OCP 开发原则的一个重要体现:在不修改主业务逻辑的前提下,扩展和增强其功能。

     1 package com.tongji.test;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 
     7 import org.junit.Test;
     8 
     9 import com.tongji.service.ISomeService;
    10 import com.tongji.service.SomeServiceImpl;
    11 import com.tongji.utils.SomeUtils;
    12 
    13 public class MyTest {
    14     @Test
    15     public void test01() {
    16         final ISomeService target = new SomeServiceImpl();
    17         ISomeService proxy = (ISomeService) Proxy.newProxyInstance(
    18                         target.getClass().getClassLoader(), 
    19                         target.getClass().getInterfaces(), 
    20                         new InvocationHandler() {
    21                             
    22                             //织入:交叉业务逻辑切入到主业务中,就在这里完成的
    23                             @Override
    24                             public Object invoke(Object proxy, Method method, Object[] args)
    25                                     throws Throwable {
    26                                 SomeUtils.doTransaction();
    27                                 Object result = method.invoke(target, args);
    28                                 SomeUtils.doLog();
    29                                 return result;
    30                             }
    31                         });
    32         proxy.doSome();
    33         proxy.doSecond();
    34     }
    35 }

      

      AOP简介:

        AOP(Aspect Orient Programming),面向切面编程,是面向对象编程 OOP 的一种补充。

        面向对象编程是从静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序运行过程AOP 底层,就是采用动态代理模式(代理模式见此链接)实现的。采用了两种代理:JDK 的动态代理,与 CGLIB的动态代理。
        面向切面编程,就是将交叉业务逻辑封装成切面,利用 AOP 容器的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志等。
        若不使用 AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清。
         例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但,它们的代码量所占比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,
    还大大干扰了主业务逻辑---转账。

        AOP编程术语:

          (1)切面(Aspect)
            切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面有通知与顾问。实际就是对主业务逻辑的一种增强。
          (2)织入(Weaving)
            织入是指将切面代码插入到目标对象的过程。上例中 invoke()方法完成的工作,就可以称为织入。
          (3)切入点(Pointcut)
            切入点指切面具体织入的位置。在 StudentServiceImpl 类中,若 doSome()将被增强,而doOther()不被增强,则 doSome()为切入点,而 doOther()仅为连接点被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修的,不能被增强的。

          (4)目标对象(Target)
            目标对象指将要被增强的对象。即包含主业务逻辑的类的对象。上例中的StudentServiceImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,不被增强,也就无所谓目标不目标了。
          (5)通知(Advice)
            通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。切入点定义切入的位置,通知定义切入的时间。  
          (6)顾问(Advisor)
            顾问是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器

      通知(Advice):

        通知(Advice),切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。常用通知有:前置通知、后置通知、环绕通知、异常处理通知
        通知的用法步骤:

          (1)定义目标类
              定义目标类,就是定义之前的普通 Bean 类,也就是即将被增强的 Bean 类。
          (2)定义通知类
              通知类是指,实现了相应通知类型接口的类。当前,实现了这些接口,就要实现这些接口中的方法,而这些方法的执行,则是根据不同类型的通知,其执行时机不同。
              前置通知:在目标方法执行之前执行
              后置通知:在目标方法执行之后执行
              环绕通知:在目标方法执行之前与之后均执行
              异常处理通知:在目标方法执行过程中,若发生指定异常,则执行通知中的方法
          (3)注册目标类
              即在 Spring 配置文件中注册目标对象 Bean。

          (4)注册通知切面
              即在 Spring 配置文件中注册定义的通知对象 Bean。

          (5)注册代理工厂 Bean 类对象 ProxyFactoryBean

          (6)客户端访问动态代理对象
              客户端访问的是动态代理对象,而非原目标对象。因为代理对象可以将交叉业务逻辑按照通知类型,动态的织入到目标对象的执行中。

        通知详解:

          下面详解的共同代码:

          主业务接口(底层使用JDK的动态代理时使用,使用CGLIB动态代理时不用):

    1 package com.tongji.aop05;
    2 
    3 //主业务接口
    4 public interface ISomeService {
    5     public void doSome();
    6     public String doSecond();
    7     public void doThird();
    8 }

          目标类:

     1 package com.tongji.aop05;
     2 
     3 //目标类
     4 public class SomeServiceImpl implements ISomeService {
     5 
     6     @Override
     7     public void doSome() {
     8         System.out.println("执行doSome()方法");
     9     }
    10 
    11     @Override
    12     public String doSecond() {
    13         System.out.println("执行doSecond()方法");
    14         return "China";
    15     }
    16 
    17     @Override
    18     public void doThird() {
    19         System.out.println("执行doThird()方法");
    20     }
    21 
    22 }

         测试类:

     1 package com.tongji.aop06;
     2 
     3 import org.junit.Test;
     4 import org.springframework.context.ApplicationContext;
     5 import org.springframework.context.support.ClassPathXmlApplicationContext;
     6 
     7 public class MyTest {
     8     
     9     @Test
    10     public void test01() {
    11         String resource = "com/tongji/aop06/applicationContext.xml";
    12         @SuppressWarnings("resource")
    13         ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
    14         ISomeService service = (ISomeService) ac.getBean("serviceProxy");
    15         service.doSome();
    16         System.out.println("-------------------");
    17         String second = service.doSecond();
    18         System.out.println(second);
    19         System.out.println("-------------------");
    20         service.doThird();
    21     }
    22     
    23 }

         (1) 前置通知 MethodBeforeAdvice
            定义前置通知,需要实现 MethodBeforeAdvice 接口。该接口中有一个方法 before(),会在目标方法执行之前执行。

            通知类:

     1 package com.tongji.aop01;
     2 
     3 import java.lang.reflect.Method;
     4 
     5 import org.springframework.aop.MethodBeforeAdvice;
     6 
     7 //前置通知
     8 public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
     9     
    10     //该方法在目标方法执行之前执行
    11     //method:目标方法
    12     //args:目标方法的参数列表
    13     //target:目标对象
    14     @Override
    15     public void before(Method method, Object[] args, Object target)
    16             throws Throwable {
    17         System.out.println("目标方法执行之前:对目标对象的增强代码就是写在这里的");
    18         
    19     }
    20 
    21 }

            Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop01.SomeServiceImpl"/>
    10     <!-- 切面:前置通知 -->    
    11     <bean id="beforeAdvice" class="com.tongji.aop01.MyMethodBeforeAdvice"/>
    12     
    13     <!-- 代理对象的生成:注意这里的ProxyFactoryBefan不是代理类,而是代理工厂 -->
    14     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    15         <property name="target" ref="someService"/>
    16         <!--  <property name="targetName" value="someService"/>  -->
    17         <!-- 可以不写接口,因为默认会自动检测到目标类所实现的所有接口 -->
    18         <!--  <property name="interfaces" value="com.tongji.aop01.ISomeService"/>  -->
    19         <property name="interceptorNames" value="beforeAdvice"/>
    20     </bean>
    21 </beans>

          (2) 后置通知 AfterRunningAdvice:

            定义后置通知,需要实现接口 AfterReturningAdvice。该接口中有一个方法 afterReturning ()。

            通知类:

     1 package com.tongji.aop02;
     2 
     3 import java.lang.reflect.Method;
     4 
     5 import org.springframework.aop.AfterReturningAdvice;
     6 
     7 //后置通知
     8 public class MyAfterReturningAdvice implements AfterReturningAdvice {
     9 
    10     //returnValue:目标方法返回值,后置通知只能获取返回值不能修改返回值
    11     @Override
    12     public void afterReturning(Object returnValue, Method method,
    13             Object[] args, Object target) throws Throwable {
    14         System.out.println("目标方法执行之后,目标方法返回值为" + returnValue);
    15         
    16     }
    17 
    18 }

            Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop02.SomeServiceImpl"/>
    10     <!-- 切面:后置通知 -->    
    11     <bean id="afterAdvice" class="com.tongji.aop02.MyAfterReturningAdvice"/>
    12     
    13     <!-- 代理对象的生成 -->
    14     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    15         <property name="target" ref="someService"/>
    16         <property name="interceptorNames" value="afterAdvice"/>
    17     </bean>
    18 </beans>

          (3) 环绕通知 MethodInterceptor:

            定义环绕通知,需要实现 MethodInterceptor 接口。环绕通知,也叫方法拦截器,可以在目标方法调用之前及之后做处理,可以改变目标方法的返回值,也可以改变程序执行流程。

            通知类:

     1 package com.tongji.aop03;
     2 
     3 import org.aopalliance.intercept.MethodInterceptor;
     4 import org.aopalliance.intercept.MethodInvocation;
     5 
     6 public class MyMethodInterceptor implements MethodInterceptor {
     7 
     8     @Override
     9     public Object invoke(MethodInvocation invocation) throws Throwable {
    10         System.out.println("目标方法执行之前");
    11         //调用目标方法
    12         Object result = invocation.proceed();
    13         System.out.println("目标方法执行之后");
    14         if (result != null) {
    15             result = ((String)result).toUpperCase();
    16         }
    17         return result;
    18     }
    19 
    20 }

            Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop03.SomeServiceImpl"/>
    10     <!-- 切面:环绕通知 -->    
    11     <bean id="aroundAdvice" class="com.tongji.aop03.MyMethodInterceptor"/>
    12     
    13     <!-- 代理对象的生成 -->
    14     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    15         <property name="target" ref="someService"/>
    16         <property name="interceptorNames" value="aroundAdvice"/>
    17     </bean>
    18 </beans>

          (4) 异常通知 ThrowsAdvice:

            定义异常通知,需要实现 ThrowsAdvice 接口。该接口的主要作用是,在目标方法抛出异常后,根据异常的不同做出相应的处理。当该接口处理完异常后,会简单地将异常再次抛出给目标方法。
            不过,这个接口较为特殊,从形式上看,该接口中没有必须要实现的方法但,这个接口却确实有必须要实现的方法 afterThrowing()。这个方法重载了四种形式。由于使用时,一般只使用其中一种,若要都定义到接口中,则势必要使程序员在使用时必须要实现这四个方法。这是很麻烦的。所以就将该接口定义为了标识接口(没有方法的接口)。使用方法时要参考接口源代码中的提示。

            自定义异常类(略)

            主业务接口:

    1 package com.tongji.aop04;
    2 
    3 //主业务接口
    4 public interface ISomeService {
    5     boolean check(String username, String password) throws UserException;
    6 }

            目标类:

     1 package com.tongji.aop04;
     2 
     3 //目标类
     4 public class SomeServiceImpl implements ISomeService {
     5 
     6     //目标方法
     7     @Override
     8     public boolean check(String username, String password) throws UserException {
     9         if (!"qjj".equals(username)) {
    10             throw new UsernameException("用户名不正确");
    11         }
    12         
    13         if (!"248xiaohai".equals(password)) {
    14             throw new PasswordException("密码不正确");
    15         }
    16         
    17         return true;
    18     }
    19     
    20 }

            通知类:

     1 package com.tongji.aop04;
     2 
     3 import org.springframework.aop.ThrowsAdvice;
     4 
     5 //异常处理通知
     6 public class MyThrowsAdvice implements ThrowsAdvice {
     7     
     8     //若发生UsernameException异常,则该方法会自动被调用执行
     9     public void afterThrowing(UsernameException ex) {
    10         System.out.println("发生用户名异常,ex=" + ex);
    11     }
    12     
    13     //若发生PasswordException异常,则该方法会自动被调用执行
    14     public void afterThrowing(PasswordException ex) {
    15         System.out.println("发生密码异常,ex=" + ex);
    16     }
    17 }

           这里的参数 ex 为,与具体业务相关的用户自定义的异常类对象。容器会根据异常类型的不同,自动选择不同的该方法执行。这些方法的执行是在目标方法执行结束后执行的。

           测试类:

     1 package com.tongji.aop04;
     2 
     3 import org.junit.Test;
     4 import org.springframework.context.ApplicationContext;
     5 import org.springframework.context.support.ClassPathXmlApplicationContext;
     6 
     7 public class MyTest {
     8     
     9     @Test
    10     public void test01() {
    11         String resource = "com/tongji/aop04/applicationContext.xml";
    12         @SuppressWarnings("resource")
    13         ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
    14         ISomeService service = (ISomeService) ac.getBean("serviceProxy");
    15         try {
    16             service.check("qjj1", "248");
    17         } catch (UserException e) {
    18             e.printStackTrace();
    19         }
    20     }
    21     
    22 }

          (5) 给目标方法织入多个切面:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop11.SomeServiceImpl"/>
    10     <!-- 切面:通知 -->    
    11     <bean id="afterAdvice" class="com.tongji.aop11.MyAfterReturningAdvice"/>
    12     <bean id="beforeAdvice" class="com.tongji.aop11.MyMethodBeforeAdvice"/>
    13     
    14     <!-- 代理对象的生成 -->
    15     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    16         <property name="target" ref="someService"/>
    17         <property name="interceptorNames" value="afterAdvice,beforeAdvice"/>
    18     </bean>
    19 </beans>

          (6) 无主业务接口时,AOP底层使用CGLIB动态代理:

            目标类(无接口),其他代码均相同:

     1 package com.tongji.aop09;
     2 
     3 //目标类
     4 public class SomeService {
     5 
     6     public void doSome() {
     7         System.out.println("执行doSome()方法");
     8     }
     9 
    10     public String doSecond() {
    11         System.out.println("执行doSecond()方法");
    12         return "China";
    13     }
    14 
    15 }

         (7) 有主业务接口时,迫使AOP底层使用CGLIB动态代理:

            Spring配置文件,其他代码都不需要改变:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop10.SomeServiceImpl"/>
    10     <!-- 切面:后置通知 -->    
    11     <bean id="afterAdvice" class="com.tongji.aop10.MyAfterReturningAdvice"/>
    12     
    13     <!-- 代理对象的生成 -->
    14     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    15         <property name="target" ref="someService"/>
    16         <property name="interceptorNames" value="afterAdvice"/>
    17         <!-- <property name="proxyTargetClass" value="true"/> -->
    18         <property name="optimize" value="true"/>
    19     </bean>
    20 </beans>

        顾问(Advisor):

          通知(Advice)是 Spring 提供的一种切面(Aspect)织入方法。但其功能过于简单:只能将切面织入到目标类的所有目标方法中,无法完成将切面织入到指定目标方法中
            顾问(Advisor)是 Spring 提供的另一种切面织入方法。其可以完成更为复杂的切面织入功能。PointcutAdvisor 是顾问的一种,可以指定具体的切入点顾问将通知进行了包装,会根据不同的通知类型,在不同的时间点,将切面织入到不同的切入点。

          PointcutAdvisor 接口有两个较为常用的实现类:
            NameMatchMethodPointcutAdvisor 名称匹配方法切入点顾问
            RegexpMethodPointcutAdvisor 正则表达式匹配方法切入点顾问
          1. 名称匹配方法切入点顾问
            NameMatchMethodPointcutAdvisor,即名称匹配方法切入点顾问。容器可根据配置文件中指定的方法名来设置切入点。

            Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop05.SomeServiceImpl"/>
    10     <!-- 切面:后置通知 -->    
    11     <bean id="afterAdvice" class="com.tongji.aop05.MyAfterReturningAdvice"/>
    12     <!-- 切面:名称匹配方法切入点顾问 -->    
    13     <bean id="afterAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    14         <property name="advice" ref="afterAdvice"/>
    15         <!--  <property name="mappedNames" value="do*"/>  -->
    16         <property name="mappedNames" value="doSome,doThird"/>
    17         <!--  <property name="mappedNames">
    18             <array>
    19                 <value>doSome</value>
    20                 <value>doThird</value>
    21             </array>
    22         </property>  
    23         -->
    24     </bean>
    25     
    26     <!-- 代理对象的生成 -->
    27     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    28         <property name="target" ref="someService"/>
    29         <property name="interceptorNames" value="afterAdvisor"/>
    30     </bean>
    31 </beans>

          2. 正则表达式方法切入点顾问
            RegexpMethodPointcutAdvisor,即正则表达式方法顾问。容器可根据正则表达式来设置切入点。注意,与正则表达式进行匹配的对象是接口中的方法名,而非目标类(接口的实现类)的方法名。

            Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService" class="com.tongji.aop06.SomeServiceImpl"/>
    10     <!-- 切面:后置通知 -->    
    11     <bean id="afterAdvice" class="com.tongji.aop06.MyAfterReturningAdvice"/>
    12     <!-- 切面:正则表达式方法切入点顾问 -->    
    13     <bean id="afterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    14         <property name="advice" ref="afterAdvice"/>
    15         <!-- 正则表达式匹配的对象为:全限定性方法名,而不是简单方法名 -->
    16         <!-- <property name="pattern" value=".*T.*"/> -->
    17         <!-- <property name="patterns" value=".*T.*,.*Sec.*"/> -->
    18         <property name="pattern" value=".*T.*|.*Sec.*"/>
    19     </bean>
    20     
    21     <!-- 代理对象的生成 -->
    22     <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    23         <property name="target" ref="someService"/>
    24         <property name="interceptorNames" value="afterAdvisor"/>
    25     </bean>
    26 </beans>

        自动代理生成器:

          前面代码中所使用的代理对象,均是由 ProxyFactoryBean 代理工具类生成的。而该代理工具类存在着如下缺点:
            (1)一个代理对象只能代理一个 Bean,即如果有两个 Bean 同时都要织入同一个切面,这时,不仅要配置这两个 Bean,即两个目标对象,同时还要配置两个代理对象。
            (2)在客户类中获取 Bean 时,使用的是代理类的 id,而非我们定义的目标对象 Bean 的 id。我们真正想要执行的应该是目标对象。从形式上看,不符合正常的逻辑。
          Spring 提供了自动代理生成器,用于解决 ProxyFactoryBean 的问题。常用的自动代理生成器有两个:  
            默认 advisor 自动代理生成器
            Bean 名称自动代理生成器
          需要注意的是,自动代理生成器均继承自 Bean 后处理器 BeanPostProcessor。容器中所有 Bean 在初始化时均会自动执行 Bean 后处理器中的方法,故其无需 id 属性。所以自动代理生成器的 Bean 也没有 id 属性,客户类直接使用目标对象 bean 的 id。

         1. 默认 advisor 自动代理生成器
           DefaultAdvisorAutoProxyCreator 代理的生成方式是,将所有的目标对象与 Advisor 自动结合,生成代理对象。无需给生成器做任何的注入配置。注意,只能与 Advisor 配合使用
           Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService1" class="com.tongji.aop07.SomeServiceImpl"/>
    10     <bean id="someService2" class="com.tongji.aop07.SomeServiceImpl"/>
    11     <!-- 切面:通知 -->    
    12     <bean id="afterAdvice" class="com.tongji.aop07.MyAfterReturningAdvice"/>
    13     <bean id="beforeAdvice" class="com.tongji.aop07.MyMethodBeforeAdvice"/>
    14     <!-- 切面:名称匹配方法切入点顾问 -->    
    15     <bean id="afterAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    16         <property name="advice" ref="afterAdvice"/>
    17         <property name="mappedName" value="doSome"/>
    18     </bean>
    19     <bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    20         <property name="advice" ref="beforeAdvice"/>
    21         <property name="mappedName" value="doSecond"/>
    22     </bean>
    23     
    24     <!-- 自动代理生成器 -->
    25     <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
    26 </beans>

           测试类:

     1 package com.tongji.aop07;
     2 
     3 import org.junit.Test;
     4 import org.springframework.context.ApplicationContext;
     5 import org.springframework.context.support.ClassPathXmlApplicationContext;
     6 
     7 public class MyTest {
     8     
     9     @Test
    10     public void test01() {
    11         String resource = "com/tongji/aop07/applicationContext.xml";
    12         @SuppressWarnings("resource")
    13         ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
    14         ISomeService service1 = (ISomeService) ac.getBean("someService1");
    15         service1.doSome();
    16         service1.doSecond();
    17         service1.doThird();
    18         System.out.println("-------------------");
    19         ISomeService service2 = (ISomeService) ac.getBean("someService2");
    20         service2.doSome();
    21         service2.doSecond();
    22         service2.doThird();
    23     }
    24     
    25 }

          2. Bean 名称自动代理生成器
            DefaultAdvisorAutoProxyCreator 会为每一个目标对象织入所有匹配的 Advisor,不具有选择性。而 BeanNameAutoProxyCreator 的代理生成方式是,根据 bean 的 id,来为符合相应名称的类生成相应代理对象

            Spring配置文件:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans  
     6         http://www.springframework.org/schema/beans/spring-beans.xsd">
     7 
     8     <!-- 目标对象 -->    
     9     <bean id="someService1" class="com.tongji.aop08.SomeServiceImpl"/>
    10     <bean id="someService2" class="com.tongji.aop08.SomeServiceImpl"/>
    11     <!-- 切面:通知 -->    
    12     <bean id="afterAdvice" class="com.tongji.aop08.MyAfterReturningAdvice"/>
    13     <bean id="beforeAdvice" class="com.tongji.aop08.MyMethodBeforeAdvice"/>
    14     <!-- 切面:名称匹配方法切入点顾问 -->    
    15     <bean id="afterAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    16         <property name="advice" ref="afterAdvice"/>
    17         <property name="mappedName" value="doSome"/>
    18     </bean>
    19     <bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    20         <property name="advice" ref="beforeAdvice"/>
    21         <property name="mappedName" value="doSecond"/>
    22     </bean>
    23     
    24     <!-- 该自动代理生成器,不仅可以指定目标对象,还可以指定切面,并且切面可以是通知或顾问 -->
    25     <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    26         <property name="beanNames" value="someService1"/>
    27         <property name="interceptorNames" value="beforeAdvice"/>
    28     </bean>
    29 </beans>
  • 相关阅读:
    【Hadoop】HDFS的运行原理
    ZOOKEEPER3.3.3源码分析(四)对LEADER选举过程分析的纠正
    zookeeper源码分析二FASTLEADER选举算法
    面试题9:用两个栈实现队列
    面试题7:重建二叉树
    C/C++实现链表的常用操作
    扩展卡尔曼滤波(EKF)实现三维位置估计
    毕业论文思路
    链表常用操作
    关于指针
  • 原文地址:https://www.cnblogs.com/qjjazry/p/6363300.html
Copyright © 2020-2023  润新知