在实际开发中,最常用到的是基于AspectJ的AOP开发方式。
AspectJ的使用用两种方式:注解式和xml配置式。下面分别讲解。
注解式:
首先,引用开发包。下面列出使用Spring AspectJ所需要的完整依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</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>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
</dependencies>
实例中使用Junit进行测试,所以引入了junit包。
使用Spring进行开发,当然Spring的四个包不能少。
进行AOP的开发,aop联盟的包和Spring的aop 包也要引入。
使用aspectJ,要引入aspectJ框架的包和Spring的aspects包。
下面准备配置文件:因为需要aop开发,所以配置文件中需要有aop相关的约束。我们在IDEA中新建的spring配置文件是没有次约束的。可以在Spring包中的技术文件中找到:spring-framework-4.3.9.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html。页面中靠近末尾的地方有:41.2.7 the aop schema这一章节,把相应的xml文件内容复制来就行了。
<?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">
<!--开启AspectJ的注解开发,自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
其中加上一句:<aop:aspectj-autoproxy></aop:aspectj-autoproxy>。它指定开启@AspectJ自动代理
@AspectJ提供的不同类型的增强处理,我们已经有文章说过了。此文中用到:@Before、@AfterReturning、@Around、@AfterThrowing、@After这五种处理。
上面做好了准备工作,下面正式进入。
使用注解进行开发步骤非常简单:
1:首先要有目标类。这里我们提供一个ProductDao类:
package com.imooc.aspectJ.demo1;
public class ProductDao {
public void save(){
System.out.println("保存商品...");
}
public void update(){
System.out.println("修改商品...");
}
public String delete(){
System.out.println("删除商品...");
return "6666666";
}
public void findOne(){
System.out.println("查询一个商品...");
// int i = 1/0;
}
public void findAll(){
System.out.println("查询所有商品...");
}
}
2:使用@AspectJ来定义切面类。MyAspectAnno
package com.imooc.aspectJ.demo1;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* 切面类
*/
@Aspect
public class MyAspectAnno {
//前置增强注解
@Before(value="point()")
public void before(){
System.out.println("前置增强=========");
}
//后置增强注解
@AfterReturning(value="point()",returning = "result")
public void afterReturning(Object result){
System.out.println("后置增强========="+result);
}
//环绕增强注解
@Around(value="execution(* com.imooc.aspectJ.demo1.ProductDao.delete(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前处理============");
//此处是执行原方法。这里可以不执行,就截断了代理方法的执行。
Object obj = joinPoint.proceed();
System.out.println("环绕后处理============");
return obj;
}
//异常抛出注解
@AfterThrowing(value="execution(* com.imooc.aspectJ.demo1.ProductDao.findOne(..))",throwing = "e")
public void afterThrowing(Throwable e){
System.out.println("异常抛出通知============="+e.getMessage());
}
//最终注解
@After(value="execution(* com.imooc.aspectJ.demo1.ProductDao.findAll(..))")
public void after(){
System.out.println("最终通知===========");
}
//定义切入点
@Pointcut(value="execution(* com.imooc.aspectJ.demo1.ProductDao.save(..))")
public void point(){}
}
如上面代码所示,切面类定义好后,可以定义增强处理。基本用法是:
@Before(value="execution(<访问修饰符,可有可无> <返回值类型> <指定的方法名>(参数列表))")
这个注解作用就是:定义了增强处理的类型,还定义了作用到哪个类的哪个方法上。结合(*)的使用,可以变得非常灵活。
当然,增强注解都是作用于切面类的方法上的。也就是把方法内容织入到目标类的目标方法。
上面就完成了使用注解开发AOP。
具体到细节来说:
@Before注解,可以在注解的方法中传入JointPoint对象。此对象就是注解作用的目标类中的方法信息,就是连接点嘛。
@AfterReturning注解,可以定义方法返回值作为参数。当然也可以传入JointPoint对象。
@Around注解,此注解的方法要有返回值。要传入参数:ProceedingJointPoing pjp 。返回值就是目标代理方法的返回值。一般使用Object作为返回值类型。此注解方法最牛的是可以拦截目标代理方法的执行。只要其中不在增强方法中写pjp.proceed()即可。
@AfterThrowing注解,此注解在代理方法抛出异常时执行。
@After注解,此注解不管代理方法是否发生异常,都执行。
还有最有用的一点:定义切入点。
因为,比如我们目标代理方法中需要用到了好几个注解。那么难道我们每个注解都指定该切入点表达式吗?这就做了重复工作。
定义切入点的操作是:在切面类中随便建一个方法,该方法没有实际意义,就是用来写切入点表达式的。上面代码中的point方法就是一个切入点。它指向了* com.imooc.aspectJ.demo1.ProductDao.save(..)) 这个方法。我们的前置增强和后置增强处理需要指向这个方法时,value值写此方法就行了。