Spring Boot 接口和抽象类

1. ResponseBodyAdviceRequestBodyAdvice

可以对 @RequestBody 的参数进行各种处理,本质上都是 AOP

1. ResponseBodyAdvice

ResponseBodyAdvice 可以在注解 @ResponseBody 将返回值处理成相应格式之前操作返回值。用于对 response 数据的一些统一封装或者加密等操作, 再将结果返回给客户端, 可以实现该接口, 并增加注解 @RestControllerAdvice 来拦截处理, 其有 2 个方法

  • supports : 判断是否要执行 beforeBodyWrite 方法, true 为执行, false不执行. 通过该方法可以选择哪些类或那些方法的 response 要进行处理, 其他的不进行处理
  • beforeBodyWrite : 在 RequestBody 写入前进行处理, 比如统一封装

2. RequestBodyAdvice

给请求体参数做增强处理, 可以实现该接口, 并增加注解 @RestControllerAdvice 来拦截处理

  • supports: 判断是否要执行下面 3 个方法
  • beforeBodyRead: 在 RequestBody 读取前进行处理
  • afterBodyRead: 在 RequestBody 读取后进行处理
  • handleEmptyBody: 在 RequestBody 为空时处理

2. BeanPostProcessorBeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor

1. BeanPostProcessor

Bean 后置处理器,Bean 初始化前后,会回调 BeanPostProcessor 中定义的两个方法

1
2
3
4
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

2. BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor

前者实现它可以对 Bean 工厂中 Bean 定义(BeanDefintion)进行修改,它的执行时机是 BeanFactory 标准初始化之后,所有的 Bean 定义已经被加载,但标准 Bean 的实例还没被创建(不包括 BeanFactoryPostProcessor 类型)。

BeanDefinitionRegistryPostProcessor 继承自前者,所有的 Bean 定义即将被加载,但Bean的实例还没被创建时,也就是说,BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry 方法执行时机先于前者的 postProcessBeanFactory 方法。

3. 执行顺序

  1. BeanDefinitionRegistryPostProcessor
  2. BeanFactoryPostProcessor
  3. BeanPostProcessor

3. springboot 生命周期相关

1. 启动时执行

  • @PostConstruct : beans 初始化前执行
  • CommandLineRunner : beans初始化后执行,实现方法 run 方法,可以在类上使用 @Order(n) 定义多个并按顺序有小到大执行
  • ApplicationRunner : 类似 CommandLineRunner,只是实现方法 run 参数不一样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// CommandLineRunner
@Component
@Order(99)
public class CommandLineRunnerA implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("初始化:CommandLineRunnerA");
}
}

@Component
@Order(1)
public class CommandLineRunnerB implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("初始化:CommandLineRunnerB");
}
}

// ApplicationRunner
@Component
public class InitApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
System.out.println("初始化:InitApplicationRunner");
}
}

2. 结束前执行

  • DisposableBean : 实现 destroy 方法
  • @PreDestroy : 在 DisposableBean 之前执行
1
2
3
4
5
6
7
@Component
public class DisposableBeanImpl implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("销毁:DisposableBeanImpl.destroy");
}
}

4. RequestResponse 处理

HttpServletRequestWrapperHttpServletResponseWrapper 是 Servlet 规范中定义的包装器,用来扩展和增强请求和相应参数

1. HttpServletRequestWrapper

  • getParameterNames(): 获取 request 里所有的 name,返回 Enumeration 类型
  • getParameter(String name): 获取 name 对应的 value,如果有多个,返回第一个
  • getParameterValues(String name): 获取 name 对应的所有 value
  • getParameterMap(): 不可一个修改的 map,可以新建一个进行修改,最后返回时必须调用Collections.unmodifiableMap(Map<? extends K, ? extends V> m) 把 map 改成不可变
  • getInputStream(): 获取输入流,但只能读取一次,需要读取之后存储下来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
public ServletInputStream getInputStream() throws IOException {
String body = IOUtils.toString(super.getInputStream(), StandardCharsets.UTF_8);
final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}

@Override
public int available() throws IOException {
return body.length;
}

@Override
public boolean isFinished() {
return false;
}

@Override
public boolean isReady() {
return false;
}

@Override
public void setReadListener(ReadListener readListener) {

}
};
}

2. HttpServletResponseWrapper

  • getOutputStream(): 获取输出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}

@Override
public void setWriteListener(WriteListener listener) {

}

@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
};
}