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>

Spring4笔记6--Spring与AOP的更多相关文章

  1. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  2. Spring中AOP原理,源码学习笔记

    一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...

  3. Spring学习笔记(二)Spring基础AOP、IOC

    Spring AOP 1. 代理模式 1.1. 静态代理 程序中经常需要为某些动作或事件作下记录,以便在事后检测或作为排错的依据,先看一个简单的例子: import java.util.logging ...

  4. spring学习笔记二 注解及AOP

    本节需要导入spring-aop包 注解 使用注解的目的是为了代替配置,在使用注解时,省略键时,则是为value赋值. 扫描某个包下的所有类中的注解 <?xml version="1. ...

  5. Spring学习笔记5——注解方式AOP

    第一步:注解配置业务类 使用@Component("Pservice")注解ProductService 类 package com.spring.service; import ...

  6. 【学习笔记】Spring AOP注解使用总结

    Spring AOP基本概念 是一种动态编译期增强性AOP的实现 与IOC进行整合,不是全面的切面框架 与动态代理相辅相成 有两种实现:基于jdk动态代理.cglib Spring AOP与Aspec ...

  7. Spring4笔记7--AspectJ 对 AOP 的实现

    AspectJ 对 AOP 的实现: 对于 AOP 这种编程思想,很多框架都进行了实现.Spring 就是其中之一,可以完成面向切面编程.然而,AspectJ 也实现了 AOP 的功能,且其实现方式更 ...

  8. Spring学习笔记(12)——aop

    先了解AOP的相关术语:1.通知(Advice):通知定义了切面是什么以及何时使用.描述了切面要完成的工作和何时需要执行这个工作.2.连接点(Joinpoint):程序能够应用通知的一个"时 ...

  9. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring通知类型及使用ProxyFactoryBean创建AOP代理

    通知(Advice)其实就是对目标切入点进行增强的内容,Spring AOP 为通知(Advice)提供了 org.aopalliance.aop.Advice 接口. Spring 通知按照在目标类 ...

随机推荐

  1. GPU并行编程小结

    http://peghoty.blog.163.com/blog/static/493464092013016113254852/ http://blog.csdn.net/augusdi/artic ...

  2. 51nod 1376 最长上升子序列的数量 | DP | vector怒刷存在感!

    51nod 1376 最长上升子序列的数量 题解 我们设lis[i]为以位置i结尾的最长上升子序列长度,dp[i]为以位置i结尾的最长上升子序列数量. 显然,dp[i]要从前面的一些位置(设为位置j) ...

  3. 【Learning】分数规划

    分数规划 ​ 分数规划是一类决策性问题.一般地,题目会要求你针对问题规划一种方案,使得其代价函数最小或最大.其中,代价函数一般是分数形式,且分子分母的构成元素一般呈现一一对应关系. 直接上例题观察:B ...

  4. Spring MVC使用Cors实现跨域

    在开发APP过程中,APP调用后端接口有跨域的问题,只要在spring-mvc.xml 文件中加入下面的配置即可: <!-- 解决API接口跨域问题配置 Spring MVC 版本必须是 4.2 ...

  5. salt源码安装

    salt是什么? 一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯. salt底层采用动态的连接总线, 使其可以用于编配, 远 ...

  6. 利用机器学习实现微信小程序-加减大师自动答题

    之前有看到微信小程序<跳一跳>别人用python实现自动运行,后来看到别人用hash码实现<加减大师>的自动答题领取娃娃,最近一直在研究深度学习,为啥不用机器学习实现呢?不就是 ...

  7. python学习笔记__反射

    反射 # 通过字符串的形式对对象中的成员进行操作(获取/查找/添加/删除). 操作的内置函数: 1.获取   getattr(object, name) # 去对象object中获取name的内容 c ...

  8. 二、Linux学习之centOS的的setup

    因为我是在VMware上安装的centOS,网络设置选择的是桥接模式,这样可以和实体机使用同样的网络,但是也使用同样的IP,因此就需要设置一下IP了,否则使用ifconfig查询ip的时候显示的是12 ...

  9. mysqldump参数详细说明(转)

    Mysqldump参数大全(参数来源于mysql5.5.19源码)   参数 参数说明 --all-databases  , -A 导出全部数据库. mysqldump  -uroot -p --al ...

  10. SVN报错:Node remains in conflict显示冲突的解决办法

    如果是提示文件冲突: svn revert --depth=infinity 有冲突的文件名 如果提示目录有冲突: svn revert --depth=infinity 目录名 搞定.