深入剖析Spring Boot / Spring 应用中可自定义的扩展点
概览
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";@Overridepublic boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {req.setAttribute(START, System.nanoTime());return true; // 继续处理}@Overridepublic 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 {@Overridepublic 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 {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/files/**").addResourceLocations("file:/var/data/files/");}@Overridepublic 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 {@Overridepublic boolean supportsParameter(MethodParameter param) {return param.hasParameterAnnotation(CurrentUser.class) && param.getParameterType().equals(User.class);}@Overridepublic 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> {@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return true; // 或更精确的条件}@Overridepublic 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));}@Overrideprotected boolean supports(Class<?> clazz) {return Person.class.isAssignableFrom(clazz);}@Overrideprotected Person readInternal(Class<? extends Person> clazz, HttpInputMessage input) throws IOException {String body = StreamUtils.copyToString(input.getBody(), StandardCharsets.UTF_8);// parse body -> Personreturn Person.parse(body);}@Overrideprotected 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 {@Overrideprotected 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);}@Overridepublic ServletInputStream getInputStream() {ByteArrayInputStream bais = new ByteArrayInputStream(cachedBody);return new DelegatingServletInputStream(bais);}@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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
来缓存请求体
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();}@Overridepublic InputStream getInputStream() throws IOException {return new ByteArrayInputStream(cachedBody); // 返回缓存的请求体}public String getBodyAsString() {return new String(cachedBody);}
}
1.2 创建 RequestLoggingFilter
过滤器,记录请求日志
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 {@Overrideprotected 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 中
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class WebConfig {@Beanpublic 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
注解
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
实现
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 {@Autowiredprivate UserService userService; // 用于获取当前用户的服务@Overridepublic boolean supportsParameter(MethodParameter parameter) {// 判断是否为 @CurrentUser 注解return parameter.hasParameterAnnotation(CurrentUser.class) && parameter.getParameterType().equals(User.class);}@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {// 从请求头中获取用户信息(这里假设从 JWT 或 session 获取)String userId = webRequest.getHeader("Authorization"); // 假设请求头有 Authorizationreturn userService.getUserById(userId);}
}
2.3 注册 HandlerMethodArgumentResolver
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 {@Autowiredprivate CurrentUserArgumentResolver currentUserArgumentResolver;@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {resolvers.add(currentUserArgumentResolver); // 注册自定义解析器}
}
2.4 使用 @CurrentUser
@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
类
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
实现
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> {@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {// 统一对所有返回类型生效return true;}@Overridepublic 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 使用统一响应包装
@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
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"));}@Overrideprotected boolean supports(Class<?> clazz) {return true; // 支持所有类型}@Overrideprotected Object readInternal(Class<? extends Object> clazz, org.springframework.http.HttpInputMessage inputMessage)throws IOException, org.springframework.http.converter.HttpMessageNotReadableException {// 自定义读取逻辑return new Object(); // 返回自定义对象}@Overrideprotected 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
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate CustomHttpMessageConverter customHttpMessageConverter;@Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(customHttpMessageConverter); // 注册自定义消息转换器}
}
5. BeanPostProcessor(基于注解生成代理)
需求: 在服务方法上使用 @Log
注解,自动生成代理,记录方法调用日志。
代码实现
5.1 创建 @Log
注解
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
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 {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {return bean; // 初始化前不做任何操作}@Overridepublic 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
注解
public interface MyService {@Logvoid doSomething();
}@Service
public class MyServiceImpl implements MyService {@Overridepublic void doSomething() {System.out.println("Doing something...");}
}