先上代码
@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实现被注入并按需执行:
@Autowired
private ObjectProvider<InterceptorRegistryCustomizer> interceptorRegistryCustomizers;
在DefaultWebMvcConfig类的addInterceptors方法中,使用了这个interceptorRegistryCustomizers来动态执行所有的InterceptorRegistryCustomizer实现:
@Override
public void addInterceptors(InterceptorRegistry registry) {
for (InterceptorRegistryCustomizer interceptorRegistryCustomizer : interceptorRegistryCustomizers) {
interceptorRegistryCustomizer.custom(registry);
}
}
- 作用:通过这种设计,DefaultWebMvcConfig类可以收集并应用所有已定义的InterceptorRegistryCustomizer实现,以动态地、按顺序地将不同的拦截器添加到Spring的拦截器链中。
3. 具体实现与使用
在内部配置类InspectConfiguration和ApiGuardConfiguration
中,定义了具体的InterceptorRegistryCustomizer实现:
@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("/**");
}
@Bean
InterceptorRegistryCustomizer 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)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.