SpringBoot应用AOP及各注解的执行顺序
首先第一步,POM引入jar
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-aop</artifactId>
- </dependency>
-
- <dependency>
- <groupId>aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- <version>1.5.3</version>
- </dependency>
第二步随便写一个类,然后类中写一个方法,我这里是写了一个除法运算:
- public class MathCalculator {
-
- public int div (int i, int j) {
- System.out.println("MathCalculator.div...");
- return i / j;
- }
- }
第三步写一个切面类:
- //该注解表示声明该类为一个切面类
- @Aspect
- public class LogAspects {
-
- //定义一个切点,表达式可以灵活运用,我这个表达式是表示MathCalculator类中所有的方法都进行切入
- @Pointcut("execution(public int com.example.demo.aop.MathCalculator.*(..))")
- public void pointCut () {}
-
- //方法执行开始之前
- @Before("pointCut()")
- public void logStart (JoinPoint joinPoint) {
- System.out.println("除法运行...参数:{"+ Arrays.asList(joinPoint.getArgs())+"}");
- }
-
- //方法执行开始之后
- @After("pointCut()")
- public void logEnd (JoinPoint joinPoint) {
- System.out.println("除法结束..." + joinPoint.getSignature().getName());
- }
-
- //当方法进行返回的时候,returning属性是指定方法参数中的result来接收返回参数,这样就可以修改返回参数
- @AfterReturning(value = "pointCut()", returning = "result")
- public void logReturn (JoinPoint joinPoint, Object result) {
- System.out.println("除法正常返回... 返回结果:{"+result+"}");
- }
-
- //当方法执行异常的时候,throwding是指定方法参数中的e来接收异常参数,可以查看发生的什么异常
- @AfterThrowing(value = "pointCut()", throwing = "e")
- public void logException (JoinPoint joinPoint, Exception e) {
- System.out.println("异常... 异常信息:{"+e+"}");
- }
-
- //环绕通知
- @Around("pointCut()")
- public Object logAround (ProceedingJoinPoint joinPoint) throws Throwable {
- //原方法执行之前会打印这个日志
- System.out.println("环绕通知... 开始");
- //执行原方法
- Object obj = joinPoint.proceed();
- //原方法执行结束,打印这行日志
- System.out.println("环绕通知... 结束");
- //返回方法返回参数
- return obj;
- }
- }
这里要注意一下AOP注解执行的先后顺序
- 环绕通知... 开始
- 除法运行...参数:{[1, 1]}
- MathCalculator.div...
- 环绕通知... 结束
- 除法结束...div
- 除法正常返回... 返回结果:{1}
-
运行的顺序是
1、@Around
2、@Before
3、原方法
4、@Around
5、@After
6、@AfterReturning
第四步,写一个配置类,记得一定要加@EnableAspectJAutoProxy注解
- //该配置类是为了将我们前2个类(切面类、被切面类)加入到Spring容器中
- @Configuration
- //启动AOP(一定要加这个注解,切记!!!)
- @EnableAspectJAutoProxy
- public class SpringOfAOPConfig {
-
- @Bean
- public MathCalculator mathCalculator () {
- return new MathCalculator();
- }
-
- @Bean
- public LogAspects logAspects () {
- return new LogAspects();
- }
-
- }
第五步,测试:
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class DemoApplicationTests {
-
- @Test
- public void contextLoads() {
- //根据配置类获取SPring容器
- AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringOfAOPConfig.class);
- //从容器中获取Bean
- MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
- //执行除法运算
- mathCalculator.div(1, 1);
- //关闭容器
- applicationContext.close();
- }
-
- }
正常结果:
- 2018-12-11 11:01:25.496 INFO 16364 --- [ main] com.example.demo.DemoApplicationTests : Started DemoApplicationTests in 3.455 seconds (JVM running for 4.972)
- 环绕通知... 开始
- 除法运行...参数:{[1, 1]}
- MathCalculator.div...
- 环绕通知... 结束
- 除法结束...div
- 除法正常返回... 返回结果:{1}
- 2018-12-11 11:01:25.807 INFO 16364 --- [ Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
异常结果:
- 2018-12-11 11:11:22.205 INFO 9628 --- [ main] com.example.demo.DemoApplicationTests : Started DemoApplicationTests in 3.532 seconds (JVM running for 4.559)
- 环绕通知... 开始
- 除法运行...参数:{[1, 0]}
- MathCalculator.div...
- 除法结束...div
- 异常... 异常信息:{java.lang.ArithmeticException: / by zero}
-
- java.lang.ArithmeticException: / by zero
看到没:
当发生异常的时候@Around的方法执行后切入没有进行,但是@After的方法却执行了,所以原方法发生异常后顺序就是
1、@Around
2、@Brfore
3、原方法
4、@After
5、@AfterThrowing