基于AspectJ的注解AOP开发
AspectJ简介
环境搭建
使用AspectJ之前需要在pom.xml中引入Spring AOP和AspectJ的相关jar包
<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><!--aspectj的包依赖以上2个包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
配置文件
按以下内容配置好applicationContext.xml文件,即可开始AOP的注解开发。
<?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/></beans>
@AspectJ 注解提供的通知类型
- @Before => 相当于BeforeAdvice(前置通知)
- @AfterReturning => 相当于AfterReturningAdvice(后置通知)
- @Around => 相当于MethodInterceptor(环绕通知)
- @AfterThrowing=> 相当于ThrowAdvice(异常通知)
- @After => 相当于try-catch语句的finally,不管是否异常都会通知
value属性定义切点
在为一个方法写通知类型时,需要使用value属性来配置方法对应的切点(也就是拦截的方法)
前置通知的例子
com.aspectJ建了2个类,ProductDao是被代理类,MyAspectAnno是代理类。
配置文件
<?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/>
<!-- 配置被代理对象 -->
<bean id="productDao" class="com.aspectJ.ProductDao"></bean>
<!-- 配置切面 -->
<bean class="com.aspectJ.MyAspectAnno"></bean>
</beans>
2个类结构:
编写测试类
@org.junit.Test
public void test() {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
// 获取bean
ProductDao productDao = (ProductDao) context.getBean("productDao");
productDao.save();
productDao.delete();
}
运行结果:
前置增强...execution(void com.aspectJ.ProductDao.save())
保存商品...
删除商品...
其它类型通知
后置通知
// 后置通知,拦截update方法
@AfterReturning(value="execution(* com.aspectJ.ProductDao.update(..))",returning="ret")
public void afterReturning(Object ret) {
// ret是拦截的方法返回值
System.out.println("后置增强" + ret);
}
环绕通知
// 环绕通知,拦截所有方法
@Around(value="execution(* *(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前增强");
// 执行拦截到的方法
Object object = joinPoint.proceed();
System.out.println("环绕后增强");
return object;
}
异常抛出通知
// 异常抛出通知
@AfterThrowing(value="execution(* *(..))", throwing="e")
public void throwing(Throwable e) {
System.out.println("异常抛出通知" + e.getMessage());
}
最终通知(类似finally)
// 最终通知
@After(value="execution(* *(..))")
public void after() {
System.out.println("最终通知");
}
起别名:给要拦截的方法起别名,这样在一个方法需要在多处产生通知时使用别名有利于代码的维护.
value后面写要起别名的方法,下面写一个 private void 别名() {},这样就产生了别名,在使用拦截的地方,把value写成value="别名()"就可以了。
// 给拦截的方法起别名
@Pointcut(value="execution(* com.aspectJ.ProductDao.update(..))")
private void myPointCut() {}
// 后置通知,使用别名
@AfterReturning(value="myPointCut()",returning="ret")
public void afterReturning(Object ret) {
// ret是拦截的方法返回值
System.out.println("后置增强" + ret);
}