深入剖析Spring Boot / Spring 应用中可自定义的扩展点

概览

  • Web 层:HandlerInterceptorWebMvcConfigurer / WebMvcConfigurationSupportHandlerMethodArgumentResolverHandlerMethodReturnValueHandlerControllerAdvice/@ExceptionHandlerResponseBodyAdviceViewResolverLocaleResolver、CORS 配置、Static Resource Handler。

  • Message conversion:HttpMessageConverterAbstractHttpMessageConverter)、MappingJackson2HttpMessageConverter 自定义 ObjectMapperConverter/Formatter

  • Servlet / Filter:OncePerRequestFilterFilterRegistrationBeanHttpServletRequestWrapperHttpServletResponseWrapperServletContextInitializer

  • Bean & 容器:BeanPostProcessorBeanFactoryPostProcessorBeanDefinitionRegistryPostProcessorApplicationContextInitializerApplicationListenerEnvironmentPostProcessor@Configuration + @Conditional 扩展。

  • AOP / 横切:自定义注解 + @AspectMethodInterceptor)、AdvisorProxyFactoryBean

  • 事务 / 安全:自定义 PlatformTransactionManager/TransactionInterceptor、Spring Security 的 filter chain (SecurityFilterChain) 与 OncePerRequestFilter 的结合点。

  • 嵌入式容器:WebServerFactoryCustomizer / ConfigurableServletWebServerFactoryTomcatContextCustomizerUndertowDeploymentInfoCustomizer

  • Actuator / 监控:HealthIndicatorInfoContributorMeterBinder、自定义端点(@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 内部有很多重要实现(例如 AutowiredAnnotationBeanPostProcessorConfigurationClassPostProcessor 等)。

示例:自动为带 @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. 事务拦截器

  • 通过 @TransactionalTransactionInterceptor 配合 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 添加、缓存控制、版本控制(ResourceUrlEncodingFilterVersionResourceResolver


九、注册 & 优先级 / Ordering 机制(如何能力协作)

  • Filters:通过 FilterRegistrationBean.setOrder(...)@Order 控制。Servlet Container 的 filter 最早,Spring 的 handler interceptor 在 MVC 层。

  • Interceptors:InterceptorRegistry 的顺序决定拦截链。

  • BeanPostProcessor:必须尽早注册(通常声明为 static @Bean 或在 spring.factories/自动配置中注册)。

  • AOP/Advisor:可通过 @OrderOrdered 接口定制优先级。

  • MessageConverters:extendMessageConverters 插入(推荐)而不是 configureMessageConverters(会替换默认列表),除非你要完全控制。


十、常见陷阱与最佳实践

  1. 不要轻易继承 WebMvcConfigurationSupport,会覆盖 Spring Boot 的自动配置。

  2. Filter 与 Interceptor 的职责分明:Filter 负责底层请求(例如安全、CORS),Interceptor 负责 MVC 层逻辑(例如权限检查基于 Handler)。

  3. 避免在 BeanPostProcessor 中去创建或依赖延迟创建大量 bean(可能触发循环依赖或性能问题)。

  4. 对请求 body 做缓存要注意大小(使用流处理或限制最大大小)。

  5. AOT/native 环境:某些依赖运行时反射的插件/注入在 native image 下需要额外配置(reflection metadata)。自定义注解处理器生成静态配置更安全。

  6. 顺序管理:复杂系统多个 filter/interceptor/advices 时,务必写清楚 order 并记录理由(例如日志 filter 要在 security filter 之前或之后执行)。

  7. 错误处理 :Global Exception Handler 要考虑 Spring Boot 的 ErrorController 行为与静态资源处理冲突场景。

  8. 性能:避免在 high-throughput 点做阻塞/同步 IO;对于密集调用点(如每个请求的复杂解析)考虑使用缓存或在请求入口做提前判定。


十一、精选完整示例(可复制的"真实样板")

下面给出 5 个经常直接可用的样板:

  1. OncePerRequestFilter + HttpServletRequestWrapper(请求日志 + 缓存 body)

  2. HandlerMethodArgumentResolver(@CurrentUser)

  3. ResponseBodyAdvice(统一响应包装)

  4. AbstractHttpMessageConverter(自定义 media-type)

  5. 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(统一响应包装)

需求: 所有的响应数据都加上统一的包装(比如 codemessagedata 字段)。

代码实现

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...");
    }
}
相关推荐
码熔burning5 小时前
Spring Security 深度学习(六): RESTful API 安全与 JWT
安全·spring·restful·springsecurity
爬虫程序猿5 小时前
利用 Java 爬虫获取淘宝商品 SKU 详细信息实战指南
java·开发语言·爬虫
茶本无香5 小时前
RequestContextFilter介绍
java·spring·filter·requestcontext
iナナ6 小时前
初识JVM
java·jvm
m0_570466416 小时前
代码随想录算法训练营第二十八天 | 买卖股票的最佳实际、跳跃游戏、K次取反后最大化的数组和
java·开发语言·算法
ST.J7 小时前
swing笔记
java·笔记
菩提树下的凡夫7 小时前
瑞芯微RV1126目标识别算法Yolov8的部署应用
java·算法·yolo
尚学教辅学习资料7 小时前
Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.1 Spring Boot自动配置
vue.js·spring boot·spring