前言
看了标题后,你应该能猜到我不是要从源码角度分析 SpringBoot 自动装配原理。再分析源码那也太没劲了,写文章很麻烦的,写一个很多人写过的文章更麻烦(但我依旧建议先了解原理,再找机会应用到项目中)【白嫖资料】
我想记录的其实是:我在项目中无意间使用了SpringBoot的自动装配,做了一个 SpringBoot 自动装配的实战案例。
先说一下这个“无意间”的事件发生背景吧!作为一个后端程序员,对于接口入参的字段校验那是家常便饭,所以对校验非空的注解常用 @NotNull,字段为空会抛出 MethodArgumentNotValidException 异常,就是下面这一长串。
{
"timestamp": "2021-07-02T02:12:29.868+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotNull.loginDTO.password",
"NotNull.password",
"NotNull.java.lang.String",
"NotNull"
],
"arguments": [
{
"codes": [
"loginDTO.password",
"password"
],
"arguments": null,
"defaultMessage": "password",
"code": "password"
}
],
"defaultMessage": "密码不能为空",
"objectName": "loginDTO",
"field": "password",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotNull"
}
],
"message": "Validation failed for object='loginDTO'. Error count: 1",
"path": "/v1/test/login"
}
但是我的固搭前端小伙伴只想要 @NotNull(message=“自定义异常”)里的 message 内容;所以我每次都会在项目中定义一个全局异常处理,一旦发生 MethodArgumentNotValidException 异常,就捕捉处理,如下面这样子的:
{
"code": 400,
"msg": "password:密码不能为空",
"data": 0
}
以前我每个项目都要写这个全局异常处理,烦得很!恰巧最近在搭建 maven 私服,我就想将这块功能写到我的 maven 私服中,以后只要在 pom 文件中依赖我的 maven,我都不用写了。
接下来就是我的实现步骤了,看我如何一步步“被逼”使用了 SpringBoot 的自动装配。
项目搭建发布
首先在 maven 项目中添加一个全局异常处理类 ValidParamExceptionHandler ,负责接口入参非空验证的异常处理。
@ControllerAdvice
public class ValidParamExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ApiResponse handlerMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
StringBuilder errorMessage = new StringBuilder(bindingResult.getFieldErrors().size() * 16);
for (int i = 0; i < bindingResult.getFieldErrors().size(); i++) {
if (i > 0) {
errorMessage.append(",");
}
FieldError fieldError = bindingResult.getFieldErrors().get(i);
errorMessage.append(fieldError.getField());
errorMessage.append(":");
errorMessage.append(fieldError.getDefaultMessage());
}
return new ApiResponse(400,errorMessage.toString(),0);
}
}
如果此时我直接打包发布并在新的项目中引入这个 maven 的依赖,你觉得新的项目中会做全局异常处理吗?我第一次就是原封不动的操作了一遍,结果就是不行!!!于是我在想,是因为 ValidParamExceptionHandler 类没有被 Spring 扫描到?那我加一个 @Component 注解不就可以了吗?但是当我打开 @ControllerAdvice 注解,我就知道我在想屁吃,因为 @ControllerAdvice 中已经包含了 @Component 注解。
最后我上网搜索解决方式,看到了如下解决方案,即在 resources 文件夹下面的 META-INF 新建一个spring.factories 文件,并写入如下内容【白嫖资料】
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xinmachong.exception.ValidParamExceptionHandler
第一行是固定的,第二行显然就是全局异常处理类的路径。
最后打包发布。
全局异常测试
写一个测试接口如下图所示:
其中 LoginDTO 是:
@Data
public class LoginDTO {
@NotNull(message = "账号不能为空")
private String account;
@NotNull(message = "密码不能为空")
private String password;
}
测试接口的过程和结果如下图所示:
入参只有一个 account,请求后看到返回信息为:“password:密码不能为空”。当时的内心就是两个字—握草;因为这个全局异常处理在新项目中竟然生效了。
总结
做的时候没有多想原理,但实现之后我肯定要弄明白的啊,所有人都知道了,关键点就在 spring.factories;但是为啥 spring.factories 这个文件这么屌?突然想起来之前看的 SpringBoot 自动装配实现的源码中好像有提到这个,通过查证,在源码的最后找到了 spring.factories。
一瞬间我突然理解了,原来这个就是通过 SpringBoot 自动装配实现了全局异常处理类的生效!豁然开朗。
最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。
可以的话 请给我一个三连支持一下哟???【白嫖资料】