使用AspectJ实现AOP
Aspect简介
AspectJ是一个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ是AspectJ 1.5新增的功能,通过JDK5注解技术,允许直接在Bean类中定义切面
新版本Spring框架,建议使用AspectJ方式来开发AOP
1 2 3 4 5
   | 使用AspectJ需要引入Spring AOP和AspectJ相关Jar包: spring-aop aopalliance spring-aspects aspectjweaver
   | 
 
案例使用的代码:
 https://github.com/hzebin/SpringAOP_AspectJ 
使用AspectJ是,xml配置文件格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
      
           <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
 
  </beans>
   | 
 
@AspectJ提供的通知类型
| 通知类型 | 
说明 | 
| @Before | 
前置通知,相当于BeforeAdvice | 
| @AfterReturning | 
后置通知,相当于AfterReturningAdvice | 
| @Around | 
环绕通知,相当于AfterReturningAdvice | 
| @AfterThrowing | 
异常抛出通知,相当于ThrowAdvice | 
| @After | 
最终通知(相当于try-catch的finally),不管是否异常,该通知都会执行 | 
| @DeclareParents | 
引介通知,相当于IntroductionInterceptor | 
使用的例子(注解方式)
step1:创建Maven项目(Webapp)
step2:引入jar包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
   | <?xml version="1.0" encoding="UTF-8"?>
  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">   <modelVersion>4.0.0</modelVersion>
    <groupId>cn.hzebin</groupId>   <artifactId>im_spring_aspect</artifactId>   <version>1.0-SNAPSHOT</version>   <packaging>war</packaging>
    <name>im_spring_aspect Maven Webapp</name>      <url>http://www.example.com</url>
    <properties>     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>     <maven.compiler.source>1.7</maven.compiler.source>     <maven.compiler.target>1.7</maven.compiler.target>   </properties>
    <dependencies>          <dependency>       <groupId>junit</groupId>       <artifactId>junit</artifactId>       <version>4.11</version>       <scope>test</scope>     </dependency>     <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-test</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>
           <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-core</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>     <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-context</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>     <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-beans</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>     <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-expression</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>
           <dependency>       <groupId>aopalliance</groupId>       <artifactId>aopalliance</artifactId>       <version>1.0</version>     </dependency>     <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-aop</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>
           <dependency>       <groupId>org.aspectj</groupId>       <artifactId>aspectjweaver</artifactId>       <version>1.9.5</version>     </dependency>     <dependency>       <groupId>org.springframework</groupId>       <artifactId>spring-aspects</artifactId>       <version>4.2.4.RELEASE</version>     </dependency>     <dependency>       <groupId>junit</groupId>       <artifactId>junit</artifactId>       <version>4.12</version>       <scope>compile</scope>     </dependency>   </dependencies>
    <build>     <finalName>im_spring_aspect</finalName>     <pluginManagement>       <plugins>         <plugin>           <artifactId>maven-clean-plugin</artifactId>           <version>3.1.0</version>         </plugin>                  <plugin>           <artifactId>maven-resources-plugin</artifactId>           <version>3.0.2</version>         </plugin>         <plugin>           <artifactId>maven-compiler-plugin</artifactId>           <version>3.8.0</version>         </plugin>         <plugin>           <artifactId>maven-surefire-plugin</artifactId>           <version>2.22.1</version>         </plugin>         <plugin>           <artifactId>maven-war-plugin</artifactId>           <version>3.2.2</version>         </plugin>         <plugin>           <artifactId>maven-install-plugin</artifactId>           <version>2.5.2</version>         </plugin>         <plugin>           <artifactId>maven-deploy-plugin</artifactId>           <version>2.8.2</version>         </plugin>       </plugins>     </pluginManagement>   </build> </project>
   | 
 
step3 - 1:创建目标类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | package cn.hzebin.demo1;
  public class ProductDao {     public void add() {         System.out.println("增加操作");     }
      public void update() {         System.out.println("修改操作");     }
      public void find() {         System.out.println("查询操作");     }
      public void delete() {         System.out.println("删除操作");     } }
   | 
 
step3 - 2:创建切面类
JoinPoint类可以获得切入点信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | package cn.hzebin.demo1;
  import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;
 
 
 
  @Aspect   public class MyAspectAnno {
      
      @Before(value = "execution(* cn.hzebin.demo1.ProductDao.add(..))")     public void before(JoinPoint joinPoint) {                  System.out.println("前置通知" + joinPoint);     } }
   | 
 
step4:创建applicationContext.xml配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
      
           <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
           
           <bean id="productDao" class="cn.hzebin.demo1.ProductDao"></bean>
           <bean class="cn.hzebin.demo1.MyAspectAnno"></bean> </beans>
   | 
 
step5:使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | package cn.hzebin.demo1;
  import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  import javax.annotation.Resource;
 
 
 
 
 
  @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo1 {     @Resource(name = "productDao")     private ProductDao productDao;
      @Test     public void demo1() {         productDao.add();         productDao.delete();         productDao.find();         productDao.update();     } }
   | 
 
@Before前置通知
可以在方法中传入JoinPoint对象,用来获得切点的信息
1 2 3 4 5 6 7
   | 
  @Before(value = "execution(* cn.hzebin.demo1.ProductDao.add(..))") public void before(JoinPoint joinPoint) {          System.out.println("==前置通知==,可以获得切入点信息" + joinPoint); }
 
  | 
 
@AfterReturning后置通知
通过returning属性,可以定义方法返回值,作为参数
1 2 3 4 5
   |  @AfterReturning(value = "execution(* cn.hzebin.demo1.ProductDao.update(..))", returning = "result") public void demo2(Object result) {     System.out.println("==后置通知==,可以获得切入点的返回值  ->  " + result); }
 
  | 
 
@Around环绕通知
around方法的返回值就是目标代理方法执行返回值
参数为ProceedingJoinPoint,可以拦截目标方法的执行
1 2 3 4 5 6 7 8
   |  @Around(value = "execution(* cn.hzebin.demo1.ProductDao.delete(..))") public Object demo3(ProceedingJoinPoint joinPoint) throws Throwable {     System.out.println("环绕前的通知");     Object obj = joinPoint.proceed();       System.out.println("环绕后的通知");     return obj; }
 
  | 
 
@AfterThrowing异常通知
通过设置throwing属性,可以设置发生异常对象参数
1 2 3 4 5
   |  @AfterThrowing(value = "execution(* cn.hzebin.demo1.ProductDao.find(..))", throwing = "e") public void demo4(Throwable e) {     System.out.println("异常通知," + e.getMessage()); }
 
  | 
 
@After最终通知
无论是否发生异常,最终通知总是会被执行
1 2 3 4 5
   |  @After(value = "execution(* cn.hzebin.demo1.ProductDao.findOne(..))") public void demo5() {     System.out.println("最终通知"); }
 
  | 
 
@Pointcut可以给切点命名
- 在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
 
- 切点方法:private void 切点名() {}
 
- 当通知多个切点时,可以使用||进行连接
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
   | package cn.hzebin.demo2;
  import org.aspectj.lang.annotation.*;
 
 
 
  @Aspect public class AspectAnno {     @Before(value = "myPointCut1() || myPointCut2()")       public void demo1() {         System.out.println("前置通知");     }
      @AfterReturning(value = "myPointCut2()", returning = "result")     public void demo2(Object result) {         System.out.println("后置通知" + result);     }
 
           @Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.add(..))")     private void myPointCut1() {}
      @Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.delete(..))")     private void myPointCut2() {}
      @Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.update(..))")     private void myPointCut3() {}
      @Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.findOne(..))")     private void myPointCut4() {}
      @Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.findAll(..))")     private void myPointCut5() {} }
   | 
 
Aspect的XML配置
== 【unfinish】 ==