什么是 Spring AOP ?
在介绍 Spring AOP 之前,⾸先要了解⼀下什么是 AOP?
AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的 集中处理。⽐如⽤户登录权限的效验,没学 AOP 之前,我们所有需要判断⽤户登录的⻚⾯(中 的⽅法),都要各⾃实现或调⽤⽤户验证的⽅法,然⽽有了 AOP 之后,我们只需要在某⼀处配 置⼀下,所有需要判断⽤户登录⻚⾯(中的⽅法)就全部可以实现⽤户登录验证了,不再需要每 个⽅法中都写相同的⽤户登录验证了。
AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和 IoC 与 DI 类似。
AOP 相关概念:
1. 切面(类)
切面是一个模块化单元,它封装了与横切关注点相关的行为。通俗来说就是某一方面的具体内容,比如用户的登录验证就是一个切面。
2.切点
切点是拦截规则,定义了在应用程序中哪些方法将被拦截并应用通知。
3. 通知
方法被拦截后具体要执行的动作。
4. 连接点
所有可能触发切点的点就是连接点,可以是方法调用、方法执行、异常处理等。
Spring AOP 的使用:
1. 添加依赖:
注意添加SpringBootAOP:
2.定义切面
3.切点
4.通知
5.连接点
运行结果:
未配置拦截规则类下方法的运行结果:
环绕通知:
拦截规则的语法(修饰符可以省略):
Spring AOP的实现原理:
两种实现方式:
1.JDK 动态代理:
要求:被代理类必须实现接口;
技术:反射
特点:创建时慢,运行时快。
2.CGLIB
被代理类可以不实现接⼝,是通过继承被代理类,在运⾏时动态的⽣成代理类对象。
特点:创建快,运行稍慢,可以代理所有的方法。
Spring Boot 统一功能处理
1. 用户登录权限校验
被拦截效果:
拦截器交互过程:
2.统一异常处理
通过这两个注解实现对异常的检测,返回自定义的类型数据。
第一个注解只能扫描含有controller注解的类,如果要扫描其他注解的类,可以通过 @ControllerAdvice(basePackages = "com.example.components")来标记要扫描的路径。
第二个注解标记了要处理的异常类型,具体的异常处理方法和返回值,方法名可以自行定义。
3.统一格式的数据返回
在业务代码将数据返回给前端时对数据进行加工后再返回给前端:
测试代码:
运行结果:
但是,上述统一返回结果存在问题,当返回数据为String时会报错,解决办法及引起错误原因如下:
错误类型:
原因及解决办法:
返回执行流程:
1.方法返回的是String
2.统一数据返回之前处理->String Convert HashMap
3.将HashMap_转换成application/ json字符串给前端(接口) 问题出在这一步
解决方法:
1.在返回数据之前,单独处理String类型
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
/**
* 是否执行beforeBodyWrite 方法,返回true=执行
* @param returnType
* @param converterType
* @return
*/
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
/**
* 返回数据之前进行重写
* @param body 原始数据
* @param returnType
* @param selectedContentType
* @param selectedConverterType
* @param request
* @param response
* @return
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if(body instanceof HashMap){
return body;
}
HashMap<String,Object> result = new HashMap<>();
result.put("code",200);
result.put("msg","");
result.put("data",body);
if(body instanceof String){
//当原始数据是字符串时需要单独处理,将其转换为json字符串
try {
return objectMapper.writeValueAsString(result);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
return result;
}
}
2. 将StringHttpMessageConverter 去掉
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
}
}
Spring 事务
1. 编程式事务
运行结果:
2. 声明式事务
该注解的参数说明:
事务的隔离级别:
注意事项:当事务发生异常,并将可能发生异常的代码加上try_catch后,又可能导致事务无法正常回滚:
解决办法:
1.将异常抛出去,让框架感知到异常,如果框架感受到异常后,框架就会自动回滚事务。
2.手动回滚事务
transactional 原理:
3.事务的传播机制
事务的传播机制解决的是一个事务在多个方法中传递的问题:
事务的传播机制有哪些?
分类:
示例:
运行结果:
数据库中没有添加任何数据,说明进行了事务的回滚。