Truman
Posted on
WEB MVC的一些基础配置
先上代码
@Configuration@ConditionalOnClass(org.springframework.web.servlet.config.annotation.WebMvcConfigurer.class)public class DefaultWebMvcConfig implements WebMvcConfigurer { // 注入用于处理JSON转换的消息转换器 @Autowired private MappingJackson2HttpMessageConverter jackson2HttpMessageConverter; // 注入自定义的拦截器注册器,允许在运行时动态添加拦截器 @Autowired private ObjectProvider<InterceptorRegistryCustomizer> interceptorRegistryCustomizers; // 配置消息转换器列表 @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { // 添加字节数组消息转换器,处理字节数组类型的请求和响应 converters.add(new ByteArrayHttpMessageConverter()); // 添加字符串消息转换器,处理字符串类型的请求和响应 converters.add(new StringHttpMessageConverter()); // 添加资源消息转换器,处理文件资源类型的请求和响应 converters.add(new ResourceHttpMessageConverter()); // 添加表单消息转换器,处理表单类型的数据 converters.add(new AllEncompassingFormHttpMessageConverter()); // 添加Jackson消息转换器,处理JSON类型的请求和响应 converters.add(jackson2HttpMessageConverter); } // 创建并配置Jackson消息转换器Bean @Bean public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper mapper = new ObjectMapper(); // 配置ObjectMapper,忽略未知属性,设置日期格式和时区,指定命名策略 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.setDateFormat(new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN)); mapper.setTimeZone(TimeZone.getTimeZone("GMT+8")); mapper.setPropertyNamingStrategy(new SpeedNamingStrategy()); // 将配置后的ObjectMapper设置到消息转换器中 converter.setObjectMapper(mapper); return converter; } /** * 设置静态资源文件目录 * * @param registry 资源处理注册器 */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations("classpath:/resources/") // 设置资源目录为resources .addResourceLocations("classpath:/static/") // 设置资源目录为static .addResourceLocations("classpath:/META-INF/resources/") // 设置资源目录为META-INF/resources .addResourceLocations("classpath:/public/"); // 设置资源目录为public } /** * 添加自定义的参数解析器,用于解析特定的参数(如Token) * * @param argumentResolvers 参数解析器列表 */ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new RequestContextArgumentResolver()); // 添加自定义的参数解析器 } /** * 添加自定义拦截器 * * @param registry 拦截器注册器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 通过自定义的拦截器注册器动态添加拦截器 for (InterceptorRegistryCustomizer interceptorRegistryCustomizer : interceptorRegistryCustomizers) { interceptorRegistryCustomizer.custom(registry); } } @Configuration @ConditionalOnClass({RedisTemplate.class, InterceptorRegistry.class}) @EnableConfigurationProperties(ApiControlProperties.class) static class InspectConfiguration { // 配置ApiManager Bean,负责管理API统计数据 @Bean public ApiManager handlerMethodRedisRegistry( RedisTemplate<String, Object> redisTemplate, RequestMappingHandlerMapping requestMappingHandlerMapping) { return new ApiManager(redisTemplate, requestMappingHandlerMapping); } // 配置ApiControlInterceptor的自定义拦截器注册器,添加拦截器到注册器 @Bean InterceptorRegistryCustomizer apiControlInterceptorCustomizer(ApiControlProperties apiControlProperties, @Autowired(required = false) CacheControl cacheControl, ApplicationContext applicationContext){ return registry -> registry.addInterceptor(new ApiControlInterceptor(apiControlProperties, cacheControl, applicationContext)) .order(Ordered.HIGHEST_PRECEDENCE + 11) // 设置拦截器的优先级 .addPathPatterns("/**"); // 设置拦截的路径模式 } } @Configuration @ConditionalOnClass({InterceptorRegistry.class}) @EnableConfigurationProperties(ApiGuardProperties.class) static class ApiGuardConfiguration { // 配置ApiGuardInterceptor的自定义拦截器注册器,添加拦截器到注册器 @Bean InterceptorRegistryCustomizer apiGuardInterceptorCustomizer(ApiGuardProperties apiGuardProperties){ return registry -> registry.addInterceptor(new ApiGuardInterceptor(apiGuardProperties)) .order(Ordered.HIGHEST_PRECEDENCE + 10) // 设置拦截器的优先级 .addPathPatterns("/**"); // 设置拦截的路径模式 } } // 拦截器注册器自定义接口,允许动态注册拦截器 public interface InterceptorRegistryCustomizer { void custom(InterceptorRegistry registry); } @ConditionalOnClass({SentinelWebTotalInterceptor.class, InterceptorRegistry.class}) @Configuration static class SentinelConfig { // 配置Sentinel的自定义拦截器注册器,添加拦截器到注册器 @Bean InterceptorRegistryCustomizer sentinelWebTotalInterceptorCustomizer(){ return registry -> { SentinelWebMvcTotalConfig conf = new SentinelWebMvcTotalConfig(); conf.setTotalResourceName(SpringContextHolder.getApplicationName()); // 设置总资源名 conf.setBlockExceptionHandler(new DefaultBlockExceptionHandler()); // 设置默认的阻塞异常处理器 SentinelWebTotalInterceptor interceptor = new SentinelWebTotalInterceptor(conf); registry.addInterceptor(interceptor) // 添加拦截器 .order(Ordered.HIGHEST_PRECEDENCE) // 设置拦截器的优先级 .addPathPatterns("/**"); // 设置拦截的路径模式 }; } }}
详细解释
- DefaultWebMvcConfig 类
- 这是一个Spring的配置类,使用@Configuration和@ConditionalOnClass注解,条件加载WebMvc配置。
- configureMessageConverters方法配置了一组消息转换器,用于处理不同类型的请求和响应数据格式,如字节数组、字符串、资源和JSON。
- jackson2HttpMessageConverter是一个Bean方法,配置了一个Jackson消息转换器,用于将Java对象与JSON之间进行转换,包含了日期格式、时区和命名策略的定制。
- addResourceHandlers方法配置了静态资源的处理路径,支持从多个目录加载资源。
- addArgumentResolvers方法配置了一个自定义的参数解析器,用于在请求处理时解析自定义参数类型。
- addInterceptors方法通过自定义的拦截器注册器动态添加拦截器,允许扩展和定制拦截器的行为。
- InspectConfiguration 类
- 这个内部配置类用于配置API管理和控制的相关Bean。
- handlerMethodRedisRegistry方法定义了一个ApiManager Bean,负责管理API统计数据,将其存储在Redis中,并与其他组件共享数据。
- apiControlInterceptorCustomizer方法配置了一个ApiControlInterceptor拦截器,用于对API请求进行监控和控制。
- ApiGuardConfiguration 类
- 这个配置类配置了API安全控制的相关拦截器。
- apiGuardInterceptorCustomizer方法配置了ApiGuardInterceptor拦截器,用于对API请求进行安全控制。
- SentinelConfig 类
- 这个配置类配置了基于Sentinel的API请求拦截器。
- sentinelWebTotalInterceptorCustomizer方法配置了SentinelWebTotalInterceptor拦截器,用于对API请求进行流量控制和异常处理。
- InterceptorRegistryCustomizer 接口
- 这个接口允许自定义拦截器的注册,提供了灵活的拦截器配置机制。
InterceptorRegistryCustomizer接口和其他代码的关系
1. 接口定义与实现
public interface InterceptorRegistryCustomizer { void custom(InterceptorRegistry registry);}
- 作用:InterceptorRegistryCustomizer接口定义了一个方法custom(InterceptorRegistry registry),该方法允许实现者自定义对InterceptorRegistry(拦截器注册表)的操作。通过实现这个接口,开发者可以在运行时动态地向Spring的拦截器链中添加、移除或配置拦截器。
2. 与配置类的关系
在DefaultWebMvcConfig类中,通过注入一个ObjectProvider对象,Spring允许多个InterceptorRegistryCustomizer实现被注入并按需执行:
@Autowiredprivate ObjectProvider<InterceptorRegistryCustomizer> interceptorRegistryCustomizers;
在DefaultWebMvcConfig类的addInterceptors方法中,使用了这个interceptorRegistryCustomizers来动态执行所有的InterceptorRegistryCustomizer实现:
@Overridepublic void addInterceptors(InterceptorRegistry registry) { for (InterceptorRegistryCustomizer interceptorRegistryCustomizer : interceptorRegistryCustomizers) { interceptorRegistryCustomizer.custom(registry); }}
- 作用:通过这种设计,DefaultWebMvcConfig类可以收集并应用所有已定义的InterceptorRegistryCustomizer实现,以动态地、按顺序地将不同的拦截器添加到Spring的拦截器链中。
3. 具体实现与使用
在内部配置类InspectConfiguration和ApiGuardConfiguration
中,定义了具体的InterceptorRegistryCustomizer实现:
@BeanInterceptorRegistryCustomizer apiControlInterceptorCustomizer(ApiControlProperties apiControlProperties, @Autowired(required = false) CacheControl cacheControl, ApplicationContext applicationContext) { return registry -> registry.addInterceptor(new ApiControlInterceptor(apiControlProperties, cacheControl, applicationContext)) .order(Ordered.HIGHEST_PRECEDENCE + 11).addPathPatterns("/**");}
@BeanInterceptorRegistryCustomizer apiGuardInterceptorCustomizer(ApiGuardProperties apiGuardProperties) { return registry -> registry.addInterceptor(new ApiGuardInterceptor(apiGuardProperties)) .order(Ordered.HIGHEST_PRECEDENCE + 10).addPathPatterns("/**");}
- 关系:
- 这些具体实现负责将自定义的拦截器(例如ApiControlInterceptor和ApiGuardInterceptor)添加到Spring的拦截器链中。
- 每个实现都通过custom方法将一个新的拦截器注册到InterceptorRegistry中,并且可以自定义拦截器的顺序和拦截路径。
4. 动态性与扩展性
- InterceptorRegistryCustomizer接口提供了一种高度灵活和可扩展的机制,允许开发者在不修改核心配置类的情况下,通过定义多个实现类来自定义拦截器的注册逻辑。
- 这种设计模式遵循了依赖注入和面向接口编程的原则,使得代码更具扩展性和模块化,符合Spring框架的设计哲学。
5. 总结
- InterceptorRegistryCustomizer接口 是连接配置类(如DefaultWebMvcConfig)和具体拦截器实现之间的桥梁。
- 它使得拦截器的添加与配置过程更加动态化和可定制,满足了复杂应用场景下对拦截器灵活配置的需求。
- 每个具体的InterceptorRegistryCustomizer实现都会在应用启动时被收集和执行,从而在拦截器链中注册不同的拦截器,这些拦截器将按照配置的优先级处理应用的所有请求。
Top comments(0)
Subscribe
Some comments may only be visible to logged-in visitors.Sign in to view all comments.
For further actions, you may consider blocking this person and/orreporting abuse