Spring Boot 入门之路(11)--- 在 Spring Boot 中使用 AOP - Go语言中文社区

Spring Boot 入门之路(11)--- 在 Spring Boot 中使用 AOP


本文注重讲解在 Spring Boot 中如何使用 AOP,而不会过多纠结于 AOP 的基础知识,若对 AOP 还不了解的同学可以先看我之前写的这篇文章 Spring 中的 AOP 详解

1 引入依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

在我们引入 AOP 依赖包之后,并不需要去做其他配置,因为 Spring Boot 已经帮我们配置好了。

2 创建一个简单的控制器

package edu.szu.test.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
	
	@RequestMapping("/hello")
	public String hello() {
		return "hello";
	}
	
	@RequestMapping("/end")
	public String end() {
		return "end";
	}
}

3 创建切面类

这里注意,要想一个类成为切面类,必须添加注解 @Component 和 @Aspect 。

package edu.szu.test.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogAspect {
	
	private Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	// 配置切点
	@Pointcut("execution(* edu.szu.test.controller.*.*(..))")
	private void point(){};
	
	// 前置通知
	@Before("point()")
	public void doBefore(JoinPoint joinPoint){
		//获取通知的签名
		Signature signature = joinPoint.getSignature();
		//获取代理方法
		String name = signature.getName();
		//获取代理类
		String className = signature.getDeclaringTypeName();
		logger.info("这是一个前置通知:" + "代理方法为" + name + " 代理类为" + className);
	}
}

我们这里定义的切点为 edu.szu.test.controller 下的所有函数。

打开浏览器,先输入 http://localhost:8080/hello,再输入 http://localhost:8080/end,发现结果如下
在这里插入图片描述

4 其他通知

package edu.szu.test.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogAspect {
	
	private Logger logger = LoggerFactory.getLogger(LogAspect.class);
	
	// 配置切点
	@Pointcut("execution(* edu.szu.test.controller.*.*(..))")
	private void point(){};
	
	// 前置通知
	@Before("point()")
	public void doBefore(JoinPoint joinPoint){
		//获取通知的签名
		Signature signature = joinPoint.getSignature();
		//获取代理方法
		String name = signature.getName();
		//获取代理类
		String className = signature.getDeclaringTypeName();
		logger.info("这是一个前置通知:" + "代理方法为" + name + " 代理类为" + className);
	}
	
	// 环绕通知
	@Around("point()")
	public Object around(ProceedingJoinPoint proceedingJoinPoint) {
		//获取方法名
		String name = proceedingJoinPoint.getSignature().getName();
		logger.info("这是一个环绕通知:" + "代理方法为" + name);
		try {  
	        Object obj = proceedingJoinPoint.proceed();  
	        logger.info("这是一个环绕通知:方法已被执行");
	        return obj;  
	    } catch (Throwable throwable) {  
	        throwable.printStackTrace();
	        logger.error("这是一个环绕通知:出错了!");
	    }  
	    return null;  
	}
	
	// 后置通知
	@After("point()")
	public void after(JoinPoint joinPoint) {
		//获取通知的签名
		Signature signature = joinPoint.getSignature();
		//获取代理方法
		String name = signature.getName();
		//获取代理类
		String className = signature.getDeclaringTypeName();
		logger.info("这是一个后置通知:" + "代理方法为" + name + " 代理类为" + className);
	}
	
	// 后置返回通知,其中 keys 为返回值的信息
	@AfterReturning(value = "point()",returning = "keys")  
	public void afterReturning(JoinPoint joinPoint,Object keys){  
	    logger.info("这是一个后置返回通知:返回值为" + keys.toString());  
	}  
	
	// 后置异常通知
	@AfterThrowing(value = "point()",throwing = "exception")
	public void afterThrowing(JoinPoint joinPoint,Throwable exception){  
		//获取通知的签名
		Signature signature = joinPoint.getSignature();
		//获取代理方法
		String name = signature.getName();
		logger.error("这是一个后置异常通知:" + "代理方法为" + name);
	    logger.error("这是一个后置异常通知:" + exception); 
	}  
}

还是来谈谈环绕通知吧,这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或者直接返回它自己的返回值或抛出异常来结束执行,甚至可以决定执行时是否需要替换方法参数以及执行完毕是否需要替换返回值。调用 ProceedingJoinPoint 的 proceed() 方法会导致后台的连接点方法执行。

5 测试

先来测试正常的控制器

	@RequestMapping("/hello")
	public String hello() {
		//int i = 1/0;
		return "hello";
	}

结果如下
在这里插入图片描述
再故意在控制器中抛出异常

	@RequestMapping("/hello")
	public String hello() {
		int i = 1/0;
		return "hello";
	}

结果如下
在这里插入图片描述
在这里插入图片描述

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/geffin/article/details/100534556
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢