Spring的很多子项目都涉及到配置。在这些项目中,存在一个较为通用的配置模式,了解该模式有助于我们更好地理解框架。本文将对这一模式进行介绍。
我们会先介绍Spring Web MVC框架,之后再结合其他相似的项目进行总结。
1 Registry
registry是登记、注册的意思。以Registry
结尾的对象用于完成特定功能的配置。比如CorsRegistry
用来配置应用的跨域访问功能,ViewResolverRegistry
用来配置应用的视图解析功能,FormatterRegistry
用来配置应用的格式转换功能……
这些以
Registry
结尾的对象只是在逻辑含义上相似,并不是说所有的这些对象都继承或实现了某个Registry
接口。实际上,名为Registry
的接口在Spring中并不存在。
下面是经过整理后的FormatterRegistry
类的源代码。
package org.springframework.format;
import java.lang.annotation.Annotation;
import org.springframework.core.convert.converter.ConverterRegistry;
/**
* A registry of field formatting logic.
*/
public interface FormatterRegistry extends ConverterRegistry {
void addPrinter(Printer<?> printer);
void addParser(Parser<?> parser);
void addFormatter(Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
}
2 Configurer
configurer是配置器的意思,以Configurer
结尾的对象表示一个配置集合。以Spring Web MVC项目为例,最著名的当数WebMvcConfigurer
这个接口了,它是Spring Web MVC中涉及配置的一个核心抽象。
Configurer
和Registry
之间具有从属关系。在Configurer
中会拆分出很多方法,这些方法用于完成特定功能的配置。方法的入参往往会抽象成一个Registry
对象。比如void addFormatters(FormatterRegistry registry)
方法是给应用增加新的格式化功能的,它的方法入参就是一个名为FormatterRegistry
的Registry
对象。
下面是整理简化后的WebMvcConfigurer
源码。
package org.springframework.web.servlet.config.annotation;
/**
* Defines callback methods to customize the Java-based configuration for
* Spring MVC enabled via {@code @EnableWebMvc}.
*/
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
default void addFormatters(FormatterRegistry registry) {}
default void addInterceptors(InterceptorRegistry registry) {}
default void addResourceHandlers(ResourceHandlerRegistry registry) {}
default void addCorsMappings(CorsRegistry registry) {}
default void addViewControllers(ViewControllerRegistry registry) {}
default void configureViewResolvers(ViewResolverRegistry registry) {}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
}
3 ConfigurerComposite
Spring工程中还有一类以ConfigurerComposite
结尾的类,这个类是一个代理类。ConfigurerComposite
一般会实现一个同类型的Configurer
类,并在内部保存一个类型相同的名为delegates
的列表(代理模式)。
比如Spring Web MVC中的WebMvcConfigurerComposite
,它实现了WebMvcConfigurer
接口,并在内部定义了一个List<WebMvcConfigurer>
类型的列表。
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
}
这种设计的好处是可以通过IoC容器的依赖注入特性,将应用中所有Configurer
的具体实现注入到ConfigurerComposite
类中,并通过代理方法依次调用所有实现类对应的配置方法。
class WebMvcConfigurerComposite implements WebMvcConfigurer {
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void addFormatters(FormatterRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addFormatters(registry);
}
}
}
4 Configuration
Spring中以Configuration
结尾的类通常都是配置类,会配合@Configuration
注解一起使用,在ApplicationContext
启动时会被执行并注入到IoC容器中。
如果Configuration
类以Delegating
开头,则这个类一般会有一个Compoisite
类型的内部变量,Configuration
将配置功能通过代理的方式给到这个内部变量来处理。
在Spring Web MVC框架中,该类的名称为DelegatingWebMvcConfiguration
,它的内部包含一个名为configurers
的属性。
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
}
DelegatingWebMvcConfiguration
使用@Autowired
注解将IoC容器中所有WebMvcConfigurer
类型的Bean注入到configurers
属性中。
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
具体的配置功能则全部代理给configurers
实现,如下面这段代码。
@Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
5 ConfigurationSupport
Spring中还存在一类以ConfigurationSupport
结尾的类。Spring工程具有强大的自配置功能,便是通过这个ConfigurationSupport
类实现的。
Spring Web MVC中有一个名为WebMvcConfigurationSupport
类,DelegatingWebMvcConfiguration
类继承自该类,因此WebMvcConfigurationSupport
中所有的@Bean
都会注入到IoC容器中。
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
ConfigurationSupport
类会根据应用状态决定如何初始化应用。比如扫描classpath
目录下有哪些包,以决定如何初始化哪些对象。比如下面这段代码则是通过加载Jackson相关class对象判断是否引入了Jackson,已确定是否需要增加MappingJackson2HttpMessageConverter类支持相关类型转换特性。
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
5 总结
Spring工程中和配置相关的类包括:
-
*Registry
:对某一特定功能进行配置的对象 -
*Configurer
:进行配置的配置器,内部会定义多个配置方法,方法入参 类型是*Registry
-
*ConfigurerComposite
:配置器的代理类,内部会包含一个Collection<*Configurer>
的列表 -
*Configuration
:配置类,结合@Configuration
注解一起使用 -
Delegating*Configuration
:具有代理功能的配置类,内部会包含一个*ConfigurerComposite
类型的对象 -
*ConfigurationSupport
:具有自配置特性的配置类,由Delegating*Confgiuration
继承
5 后续
后续会介绍和应用配置相关的注解(@Annotation
),同时会给出几个使用该模式进行配置的Spring项目样例。