注意:下面的测试是spring4版本,spring5的执行顺序有变化,请看
1、操作术语:
-
连接点:
类里面哪些方法可以被增强,这些方法称为连接点 -
切入点:
实际被真正增强的方法,称为切入点 -
通知(增强):
1、实际增强的逻辑部分称为通知(增强)
2、通知的种类:- 前置通知——@Before()
- 后置通知——@AfterReturning() (也叫做返回通知)
- 环绕通知——@Around
- 异常通知——@AfterThrowing()
- 最终通知——@After()(相当于finally)
-
切面:
把通知应用到切入点的过程叫做切面
2、切入点表达式:
语法:execution( [权限修饰符] [返回类型] [方法名称] ([参数列表]))
- 举例1:对com.yy.test.BookService类里的add方法增强
execution(* com.yy.test.BookService.add(..)) - 举例2:对com.yy.test.BookService类里的所有方法增强
execution(* com.yy.test.BookService.*(..)) - 举例3:对com.yy.test包里的所有类的所有方法增强
execution(* com.yy.test. * . * (..))
返回类型可以省略
3、@Aspect注解用法:
-
环境:
- 引入依赖:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency>
- 开启包扫描和@Aspect注解
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启包扫描--> <context:component-scan base-package="com.yy.aspect"/> <!--开启aspectJ注解--> <aop:aspectj-autoproxy/> </beans>
- 引入依赖:
-
创建需要增强的的类User和代理类CommonAspect
User:
package com.yy.aspect;
import org.springframework.stereotype.Component;
@Component
public class User {
public void addUser(){
System.out.println("成功添加一个用户");
}
}
CommonAspect:
package com.yy.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class CommonAspect {
//前置通知
@Before(value = "execution(* com.yy.aspect.User.addUser(..))")
public void before(){
System.out.println("前置通知");
}
//后置通知(返回结果之后执行)
@AfterReturning(value = "execution(* com.yy.aspect.User.addUser(..))")
public void afterReturning(){
System.out.println("AfterReturning...");
}
//最终通知(不管有没有发生异常)
@After(value = "execution(* com.yy.aspect.User.addUser(..))")
public void after(){
System.out.println("最终通知");
}
//异常通知
@AfterThrowing(value = "execution(* com.yy.aspect.User.addUser(..))")
public void afterThrowing(){
System.out.println("AfterThrowing...");
}
//环绕通知
@Around(value = "execution(* com.yy.aspect.User.addUser(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知前");
proceedingJoinPoint.proceed();//被增强的方法执行
System.out.println("环绕通知后");
}
}
- 测试1(程序正常执行):
package com.yy.test;
import com.yy.aspect.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAspect {
@Test
public void testMethod(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User user = applicationContext.getBean(User.class);
user.addUser();
}
}
结果1:可以发现没有异常通知
环绕通知前
前置通知
成功添加一个用户
环绕通知后
最终通知
AfterReturning...
-
测试1(程序执行异常):
在User的addUser()方法中增加异常:
@Component
public class User {
public void addUser(){
int i= 10/0;
System.out.println("成功添加一个用户");
}
}
结果2:
环绕通知前
前置通知
最终通知
AfterThrowing...
java.lang.ArithmeticException: / by zero
at com.yy.aspect.User.addUser(User.java:9)
......
4. 相同切入点抽取:
可以发现:上面5中通知类型的切入点表达式都是一样的,于是可以将切入点抽取出来。
package com.yy.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class CommonAspect {
//抽取相同切入点
@Pointcut(value = "execution(* com.yy.aspect.User.addUser(..))")
public void pointCut(){}{}
//前置通知
@Before(value = "pointCut()")
public void before(){
System.out.println("前置通知");
}
//后置通知(返回结果之后执行)
@AfterReturning(value = "pointCut()")
public void afterReturning(){
System.out.println("AfterReturning...");
}
//最终通知(不管有没有发生异常)
@After(value = "pointCut()")
public void after(){
System.out.println("最终通知");
}
//异常通知
@AfterThrowing(value = "pointCut()")
public void afterThrowing(){
System.out.println("AfterThrowing...");
}
//环绕通知
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知前");
proceedingJoinPoint.proceed();//被增强的方法执行
System.out.println("环绕通知后");
}
}
5. 设置增强类的优先级:
如果多个增强类对同一个方法(或多个方法)增强,设置增强类的优先级:
- 在增强类上添加注解@Order(数字),数字越小优先级越高。