深入浅出Spring Aop

来源:互联网 发布:js判断手指滑动距离 编辑:程序博客网 时间:2024/06/01 18:58

AOP联盟规范了一套用于规范AOP实现的底层API,通过这些统一的底层API,可以使得各个AOP实现及工具产品之间实现相互移植。这些API主要以标准接口的形式提供,是AOP编程思想所要解决的横切交叉关注点问题各部件的最高抽象。无论是Spring的AOP框架,还是开源的aspect框架,都是直接以这些API为基础所构建。

这里写图片描述

这里写图片描述

这里写图片描述

Spring实现AOP都是基于接口形式的

这里写图片描述

这里写图片描述

  1. public interface GreetingInterface {
  2. String sayHello(String name);
  3. }

  1. public class GreetingImpl implements GreetingInterface {
  2.  
  3. @Override
  4. public String sayHello(String name) {
  5. System.out.println("Hello! " + name);
  6. return name;
  7. }
  8. }

这里写图片描述

  1. /** 前置通知 */
  2. public class GreetingBeforeAdvice implements MethodBeforeAdvice{
  3.  
  4. @Override
  5. public void before(Method method, Object[] args, Object target) throws Throwable {
  6. System.out.println(">>>>>>>>>>>>>>>>>>Before Start>>>>>>>>>>>>>>>>>>");
  7. System.out.println("Method Name: " + method.getName());
  8. System.out.println("args:" + Arrays.toString(args));
  9. System.out.println("Target : " + target.getClass().getName());
  10. System.out.println("<<<<<<<<<<<<<<<<<<Before End<<<<<<<<<<<<<<<<<<<<<<<<");
  11. }
  12.  
  13. }

  1. /** 后置返回通知*/
  2. public class GreetingAfterAdvice implements AfterReturningAdvice {
  3.  
  4. @Override
  5. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
  6. System.out.println(">>>>>>>>>>>>>>>>After Start>>>>>>>>>>>>>>>>>>>>");
  7. System.out.println("returnValue:" + returnValue);
  8. System.out.println("Method Name: " + method.getName());
  9. System.out.println("args:" + Arrays.toString(args));
  10. System.out.println("Target : " + target.getClass().getName());
  11. System.out.println("<<<<<<<<<<<<<<<<<After End<<<<<<<<<<<<<<<<<<<<<<");
  12. }
  13.  
  14. }

  1. /** 异常通知 */
  2. public class GreetingThrowAdvice implements ThrowsAdvice {
  3.  
  4. public void afterThrowing(Method method, Object[] args, Object target, Exception e) {
  5. System.out.println("---------- Throw Exception ----------");
  6. System.out.println("Target Class: " + target.getClass().getName());
  7. System.out.println("Method Name: " + method.getName());
  8. System.out.println("Exception Message: " + e.getMessage());
  9. System.out.println("-------------------------------------");
  10. }
  11. }

  1. /** 环绕通知*/
  2. public class GreetingAroundAdvice implements MethodInterceptor {
  3.  
  4. @Override
  5. public Object invoke(MethodInvocation invocation) throws Throwable {
  6. before();
  7. Object result = invocation.proceed();
  8. after();
  9. return result;
  10. }
  11.  
  12. private void before() {
  13. System.out.println("---->>>>Before");
  14. }
  15.  
  16. private void after() {
  17. System.out.println("---->>>>After");
  18. }
  19. }

这里写图片描述

  1. public class AdviceClient {
  2.  
  3. public static void main(String[] args) {
  4. ProxyFactory proxyFactory = new ProxyFactory(); // 创建代理工厂
  5. proxyFactory.setTarget(new GreetingImpl()); // 射入目标类对象
  6. proxyFactory.addAdvice(new GreetingBeforeAdvice()); // 添加前置通知
  7. proxyFactory.addAdvice(new GreetingAfterAdvice()); // 添加后置通知
  8. proxyFactory.addAdvice(new GreetingAroundAdvice()); // 添加环绕通知
  9. proxyFactory.addAdvice(new GreetingThrowAdvice()); // 添加抛出通知
  10. proxyFactory.setOptimize(true);//使用CGLIB动态代理
  11.  
  12. GreetingInterface greeting = (GreetingInterface) proxyFactory.getProxy(); // 从代理工厂中获取代理
  13. greeting.sayHello("Jack"); // 调用代理的方法
  14.  
  15. }
  16. }

这里写图片描述

第一种方式:

  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="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <bean id="greetingAfterReturningAdvice" class="com.somnus.spring.xml.aop.GreetingAfterReturningAdvice"/>
  7. <bean id="greetingAroundAdvice" class="com.somnus.spring.xml.aop.GreetingAroundAdvice"/>
  8. <bean id="greetingBeforeAdvice" class="com.somnus.spring.xml.aop.GreetingBeforeAdvice"/>
  9. <bean id="greetingThrowsAdvice" class="com.somnus.spring.xml.aop.GreetingThrowsAdvice"/>
  10.  
  11. <bean id="greetingImpl" class="com.somnus.spring.xml.aop.GreetingImpl"/>
  12.  
  13.  
  14. <!-- 配置一个代理 -->
  15. <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  16. <property name="interfaces" value="com.somnus.spring.xml.aop.GreetingInterface"/> <!-- 需要代理的接口 -->
  17. <property name="target" ref="greetingImpl"/> <!-- 目标接口实现类 -->
  18. <property name="interceptorNames"> <!-- 拦截器名称(也就是增强类名称,Spring Bean 的 id) -->
  19. <list>
  20. <value>greetingBeforeAdvice</value>
  21. <value>greetingAfterReturningAdvice</value>
  22. </list>
  23. </property>
  24. </bean>
  25.  
  26. </beans>
  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="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <bean id="greetingIntroAdvice" class="com.somnus.spring.xml.aop.GreetingIntroAdvice"/>
  7.  
  8. <bean id="greetingImpl" class="com.somnus.spring.xml.aop.GreetingImpl"/>
  9. <bean id="greetingImply" class="com.somnus.spring.xml.aop.GreetingImply"/>
  10.  
  11. <!-- 使用ProxyFactoryBean或者其它IOC相关类来创建AOP代理的最重要好处就是通知切入点也可以由IOC来管理 -->
  12. <!-- 被代理类没有任何接口,使用CGLIB代理,否则JDK代理 -->
  13. <!-- 通过设置proxyTargetClass为true,可【强制使】用CGLIB -->
  14. <!-- 如果目标类实现了一个(或者多个)接口,那么创建代理的类型将依赖ProxyFactoryBean的配置 -->
  15. <!-- 如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或者多个全限定接口名,基于JDK的代理将被创建 -->
  16. <!-- 如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个(或者更多)接口,那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理 -->
  17.  
  18. <bean id="greetingProxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
  19. <property name="interfaces" value="com.somnus.spring.xml.aop.Apology"/><!-- 需要动态实现的接口 -->
  20. <property name="target" ref="greetingImpl"/> <!-- 目标类 -->
  21. <property name="interceptorNames" value="greetingIntroAdvice"/> <!-- 引入增强 -->
  22. <property name="proxyTargetClass" value="true"/> <!-- 代理目标类(默认为 false,代理接口) -->
  23. </bean>
  24.  
  25. </beans>

第二种方式:

  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="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <bean id="greetingAfterReturningAdvice" class="com.somnus.spring.xml.aop.GreetingAfterReturningAdvice"/>
  7. <bean id="greetingAroundAdvice" class="com.somnus.spring.xml.aop.GreetingAroundAdvice"/>
  8. <bean id="greetingBeforeAdvice" class="com.somnus.spring.xml.aop.GreetingBeforeAdvice"/>
  9. <bean id="greetingThrowsAdvice" class="com.somnus.spring.xml.aop.GreetingThrowsAdvice"/>
  10.  
  11. <bean id="greetingImpl" class="com.somnus.spring.xml.aop.GreetingImpl"/>
  12.  
  13. <!-- 配置一个切面 -->
  14. <bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  15. <property name="advice" ref="greetingAroundAdvice"/> <!-- 增强 -->
  16. <property name="pattern" value="com.somnus.spring.xml.aop.GreetingImpl.good.*"/> <!-- 切点(正则表达式) -->
  17. </bean>
  18.  
  19. <!-- 配置一个代理 -->
  20. <bean id="greetingProxy3" class="org.springframework.aop.framework.ProxyFactoryBean">
  21. <property name="interfaces" value="com.somnus.spring.xml.aop.GreetingInterface"/> <!-- 需要代理的接口 -->
  22. <property name="target" ref="greetingImpl"/> <!-- 目标接口实现类 -->
  23. <property name="interceptorNames" value="greetingAdvisor"/> <!-- 切面 -->
  24. <property name="proxyTargetClass" value="false"/> <!-- 代理目标类(默认为 false,代理接口)-->
  25. </bean>
  26.  
  27. </beans>

第三种方式

  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="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  5.  
  6. <bean id="greetingAfterReturningAdvice" class="com.somnus.spring.xml.aop.GreetingAfterReturningAdvice"/>
  7. <bean id="greetingAroundAdvice" class="com.somnus.spring.xml.aop.GreetingAroundAdvice"/>
  8. <bean id="greetingBeforeAdvice" class="com.somnus.spring.xml.aop.GreetingBeforeAdvice"/>
  9. <bean id="greetingThrowsAdvice" class="com.somnus.spring.xml.aop.GreetingThrowsAdvice"/>
  10.  
  11. <bean id="greetingImpl" class="com.somnus.spring.xml.aop.GreetingImpl"/>
  12. <bean id="greetingImply" class="com.somnus.spring.xml.aop.GreetingImply"/>
  13.  
  14. <!-- 自动代理(扫描 Bean名称) -->
  15. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> -->
  16. <property name="beanNames" value="*Impl"/> <!-- 只为后缀是“Impl”的 Bean 生成代理 -->
  17. <property name="interceptorNames" value="greetingAroundAdvice"/> <!-- 增强 -->
  18. <property name="optimize" value="true"/> <!-- 是否对代理生成策略进行优化 -->
  19. </bean>
  20. <!-- optimize若为 true 时,则可对代理生成策略进行优化(默认是 false 的)。也就是说,如果该类有接口,
  21. 就代理接口(使用 JDK 动态代理);如果没有接口,就代理类(使用 CGLib 动态代理)。
  22. 而并非像之前使用的 proxyTargetClass 属性那样,强制代理类,而不考虑代理接口的方式。
  23. -->
  24.  
  25. </beans>


这里写图片描述

这里写图片描述

这里写图片描述

  1. package com.somnus.spring.namespace.aop;
  2.  
  3. import java.util.Arrays;
  4.  
  5. import org.aspectj.lang.JoinPoint;
  6. import org.aspectj.lang.ProceedingJoinPoint;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8.  
  9. public class GreetAspector {
  10.  
  11. /**@前置通知
  12. * 方法开始之前执行一段代码
  13. * @param joinPoint
  14. */
  15. public void before(JoinPoint joinPoint) {
  16. String methodName = joinPoint.getSignature().getName();
  17. Object[] args = joinPoint.getArgs();
  18. System.out.println("The method 【" + methodName + "】 begins with " + Arrays.asList(args));
  19. }
  20.  
  21. /**@后置最终通知
  22. * 方法执行之后执行一段代码
  23. * 无论该方法是否出现异常
  24. * @param joinPoint
  25. */
  26. public void after(JoinPoint joinPoint) {
  27. String methodName = joinPoint.getSignature().getName();
  28. Object[] args = joinPoint.getArgs();
  29. System.out.println("The method 【" + methodName + "】 ends with " + Arrays.asList(args));
  30. }
  31.  
  32. /**@后置返回通知
  33. * 方法正常结束后执行的代码,不包括抛出异常的情况
  34. * 返回通知是可以访问到方法的返回值的
  35. * @param joinPoint
  36. * @param result
  37. */
  38. public void afterReturning(JoinPoint joinPoint,Object result) {
  39. String methodName = joinPoint.getSignature().getName();
  40. System.out.println("The method 【" + methodName + "】 return with " + result);
  41. }
  42.  
  43. /**@后置异常通知
  44. * 在方法出现异常时会执行的代码
  45. * 可以访问到异常对象,可以指定在出现特定异常时在执行通知代码
  46. * @param joinPoint
  47. * @param ex
  48. */
  49. public void afterThrowing(JoinPoint joinPoint, Exception ex) {
  50. String methodName = joinPoint.getSignature().getName();
  51. System.out.println("The method " + methodName + " occurs exception: " + ex);
  52. }
  53.  
  54. /**@环绕通知
  55. * 环绕通知需要携带ProceedingJoinPoint类型的参数
  56. * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
  57. * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
  58. * @param pjp
  59. * @return
  60. * @throws Throwable
  61. */
  62. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  63. Object result = null;
  64. System.out.println("target:"+pjp.getTarget());
  65. MethodSignature signature = (MethodSignature) pjp.getSignature();
  66. String methodName = signature.getName();
  67. //执行目标方法
  68. try {
  69.  
  70. System.out.println("ARROUND-->The method 【" + methodName + "】 begins with 【" + Arrays.asList(pjp.getArgs()) +"】");
  71. result = pjp.proceed();
  72. } catch (Throwable e) {
  73.  
  74. System.out.println("ARROUND-->The method 【" + methodName + "】 occurs expection : 【" + e +"】");
  75. throw new RuntimeException(e);
  76. }
  77.  
  78. System.out.println("ARROUND-->The method 【" + methodName + "】 return with 【" + result +"】");
  79. return result;
  80. }
  81.  
  82. }

这里写图片描述

  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. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  6. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  7.  
  8. <!-- application 上下文 -->
  9. <bean class="com.somnus.ApplicationContextHolder"/>
  10.  
  11. <bean id="greetAspector" class="com.somnus.spring.namespace.aop.GreetAspector"/>
  12.  
  13. <bean id="greetingImpl" class="com.somnus.spring.namespace.aop.GreetingImpl"/>
  14.  
  15. <!-- AOP配置 -->
  16. <aop:config>
  17. <!-- 声明一个切面,并注入切面Bean,相当于@Aspect -->
  18. <aop:aspect id="greetAspector" ref="greetAspector">
  19. <!-- 配置一个切入点,相当于@Pointcut -->
  20. <aop:pointcut id="greetPointcut" expression="execution(* com.somnus.spring.namespace.aop.GreetingImpl.*(..))" />
  21. <!-- 配置通知,相当于@Before、@After、@AfterReturn、@Around、@AfterThrowing -->
  22. <aop:before pointcut-ref="greetPointcut" method="before"/>
  23. <aop:after pointcut-ref="greetPointcut" method="after"/>
  24. <aop:after-returning pointcut-ref="greetPointcut" method="afterReturning" returning="result"/>
  25. <aop:after-throwing pointcut-ref="greetPointcut" method="afterThrowing" throwing="ex"/>
  26. <aop:around pointcut-ref="greetPointcut" method="around"/>
  27. <aop:declare-parents types-matching="com.somnus.spring.namespace.aop.GreetingImpl"
  28. implement-interface="com.somnus.spring.namespace.aop.Apology"
  29. default-impl="com.somnus.spring.namespace.aop.ApologyImpl"/>
  30. </aop:aspect>
  31. </aop:config>
  32.  
  33. </beans>

这里写图片描述

这里写图片描述

  1. <!-- 强制CGLIB代理 -->
  2. <!-- proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为true时,
  3. 表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,
  4. 则spring将自动使用CGLib动态代理。@see http://blog.chinaunix.net/uid-11898547-id-3417894.html -->
  5. <aop:aspectj-autoproxy proxy-target-class="true"/>

这里写图片描述

  1. package com.somnus.spring.annotation.aop;
  2.  
  3. import java.lang.reflect.Method;
  4. import java.util.Arrays;
  5.  
  6. import org.aspectj.lang.JoinPoint;
  7. import org.aspectj.lang.ProceedingJoinPoint;
  8. import org.aspectj.lang.annotation.After;
  9. import org.aspectj.lang.annotation.AfterReturning;
  10. import org.aspectj.lang.annotation.AfterThrowing;
  11. import org.aspectj.lang.annotation.Around;
  12. import org.aspectj.lang.annotation.Aspect;
  13. import org.aspectj.lang.annotation.Before;
  14. import org.aspectj.lang.annotation.DeclareParents;
  15. import org.aspectj.lang.reflect.MethodSignature;
  16. import org.springframework.stereotype.Component;
  17.  
  18. @Aspect
  19. @Component
  20. public class GreetAspector {
  21. /**@前置通知
  22. * 方法开始之前执行一段代码
  23. * @param joinPoint
  24. */
  25. @Before("execution(* com.somnus.spring.annotation.aop.GreetingImpl.*(..))")
  26. public void before(JoinPoint point) {
  27. String methodName = point.getSignature().getName();
  28. Method method = ((MethodSignature) point.getSignature()).getMethod();
  29. System.out.println(method.getName());
  30. Object[] args = point.getArgs();
  31. System.out.println("The method 【" + methodName + "】 begins with " + Arrays.asList(args));
  32. }
  33.  
  34. /**@后置最终通知
  35. * 方法执行之后执行一段代码
  36. * 无论该方法是否出现异常
  37. * @param joinPoint
  38. */
  39. @After("execution(* com.somnus.spring.annotation.aop.GreetingImpl.*(..))")
  40. public void after(JoinPoint point) {
  41. String methodName = point.getSignature().getName();
  42. Object[] args = point.getArgs();
  43. System.out.println("The method 【" + methodName + "】 ends with " + Arrays.asList(args));
  44. }
  45.  
  46. /**@后置返回通知
  47. * 方法正常结束后执行的代码,不包括抛出异常的情况
  48. * 返回通知是可以访问到方法的返回值的
  49. * @param joinPoint
  50. * @param result
  51. */
  52. @AfterReturning(value="execution(* com.somnus.spring.annotation.aop.GreetingImpl.*(..))",returning="result")
  53. public void afterReturning(JoinPoint point,Object result) {
  54. String methodName = point.getSignature().getName();
  55. System.out.println("The method 【" + methodName + "】 return with " + result);
  56. }
  57.  
  58. /**@后置异常通知
  59. * 在方法出现异常时会执行的代码
  60. * 可以访问到异常对象,可以指定在出现特定异常时在执行通知代码
  61. * @param joinPoint
  62. * @param ex
  63. */
  64. @AfterThrowing(value="execution(* com.somnus.spring.annotation.aop.GreetingImpl.*(..))", throwing="ex")
  65. public void afterThrowing(JoinPoint point, Exception ex) {
  66. String methodName = point.getSignature().getName();
  67. System.out.println("The method " + methodName + " occurs exception: " + ex);
  68. }
  69.  
  70. /**@环绕通知
  71. * 环绕通知需要携带ProceedingJoinPoint类型的参数
  72. * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
  73. * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
  74. * @param pjp
  75. * @return
  76. * @throws Throwable
  77. */
  78. @Around("execution(* com.somnus.spring.annotation.aop.GreetingImpl.*(..))")
  79. public Object around(ProceedingJoinPoint point) throws Throwable {
  80. Object result = null;
  81. System.out.println("target:" + point.getTarget());
  82. Method method = ((MethodSignature) point.getSignature()).getMethod();
  83. System.out.println(method.getName());
  84. String methodName = point.getSignature().getName();
  85. //执行目标方法
  86. try {
  87. //前置通知
  88. System.out.println("ARROUND-->The method 【" + methodName + "】 begins with 【" + Arrays.asList(point.getArgs()) +"】");
  89. result = point.proceed();
  90. } catch (Throwable e) {
  91. //后置异常通知【在方法出现异常时会执行的代码】
  92. System.out.println("ARROUND-->The method 【" + methodName + "】 occurs expection : 【" + e +"】");
  93. throw new RuntimeException(e);
  94. }
  95. //后置返回通知【方法正常结束后执行的代码,不包括抛出异常的情况】
  96. System.out.println("ARROUND-->The method 【" + methodName + "】 return with 【" + result +"】");
  97. return result;
  98. }
  99.  
  100. /**
  101. * 用 AOP 的行话来讲,对方法的增强叫做 Weaving(织入),
  102. * 而对类的增强叫做 Introduction(引入)。
  103. * 而 Introduction Advice(引入增强)就是对类的功能增强,
  104. * 它也是 Spring AOP 提供的最后一种增强
  105. */
  106. @DeclareParents(value = "com.somnus.spring.annotation.aop.GreetingImpl", defaultImpl = ApologyImpl.class)
  107. private Apology apology;
  108. }
原创粉丝点击