Spring AOP的注解简单实现

转载:https://blog.csdn.net/l1028386804/article/details/80295629

一、Spring AOP切面基础知识

下面,我们先来讲解一下Spring AOP切面的基础知识。

 * 连接点(Joinpoint) :程序执行过程中的某一行为(方法),例如,UserService.get()的调用或者UserService.delete()抛出异常等行为。
      * 通知(Advice) :“切面”对于某个“连接点”所产生的动作,例如,TestAspect中对com.spring.service包下所有类的方法进行日志记录的动作就是一个Advice。其中,一个“切面”可以包含多个“Advice”,例如ServiceAspect。
      * 切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。例如,TestAspect中的所有通知所关注的连接点,都由切入点表达式execution(* com.spring.service.impl..*.*(..))来决定。 
      * 目标对象(Target Object) :被一个或者多个切面所通知的对象。例如,AServcieImpl和BServiceImpl,在实际运行时,Spring AOP采用代理实现,实际AOP操作的是TargetObject的代理对象。 
      * AOP代理(AOP Proxy) :在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理,例如,AServiceImpl;反之,采用CGLIB代理,例如,BServiceImpl。强制使用CGLIB代理需要将 <aop:config>的 proxy-target-class属性设为true 。

    通知(Advice)类型

      *前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。

      *后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

      *返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。

      *环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。

      *抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

二、具体实现

1、定义接口UserService

[java]  view plain  copy
  1. package io.mykit.annotation.spring.aop.service;  
  2.   
  3. /** 
  4.  * Spring AOP注解实例的Service 
  5.  * @author liuyazhuang 
  6.  * 
  7.  */  
  8. public interface UserService {  
  9.       
  10.     void addUser();  
  11. }  

2、接口实现类UserServiceImpl

[java]  view plain  copy
  1. package io.mykit.annotation.spring.aop.service.impl;  
  2.   
  3. import org.springframework.stereotype.Service;  
  4.   
  5. import io.mykit.annotation.spring.aop.service.UserService;  
  6.   
  7. @Service("aopUserService")  
  8. public class UserServiceImpl implements UserService {  
  9.     @Override  
  10.     public void addUser() {  
  11.         System.out.println("执行addUser方法...");  
  12.     }  
  13.   
  14. }  

3、实现Spring AOP切面解析类Interceptor

[java]  view plain  copy
  1. package io.mykit.annotation.spring.aop.interceptor;  
  2.   
  3. import org.aspectj.lang.JoinPoint;  
  4. import org.aspectj.lang.ProceedingJoinPoint;  
  5. import org.aspectj.lang.annotation.After;  
  6. import org.aspectj.lang.annotation.AfterReturning;  
  7. import org.aspectj.lang.annotation.AfterThrowing;  
  8. import org.aspectj.lang.annotation.Around;  
  9. import org.aspectj.lang.annotation.Aspect;  
  10. import org.aspectj.lang.annotation.Before;  
  11. import org.aspectj.lang.annotation.Pointcut;  
  12. import org.slf4j.Logger;  
  13. import org.slf4j.LoggerFactory;  
  14. import org.springframework.stereotype.Component;  
  15.   
  16. /** 
  17.  * 定义Spring AOP注解的 
  18.  * @author liuyazhuang 
  19.  * 
  20.  */  
  21. @Aspect//定义切面  
  22. @Component//声明这是一个组件  
  23. public class Interceptor {  
  24.   
  25.     private static final Logger log = LoggerFactory.getLogger(Interceptor.class);  
  26.       
  27.     /** 
  28.      * 这句话是方法切入点 
  29.      * 1 execution (* io.mykit.annotation.spring.aop.service.impl..*.*(..)) 
  30.      * 2 execution : 表示执行 
  31.      * 3 第一个*号 : 表示返回值类型, *可以是任意类型 
  32.      * 4 io.mykit.annotation.spring.aop.service.impl : 代表扫描的包 
  33.      * 5 .. : 代表其底下的子包也进行拦截   
  34.      * 6 第二个*号 : 代表对哪个类进行拦截,*代表所有类   
  35.      * 7 第三个*号 : 代表方法  *代表任意方法 
  36.      * 8 (..) : 代表方法的参数有无都可以 
  37.      */  
  38.     //配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点  
  39.     @Pointcut("execution (* io.mykit.annotation.spring.aop.service.impl..*.*(..))")  
  40.     private void aspect() {  
  41.         System.out.println("============进入aspect方法==============");  
  42.     }  
  43.              
  44.     //配置环绕通知,使用在方法aspect()上注册的切入点  
  45.     @Around("aspect()")  
  46.     public void around(JoinPoint joinPoint){  
  47.         long start = System.currentTimeMillis();  
  48.         try {  
  49.             ((ProceedingJoinPoint) joinPoint).proceed();  
  50.             long end = System.currentTimeMillis();  
  51.             if(log.isInfoEnabled()){  
  52.                 log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");//这里顺便记录下执行速度,可以作为监控  
  53.             }  
  54.         } catch (Throwable e) {  
  55.             long end = System.currentTimeMillis();  
  56.             if(log.isInfoEnabled()){  
  57.                 log.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());  
  58.             }  
  59.         }  
  60.     }  
  61.      //前置通知等可以没有JoinPoint参数  
  62.     @Before("aspect()")  
  63.     public void doBefore(JoinPoint joinPoint) {  
  64.         System.out.println("==========执行前置通知===============");  
  65.         if(log.isInfoEnabled()){  
  66.             log.info("before " + joinPoint);  
  67.         }  
  68.     }        
  69.     //配置后置通知,使用在方法aspect()上注册的切入点  
  70.     @After("aspect()")  
  71.     public void doAfter(JoinPoint joinPoint) {  
  72.         System.out.println("===========执行后置通知==============");  
  73.         if(log.isInfoEnabled()){  
  74.             log.info("after " + joinPoint);  
  75.         }  
  76.     }    
  77.     //配置后置返回通知,使用在方法aspect()上注册的切入点  
  78.     @AfterReturning("aspect()")  
  79.     public void afterReturn(JoinPoint joinPoint){  
  80.         System.out.println("===========执行后置返回通知==============");  
  81.         if(log.isInfoEnabled()){  
  82.             log.info("afterReturn " + joinPoint);  
  83.         }  
  84.     }   
  85.     //配置抛出异常后通知,使用在方法aspect()上注册的切入点  
  86.     @AfterThrowing(pointcut="aspect()", throwing="ex")  
  87.     public void afterThrow(JoinPoint joinPoint, Exception ex){  
  88.          if(log.isInfoEnabled()){  
  89.              log.info("afterThrow " + joinPoint + "\t" + ex.getMessage());  
  90.          }  
  91.     }     
  92. }  

4、spring-aop-context.xml文件

[html]  view plain  copy
  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:p="http://www.springframework.org/schema/p"  
  5.        xmlns:context="http://www.springframework.org/schema/context"  
  6.        xmlns:aop="http://www.springframework.org/schema/aop"   
  7.        xmlns:tx="http://www.springframework.org/schema/tx"  
  8.        xmlns:mvc="http://www.springframework.org/schema/mvc"  
  9.        xmlns:cache="http://www.springframework.org/schema/cache"  
  10.        xmlns:task="http://www.springframework.org/schema/task"  
  11.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  12.                         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
  13.                         http://www.springframework.org/schema/context   
  14.                         http://www.springframework.org/schema/context/spring-context-4.0.xsd  
  15.                         http://www.springframework.org/schema/tx   
  16.                         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd  
  17.                         http://www.springframework.org/schema/aop   
  18.                         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
  19.                         http://www.springframework.org/schema/mvc   
  20.                         http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd  
  21.                         http://www.springframework.org/schema/cache   
  22.                         http://www.springframework.org/schema/cache/spring-cache-4.0.xsd  
  23.                         http://www.springframework.org/schema/task  http://www.springframework.org/schema/task/spring-task-4.0.xsd"  
  24.                         default-autowire="byName">  
  25.      <mvc:annotation-driven />  
  26.      <!-- 激活组件扫描功能,在包io.mykit.annotation.spring.aop及其子包下面自动扫描通过注解配置的组件 -->  
  27.      <context:component-scan base-package="io.mykit.annotation.spring.aop" />   
  28.       
  29.      <!-- 启动对@AspectJ注解的支持 -->  
  30.      <!-- proxy-target-class等于true是强制使用cglib代理,proxy-target-class默认是false,如果你的类实现了接口 就走JDK代理,如果没有走cglib代理  -->  
  31.      <!-- 注:对于单利模式建议使用cglib代理,虽然JDK动态代理比cglib代理速度快,但性能不如cglib -->  
  32.      <aop:aspectj-autoproxy proxy-target-class="true"/>  
  33.      <context:annotation-config />  
  34.      <bean id="interceptor" class="io.mykit.annotation.spring.aop.interceptor.Interceptor"/>   
  35. </beans>  

5、创建测试类

[java]  view plain  copy
  1. package io.mykit.annotation.spring.aop.provider;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. import io.mykit.annotation.spring.aop.service.UserService;  
  7.   
  8. /** 
  9.  * 测试 Spring AOP注解 
  10.  * @author liuyazhuang 
  11.  * 
  12.  */  
  13. public class AOPAnnotationTest {  
  14.       
  15.     @SuppressWarnings("resource")  
  16.     @Test  
  17.     public void testAOPAnnotation(){  
  18.         //启动Spring容器          
  19.         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"spring/spring-aop-annotation.xml"});  
  20.         UserService userService = (UserService) ctx.getBean("aopUserService");  
  21.         userService.addUser();  
  22.     }  
  23. }  

6、pom.xml Jar包依赖

[html]  view plain  copy
  1. <properties>  
  2.     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  3.     <skip_maven_deploy>false</skip_maven_deploy>  
  4.     <jdk.version>1.8</jdk.version>  
  5.     <spring.version>4.1.0.RELEASE</spring.version>  
  6. </properties>  
  7.   
  8. <dependencies>  
  9.      
  10.   <dependency>  
  11.         <groupId>org.springframework</groupId>  
  12.         <artifactId>spring-expression</artifactId>  
  13.         <version>${spring.version}</version>  
  14.     </dependency>   
  15.       
  16.         <dependency>  
  17.         <groupId>org.springframework</groupId>  
  18.         <artifactId>spring-messaging</artifactId>  
  19.         <version>${spring.version}</version>  
  20.     </dependency>  
  21.       
  22.     <dependency>  
  23.         <groupId>org.springframework</groupId>  
  24.         <artifactId>spring-jms</artifactId>  
  25.         <version>${spring.version}</version>  
  26.     </dependency>  
  27.       
  28.     <dependency>  
  29.         <groupId>org.springframework</groupId>  
  30.         <artifactId>spring-aop</artifactId>  
  31.         <version>${spring.version}</version>  
  32.     </dependency>  
  33.       
  34.     <dependency>  
  35.         <groupId>org.springframework</groupId>  
  36.         <artifactId>spring-jdbc</artifactId>  
  37.          <version>${spring.version}</version>  
  38.     </dependency>  
  39.       
  40.      <dependency>  
  41.         <groupId>org.springframework</groupId>  
  42.         <artifactId>spring-context</artifactId>  
  43.         <version>${spring.version}</version>  
  44.     </dependency>  
  45.   
  46.     <dependency>  
  47.         <groupId>org.springframework</groupId>  
  48.         <artifactId>spring-context-support</artifactId>  
  49.         <version>${spring.version}</version>  
  50.     </dependency>  
  51.       
  52.     <dependency>  
  53.         <groupId>org.springframework</groupId>  
  54.         <artifactId>spring-web</artifactId>  
  55.         <version>${spring.version}</version>  
  56.     </dependency>  
  57.       
  58.     <dependency>  
  59.         <groupId>org.springframework</groupId>  
  60.         <artifactId>spring-webmvc</artifactId>  
  61.         <version>${spring.version}</version>  
  62.     </dependency>  
  63.       
  64.     <dependency>  
  65.         <groupId>org.aspectj</groupId>  
  66.         <artifactId>aspectjtools</artifactId>  
  67.         <version>1.9.1</version>  
  68.     </dependency>  
  69.       
  70.     <dependency>  
  71.         <groupId>javax.servlet</groupId>  
  72.         <artifactId>javax.servlet-api</artifactId>  
  73.         <version>3.0.1</version>  
  74.     </dependency>  
  75.   
  76.     <dependency>    
  77.         <groupId>org.slf4j</groupId>    
  78.         <artifactId>slf4j-log4j12</artifactId>    
  79.         <version>1.7.2</version>    
  80.     </dependency>   
  81.       
  82.       <dependency>  
  83.         <groupId>commons-logging</groupId>  
  84.         <artifactId>commons-logging</artifactId>  
  85.         <version>1.1.1</version>  
  86.     </dependency>  
  87.      <dependency>  
  88.             <groupId>cglib</groupId>  
  89.             <artifactId>cglib-nodep</artifactId>  
  90.             <version>2.1_3</version>  
  91.         </dependency>  
  92.       
  93. </dependencies>  

7、log4j.properties

[plain]  view plain  copy
  1. log4j.rootCategory=INFO,stdout,file,ERROR  
  2. #log4j.rootCategory=ERROR,stdout,file  
  3. log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
  4. #log4j.appender.stdout=org.apache.log4j.FileAppender  
  5. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
  6. log4j.appender.stdout.layout.ConversionPattern=[mykit-annotation-spring-provider]%d %p [%t] %C{1}.%M(%L) | %m%n  
  7.   
  8. #log4j.appender.file=org.apache.log4j.DailyRollingFileAppender   
  9. #log4j.appender.file.MaxFileSize=100KB  
  10. #log4j.appender.file.DatePattern = '.'yyyy-MM-dd'.log'  
  11.   
  12. log4j.appender.file=org.apache.log4j.DailyRollingFileAppender   
  13. log4j.appender.file.File=/home/mykit/logs/mykit-annotation-spring-provider/mykit-annotation-spring-provider  
  14. log4j.appender.file.DatePattern='.'yyyy-MM-dd'.log'  
  15. log4j.appender.file.layout=org.apache.log4j.PatternLayout  
  16. log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%c-%L]-[%t]-[%p] %m%n  

8、测试结果

[plain]  view plain  copy
  1. ==========执行前置通知===============  
  2. [mykit-annotation-spring-provider]2018-05-12 22:42:46,449 INFO [main] Interceptor.doBefore(66) | before execution(void io.mykit.annotation.spring.aop.service.impl.UserServiceImpl.addUser())  
  3. 执行addUser方法...  
  4. [mykit-annotation-spring-provider]2018-05-12 22:42:46,461 INFO [main] Interceptor.around(52) | around execution(void io.mykit.annotation.spring.aop.service.impl.UserServiceImpl.addUser()) Use time : 14 ms!  
  5. ===========执行后置通知==============  
  6. [mykit-annotation-spring-provider]2018-05-12 22:42:46,462 INFO [main] Interceptor.doAfter(74) | after execution(void io.mykit.annotation.spring.aop.service.impl.UserServiceImpl.addUser())  
  7. ===========执行后置返回通知==============  
  8. [mykit-annotation-spring-provider]2018-05-12 22:42:46,462 INFO [main] Interceptor.afterReturn(82) | afterReturn execution(void io.mykit.annotation.spring.aop.service.impl.UserServiceImpl.addUser())  

猜你喜欢

转载自blog.csdn.net/u011109589/article/details/80305858