概览
-
Web 层:
HandlerInterceptor
、WebMvcConfigurer
/WebMvcConfigurationSupport
、HandlerMethodArgumentResolver
、HandlerMethodReturnValueHandler
、ControllerAdvice
/@ExceptionHandler
、ResponseBodyAdvice
、ViewResolver
、LocaleResolver
、CORS 配置、Static Resource Handler。 -
Message conversion:
HttpMessageConverter
(AbstractHttpMessageConverter
)、MappingJackson2HttpMessageConverter
自定义ObjectMapper
、Converter
/Formatter
。 -
Servlet / Filter:
OncePerRequestFilter
、FilterRegistrationBean
、HttpServletRequestWrapper
、HttpServletResponseWrapper
、ServletContextInitializer
。 -
Bean & 容器:
BeanPostProcessor
、BeanFactoryPostProcessor
、BeanDefinitionRegistryPostProcessor
、ApplicationContextInitializer
、ApplicationListener
、EnvironmentPostProcessor
、@Configuration
+@Conditional
扩展。 -
AOP / 横切:自定义注解 +
@Aspect
(MethodInterceptor
)、Advisor
、ProxyFactoryBean
。 -
事务 / 安全:自定义
PlatformTransactionManager
/TransactionInterceptor
、Spring Security 的 filter chain (SecurityFilterChain
) 与OncePerRequestFilter
的结合点。 -
嵌入式容器:
WebServerFactoryCustomizer
/ConfigurableServletWebServerFactory
、TomcatContextCustomizer
、UndertowDeploymentInfoCustomizer
。 -
Actuator / 监控:
HealthIndicator
、InfoContributor
、MeterBinder
、自定义端点(@Endpoint
)。 -
错误处理 / 全局响应:
ErrorController
/ErrorAttributes
/@ControllerAdvice
、自定义BasicErrorController
覆盖。 -
其他:任务执行器 (
TaskExecutor
/TaskScheduler
)、缓存(CacheManager
自定义)、消息(MessageConverter
)、Multipart(MultipartResolver
)等。
一、Web 层扩展(最常用、影响最大)
1. HandlerInterceptor(HandlerInterceptor / HandlerInterceptorAdapter)
作用 :在 Spring MVC Handler 执行前/执行后/完成后插入逻辑(类似 AOP 但作用于请求处理链)。
场景:鉴权/鉴权失败跳转、请求链日志、请求限流、统计耗时、请求上下文初始化(把 token -> user 放入 ThreadLocal)等。
示例:记录请求耗时并在 header 返回
public class TimingInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(TimingInterceptor.class);
private static final String START = "startTime";
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
req.setAttribute(START, System.nanoTime());
return true; // 继续处理
}
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
Long start = (Long) req.getAttribute(START);
if (start != null) {
long ms = (System.nanoTime() - start) / 1_000_000;
res.addHeader("X-Processing-Time-ms", Long.toString(ms));
log.info("{} {} took {} ms", req.getMethod(), req.getRequestURI(), ms);
}
}
}
注册(使用 WebMvcConfigurer
):
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TimingInterceptor()).addPathPatterns("/api/**");
}
}
注意:
-
HandlerInterceptor
在 Spring MVC 层;如果你想在 Filter 之前就生效,需用 Servlet Filter。 -
顺序:可以通过
registry.addInterceptor(...).order(int)
(Spring Boot 2.6+)或使用Ordered
接口控制。
2. WebMvcConfigurer vs WebMvcConfigurationSupport
区别:
-
WebMvcConfigurer
:通过实现接口的方法"补充"Spring Boot 的自动化配置(推荐)。 -
WebMvcConfigurationSupport
:继承并覆盖 Spring MVC 的核心配置,如果你直接继承/声明它,Spring Boot 的很多自动配置(例如WebMvcAutoConfiguration
)不会生效------等于"接管"全部 MVC 配置(除非你手动恢复那些 bean)。
建议 :大多数场景使用 WebMvcConfigurer
;只有在需要完全定制、替换 Spring MVC 默认行为(并清楚代价)时才继承 WebMvcConfigurationSupport
。
示例(使用 WebMvcConfigurer
配置静态资源与消息转换):
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/files/**")
.addResourceLocations("file:/var/data/files/");
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new MyCustomMessageConverter());
}
}
坑 :误用 WebMvcConfigurationSupport
导致 @EnableAutoConfiguration
的静态资源、jackson auto-config 等失效。
3. HandlerMethodArgumentResolver(方法参数解析器)
作用 :自定义 Controller 方法中的参数注入(例如 @CurrentUser User user
从 token解析后注入)。
场景:把 token 解出来并提供给 Controller,或者把通用的请求上下文/分页参数自动解析为对象。
示例:
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {}
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter param) {
return param.hasParameterAnnotation(CurrentUser.class) && param.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter param, ModelAndViewContainer mav, NativeWebRequest request, WebDataBinderFactory factory) {
String token = request.getHeader("Authorization");
return TokenService.parseUser(token); // 你的逻辑
}
}
注册:
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CurrentUserArgumentResolver());
}
4. HandlerMethodReturnValueHandler / ResponseBodyAdvice(返回值处理 / 响应增强)
-
HandlerMethodReturnValueHandler:在 controller 返回之前自定义如何写入 response(更底层)。
-
ResponseBodyAdvice :针对
@ResponseBody
/@RestController
的返回体统一拦截/包装(最常用)。
示例(ResponseBodyAdvice):给统一 API 格式包一层 {"code":0,"data":...}
:
@ControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true; // 或更精确的条件
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof ApiResult) return body;
return ApiResult.success(body);
}
}
5. ControllerAdvice / 全局异常处理
作用 :集中处理 Controller 中抛出的异常并统一响应。常用类:@ControllerAdvice
+ @ExceptionHandler
或继承 ResponseEntityExceptionHandler
。
示例:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiError> handle(BusinessException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiError(ex.getCode(), ex.getMessage()));
}
}
二、消息转换
1. 自定义 HttpMessageConverter
作用 :控制 Controller(@RequestBody
/@ResponseBody
)如何从/向 HTTP body 进行序列化与反序列化。Spring 提供 AbstractHttpMessageConverter<T>
便于实现。
示例:支持自定义 media-type application/x-person
的 converter(演示)
public class PersonMessageConverter extends AbstractHttpMessageConverter<Person> {
public PersonMessageConverter() {
super(new MediaType("application", "x-person", StandardCharsets.UTF_8));
}
@Override
protected boolean supports(Class<?> clazz) {
return Person.class.isAssignableFrom(clazz);
}
@Override
protected Person readInternal(Class<? extends Person> clazz, HttpInputMessage input) throws IOException {
String body = StreamUtils.copyToString(input.getBody(), StandardCharsets.UTF_8);
// parse body -> Person
return Person.parse(body);
}
@Override
protected void writeInternal(Person person, HttpOutputMessage output) throws IOException {
output.getBody().write(person.toCustomFormat().getBytes(StandardCharsets.UTF_8));
}
}
注册到 MVC:
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new PersonMessageConverter());
}
场景:需要支持二进制协议、自定义文本协议、兼容遗留系统格式等。
2. 定制 Jackson / ObjectMapper
-
通过
Jackson2ObjectMapperBuilderCustomizer
或在 Spring Boot 中配置JacksonAutoConfiguration
提供的ObjectMapper
Bean 修改规则(日期格式、忽略空字段、自定义序列化器/反序列化器)。 -
也可通过
MappingJackson2HttpMessageConverter
的替换或添加自定义JsonSerializer
。
示例(自定义 ObjectMapper):
@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.modules(new JavaTimeModule());
}
三、Filter / Servlet API 扩展(底层请求拦截)
1. OncePerRequestFilter(Spring 提供的便利 Filter)
作用 :确保过滤器在一次请求生命周期中仅执行一次(适合 Spring Security、日志、Tracing)。
使用场景:做 request scope context、trace id 注入、请求体缓存等。
示例(请求 ID):
public class RequestIdFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws ServletException, IOException {
String id = UUID.randomUUID().toString();
MDC.put("requestId", id);
try {
res.addHeader("X-Request-Id", id);
chain.doFilter(req, res);
} finally {
MDC.remove("requestId");
}
}
}
注册(Spring Boot):
@Bean
public FilterRegistrationBean<RequestIdFilter> requestIdFilter() {
FilterRegistrationBean<RequestIdFilter> fr = new FilterRegistrationBean<>(new RequestIdFilter());
fr.setOrder(Ordered.HIGHEST_PRECEDENCE);
fr.addUrlPatterns("/api/*");
return fr;
}
2. HttpServletRequestWrapper / HttpServletResponseWrapper
作用:包装请求/响应以改变输入(比如读取多次 request body、修改 header、对参数进行清洗、实现 gzip 响应等)。
示例(读取请求体多次:缓存 body)简化:
public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
private byte[] cachedBody;
public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
InputStream is = request.getInputStream();
this.cachedBody = StreamUtils.copyToByteArray(is);
}
@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream bais = new ByteArrayInputStream(cachedBody);
return new DelegatingServletInputStream(bais);
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));
}
}
常用于:验证签名(先缓存 request body 做签名校验,再传给后续处理),或做 body 修改(对敏感字段脱敏)。
注意:避免缓存超大 body 导致 OOM;对大文件要使用流式处理或限制。
四、Bean & 容器级扩展(影响整个应用)
1. BeanPostProcessor(Bean 实例化前后拦截)
作用 :可以在 bean 初始化前后做修改(AOP 代理注入、注解处理、字段注入替代等)。Spring Boot 内部有很多重要实现(例如 AutowiredAnnotationBeanPostProcessor
、ConfigurationClassPostProcessor
等)。
示例:自动为带 @Loggable
注解的 bean 生成代理记录方法调用:
public class LoggableBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean.getClass().isAnnotationPresent(Loggable.class)) {
return ProxyFactory.getProxy(bean.getClass(), (MethodInterceptor) invocation -> {
long s = System.nanoTime();
try { return invocation.proceed(); } finally {
System.out.println(invocation.getMethod().getName() + " took " + (System.nanoTime()-s)/1_000_000 + "ms");
}
});
}
return bean;
}
}
注册:
@Bean
public static LoggableBeanPostProcessor loggableBeanPostProcessor() {
return new LoggableBeanPostProcessor();
}
注意 :BeanPostProcessor
必须是 static
@Bean
(或提前注册),以确保其能在其它 bean 初始化前起作用;且不要在 post-process 中创建依赖链导致循环依赖。
2. BeanFactoryPostProcessor / BeanDefinitionRegistryPostProcessor
作用:在 Spring 创建 bean 定义后、实例化前修改 bean 定义(例如动态注册 bean、替换 ClassName、修改构造参数)。适用于框架级扩展或动态插件注册。
示例:动态注册某个 bean:
public class DynamicRegistrar implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
RootBeanDefinition bd = new RootBeanDefinition(MyDynamicService.class);
registry.registerBeanDefinition("myDynamicService", bd);
}
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}
}
3. ApplicationContextInitializer / ApplicationListener / EnvironmentPostProcessor
-
ApplicationContextInitializer
:在ApplicationContext
refresh 前修改上下文(比如注册 property source)。 -
EnvironmentPostProcessor
:在 Spring Boot 启动、Environment 准备阶段调整Environment
(常用于外部配置的加载)。 -
ApplicationListener<ApplicationReadyEvent>
:监听启动事件做初始化工作(例如预加载缓存)。
示例(EnvironmentPostProcessor,在 META-INF/spring.factories
中注册):
public class MyEnvProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
env.getPropertySources().addFirst(new MapPropertySource("my", Map.of("my.prop", "value")));
}
}
注意 :EnvironmentPostProcessor
运行非常早,bean 尚未创建;适合配置层面修改,不适合访问 bean。
五、AOP / 事务 / 安全 扩展
1. 自定义注解 + Aspect(切面)
场景:实现横切逻辑(记录、限流、幂等、重试、指标等)。
示例(@Timed 注解 + Aspect):
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Timed {}
@Aspect
@Component
public class TimedAspect {
@Around("@annotation(Timed)")
public Object around(ProceedingJoinPoint p) throws Throwable {
long s = System.nanoTime();
try { return p.proceed(); } finally {
long ms = (System.nanoTime()-s)/1_000_000;
System.out.println("timed: " + ms + "ms");
}
}
}
2. 事务拦截器
-
通过
@Transactional
或TransactionInterceptor
配合Advisor
自定义事务切面行为(例如定制回滚规则、超时、事务传播)。 -
也可以在
PlatformTransactionManager
级别扩展(实现自定义资源管理器)。
3. Spring Security 扩展点
-
用
SecurityFilterChain
(最新推荐)来自定义安全链;或写OncePerRequestFilter
插入到 filter chain 内做自定义认证(例如 JWT 验证)。 -
方法级安全通过
@PreAuthorize
/MethodSecurityExpressionHandler
扩展 expression 的能力。
六、嵌入式服务器 & 容器自定义
1. WebServerFactoryCustomizer / ConfigurableServletWebServerFactory
作用:定制嵌入式容器(Tomcat/Undertow/Jetty)行为:端口、协议、线程池、ssl、context path、access log、session config 等。
示例(Tomcat 自定义):
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerFactoryCustomizer() {
return factory -> {
if (factory instanceof TomcatServletWebServerFactory tomcat) {
tomcat.addContextCustomizers(context -> {
context.setSessionTimeout(30); // minutes
});
}
};
}
2. TomcatContextCustomizer / UndertowDeploymentInfoCustomizer
用于更细粒度定制(Valve、管理器、限制等),适合性能/安全/日志集成。
七、Actuator / 监控 / 运行时扩展
1. HealthIndicator / InfoContributor / MeterBinder
场景:将自定义健康检查、信息、度量注入到 Actuator。
示例(HealthIndicator):
@Component
public class MyServiceHealthIndicator implements HealthIndicator {
public Health health() {
boolean ok = myService.check();
return ok ? Health.up().build() : Health.down().withDetail("reason", "fail").build();
}
}
2. 自定义端点(@Endpoint)
可以创建自定义 actuator endpoint (@Endpoint
+ @ReadOperation
) 用于暴露业务诊断数据。
八、错误处理 / 全局响应与静态资源
1. ErrorController / ErrorAttributes
用途 :自定义错误页面/响应格式或注入额外错误信息。可覆盖 BasicErrorController
或提供自定义 ErrorAttributes
。
示例(简单 ErrorAttributes):
@Component
public class AppErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String,Object> attrs = super.getErrorAttributes(webRequest, options);
attrs.put("requestId", MDC.get("requestId"));
return attrs;
}
}
2. 静态资源处理
通过 ResourceHandlerRegistry
添加、缓存控制、版本控制(ResourceUrlEncodingFilter
、VersionResourceResolver
)
九、注册 & 优先级 / Ordering 机制(如何能力协作)
-
Filters:通过
FilterRegistrationBean.setOrder(...)
或@Order
控制。Servlet Container 的 filter 最早,Spring 的 handler interceptor 在 MVC 层。 -
Interceptors:
InterceptorRegistry
的顺序决定拦截链。 -
BeanPostProcessor:必须尽早注册(通常声明为
static @Bean
或在spring.factories
/自动配置中注册)。 -
AOP/Advisor:可通过
@Order
或Ordered
接口定制优先级。 -
MessageConverters:
extendMessageConverters
插入(推荐)而不是configureMessageConverters
(会替换默认列表),除非你要完全控制。
十、常见陷阱与最佳实践
-
不要轻易继承
WebMvcConfigurationSupport
,会覆盖 Spring Boot 的自动配置。 -
Filter 与 Interceptor 的职责分明:Filter 负责底层请求(例如安全、CORS),Interceptor 负责 MVC 层逻辑(例如权限检查基于 Handler)。
-
避免在 BeanPostProcessor 中去创建或依赖延迟创建大量 bean(可能触发循环依赖或性能问题)。
-
对请求 body 做缓存要注意大小(使用流处理或限制最大大小)。
-
AOT/native 环境:某些依赖运行时反射的插件/注入在 native image 下需要额外配置(reflection metadata)。自定义注解处理器生成静态配置更安全。
-
顺序管理:复杂系统多个 filter/interceptor/advices 时,务必写清楚 order 并记录理由(例如日志 filter 要在 security filter 之前或之后执行)。
-
错误处理 :Global Exception Handler 要考虑 Spring Boot 的
ErrorController
行为与静态资源处理冲突场景。 -
性能:避免在 high-throughput 点做阻塞/同步 IO;对于密集调用点(如每个请求的复杂解析)考虑使用缓存或在请求入口做提前判定。
十一、精选完整示例(可复制的"真实样板")
下面给出 5 个经常直接可用的样板:
-
OncePerRequestFilter
+HttpServletRequestWrapper
(请求日志 + 缓存 body) -
HandlerMethodArgumentResolver
(@CurrentUser) -
ResponseBodyAdvice
(统一响应包装) -
AbstractHttpMessageConverter
(自定义 media-type) -
BeanPostProcessor
(基于注解生成代理)
1. OncePerRequestFilter + HttpServletRequestWrapper(请求日志 + 缓存 body)
需求: 我们希望在每次请求时记录请求体日志,并允许后续操作(如处理请求体)时能够多次读取请求体。
代码实现
1.1 创建 CachingRequestWrapper
来缓存请求体
java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class CachingRequestWrapper extends HttpServletRequestWrapper {
private byte[] cachedBody;
public CachingRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
// 缓存请求体
this.cachedBody = request.getInputStream().readAllBytes();
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(cachedBody); // 返回缓存的请求体
}
public String getBodyAsString() {
return new String(cachedBody);
}
}
1.2 创建 RequestLoggingFilter
过滤器,记录请求日志
java
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/api/*")
public class RequestLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// 使用 CachingRequestWrapper 包装请求
CachingRequestWrapper wrappedRequest = new CachingRequestWrapper(request);
// 记录请求体日志
String requestBody = wrappedRequest.getBodyAsString();
log.info("Request Body: " + requestBody);
// 继续执行请求处理
filterChain.doFilter(wrappedRequest, response);
}
}
1.3 注册 RequestLoggingFilter
到 Spring Boot 中
java
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<RequestLoggingFilter> loggingFilter() {
FilterRegistrationBean<RequestLoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new RequestLoggingFilter());
registrationBean.addUrlPatterns("/api/*"); // 只拦截 "/api/*" 路径的请求
return registrationBean;
}
}
2. HandlerMethodArgumentResolver(@CurrentUser)
需求: 自定义注解 @CurrentUser
,自动注入当前登录用户信息。
代码实现
2.1 创建 @CurrentUser
注解
java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}
2.2 创建 CurrentUserArgumentResolver
实现
java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.stereotype.Component;
@Component
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private UserService userService; // 用于获取当前用户的服务
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 判断是否为 @CurrentUser 注解
return parameter.hasParameterAnnotation(CurrentUser.class) && parameter.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 从请求头中获取用户信息(这里假设从 JWT 或 session 获取)
String userId = webRequest.getHeader("Authorization"); // 假设请求头有 Authorization
return userService.getUserById(userId);
}
}
2.3 注册 HandlerMethodArgumentResolver
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private CurrentUserArgumentResolver currentUserArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(currentUserArgumentResolver); // 注册自定义解析器
}
}
2.4 使用 @CurrentUser
java
@RestController
public class UserController {
@GetMapping("/user")
public String getUserInfo(@CurrentUser User user) {
return "User Info: " + user.getName();
}
}
3. ResponseBodyAdvice(统一响应包装)
需求: 所有的响应数据都加上统一的包装(比如 code
、message
和 data
字段)。
代码实现
3.1 创建 ResponseWrapper
类
java
public class ResponseWrapper<T> {
private int code;
private String message;
private T data;
public ResponseWrapper(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
// Getters and Setters
}
3.2 创建 ResponseBodyAdvice
实现
java
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.core.MethodParameter;
@Component
public class ResponseWrapperAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// 统一对所有返回类型生效
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
org.springframework.http.server.ServerHttpRequest request,
org.springframework.http.server.ServerHttpResponse response) {
if (body instanceof ResponseWrapper) {
return body; // 如果已经是包装过的响应,直接返回
}
return new ResponseWrapper<>(200, "Success", body); // 统一包装
}
}
3.3 使用统一响应包装
java
@RestController
public class UserController {
@GetMapping("/user")
public ResponseWrapper<User> getUser() {
User user = new User("John", 30);
return new ResponseWrapper<>(200, "Success", user);
}
}
4. AbstractHttpMessageConverter(自定义 media-type)
需求: 支持自定义的 media-type
(例如 application/custom+json
)。
代码实现
4.1 创建自定义 HttpMessageConverter
java
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class CustomHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
public CustomHttpMessageConverter() {
super(new MediaType("application", "custom+json"));
}
@Override
protected boolean supports(Class<?> clazz) {
return true; // 支持所有类型
}
@Override
protected Object readInternal(Class<? extends Object> clazz, org.springframework.http.HttpInputMessage inputMessage)
throws IOException, org.springframework.http.converter.HttpMessageNotReadableException {
// 自定义读取逻辑
return new Object(); // 返回自定义对象
}
@Override
protected void writeInternal(Object object, org.springframework.http.HttpOutputMessage outputMessage)
throws IOException, org.springframework.http.converter.HttpMessageNotWritableException {
// 自定义写入逻辑
outputMessage.getBody().write(object.toString().getBytes());
}
}
4.2 注册 CustomHttpMessageConverter
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private CustomHttpMessageConverter customHttpMessageConverter;
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(customHttpMessageConverter); // 注册自定义消息转换器
}
}
5. BeanPostProcessor(基于注解生成代理)
需求: 在服务方法上使用 @Log
注解,自动生成代理,记录方法调用日志。
代码实现
5.1 创建 @Log
注解
java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
}
5.2 创建 LogBeanPostProcessor
java
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@Component
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean; // 初始化前不做任何操作
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof MyService) {
return Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(proxy, method, args) -> {
if (method.isAnnotationPresent(Log.class)) {
System.out.println("Method " + method.getName() + " is called");
}
return method.invoke(bean, args);
});
}
return bean;
}
}
5.3 使用 @Log
注解
java
public interface MyService {
@Log
void doSomething();
}
@Service
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("Doing something...");
}
}