1.SpringBoot自動(dòng)裝配原理
1.1 核心是這個(gè)@SpringBootApplication注解
里面主要包含三個(gè)注解:@SpringBootConfiguration、@EnableAutoConfiguration斜做、@ComponentScan贴汪;
1.2 @EnableAutoConfiguration:表示開啟自動(dòng)裝配慧脱;@ComponentScan:表示掃描當(dāng)前配置類所在路徑的全部配置類凤价。
1.3其中@EnableAutoConfiguration這個(gè)注解里面引入了一個(gè)@Import(AutoConfigurationImportSelector.class),而這個(gè)類實(shí)現(xiàn)了DeferredImportSelector接口乎莉。這個(gè)接口的selectImports()將在spring解析完我們自定義的配置類之后抄瓦,才會(huì)解析自動(dòng)配置類截型。
1)在selectImports()方法中的getAutoConfigurationEntry()將會(huì)從spring.factories文件讀取key=org.springframework.boot.autoconfigure.EnableAutoConfiguration對(duì)應(yīng)的自動(dòng)配置類:
2)在getAutoConfigurationEntry()中讼载,getConfigurationClassFilter()方法會(huì)讀取spring.factories 文件中key=AutoConfigurationImportFilter的值轿秧,同時(shí)會(huì)得到三個(gè)條件過濾器,OnBeanCondition咨堤、OnClassCondition菇篡、OnWebApplicationCondition使用這三個(gè)注解進(jìn)一步過濾掉不符合的自動(dòng)配置類:
3)在過濾器比較篩選自動(dòng)配置類時(shí),會(huì)讀取"META-INF/spring-autoconfigure-metadata.properties"文件中的內(nèi)容一喘,進(jìn)行加快篩選:
2.AutoConfigurationImportSelector的源碼解析
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 會(huì)在所有@Configuration都解析完了之后才執(zhí)行
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 獲取自動(dòng)配置類(spring.factories中所導(dǎo)入的)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 獲取@EnableAutoConfiguration的屬性 比如exclude excludeName
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 獲取spring.factories中@EnableAutoConfiguration對(duì)應(yīng)的所有的AutoConfiguration(自動(dòng)配置類)
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去重(也就是按類名去重)
configurations = removeDuplicates(configurations);
// 獲取需要排除的AutoConfiguration驱还,可以通過@EnableAutoConfiguration注解的exclude屬性铝侵,或者spring.autoconfigure.exclude來配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 排除部分自動(dòng)裝配類
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 獲取spring.factories中的AutoConfigurationImportFilter對(duì)AutoConfiguration進(jìn)行過濾
// 默認(rèn)會(huì)拿到OnBeanCondition、OnClassCondition咪鲜、OnWebApplicationCondition
// 這三個(gè)會(huì)去判斷上面的AutoConfiguration是否符合它們自身所要求的條件撞鹉,不符合的會(huì)過濾掉,表示不會(huì)進(jìn)行解析了
// 會(huì)利用spring-autoconfigure-metadata.properties中的配置來進(jìn)行過濾
configurations = getConfigurationClassFilter().filter(configurations);
// configurations表示合格的享郊,exclusions表示被排除的,把它們記錄在條件報(bào)告中
fireAutoConfigurationImportEvents(configurations, exclusions);
// 最后返回的都是符合條件的自動(dòng)裝配類
return new AutoConfigurationEntry(configurations, exclusions);
}
private ConfigurationClassFilter getConfigurationClassFilter() {
if (this.configurationClassFilter == null) {
// 讀取spring.factories中key = AutoConfigurationImportFilter的value
List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
for (AutoConfigurationImportFilter filter : filters) {
invokeAwareMethods(filter);
}
// 給filter集合賦值
this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
}
return this.configurationClassFilter;
}
ConfigurationClassFilter#filter():
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
// configurations就是讀取到的自動(dòng)配置類
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
// 逐個(gè)利用AutoConfigurationImportFilter來判斷所有的自動(dòng)配置類的條件是否匹配炊琉,匹配結(jié)果存在match數(shù)組中
// 這里過濾器的順序是spring.factories文件中配置的順序
for (AutoConfigurationImportFilter filter : this.filters) {
// 調(diào)用具體過濾器實(shí)現(xiàn)的match方法
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
candidates[i] = null;
skipped = true;
}
}
}
// 全部都匹配
if (!skipped) {
return configurations;
}
// 把匹配的記錄在result集合中又活,最后返回
List<String> result = new ArrayList<>(candidates.length);
for (String candidate : candidates) {
if (candidate != null) {
result.add(candidate);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return result;
}
這里的過濾器只有三個(gè)并不是全的苔咪,來源就是spring.factories中定義的:
3.@AutoConfigurationPackage自動(dòng)配置包路徑
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
主要執(zhí)行的方法是registerBeanDefinitions():
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 將MyApplication.class所在的包路徑注冊(cè)成BeanDefinition,
// 方便第三方減少配置,比如mybatis不用配置掃描路徑柳骄,直接獲取這個(gè)BeanDefinition
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
}
PackageImports(AnnotationMetadata metadata) {
// 獲取注解的屬性
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
// 注解屬性的value
List<String> packageNames = new ArrayList<>(Arrays.asList(attributes.getStringArray("basePackages")));
for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
packageNames.add(basePackageClass.getPackage().getName());
}
// 當(dāng)前配置類所在的包路徑
if (packageNames.isEmpty()) {
// metadata.getClassName() :獲取當(dāng)前配置類的類名
// ClassUtils.getPackageName:獲取配置類所在的包的路徑
packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));
}
this.packageNames = Collections.unmodifiableList(packageNames);
}
該方法register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]))团赏,最終會(huì)將收到的包路徑注冊(cè)到Spring容器當(dāng)中,方便第三方對(duì)接時(shí)不用填寫掃描路徑也仍然可以獲取到掃描路徑耐薯。
4.@ComponentScan中的兩個(gè)excluseFilter
1.TypeExcludeFilter.class
public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {
private BeanFactory beanFactory;
// 所有這個(gè)TypeExcludeFilter類型的Bean集合
private Collection<TypeExcludeFilter> delegates;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
// 從Spring容器中獲取TypeExcludeFilter舔清,然后進(jìn)行匹配丝里,匹配的則不解析
for (TypeExcludeFilter delegate : getDelegates()) {
// 調(diào)用自定義的TypeExcludeFilter的match方法,匹配就排除這個(gè)類
if (delegate.match(metadataReader, metadataReaderFactory)) {
return true;
}
}
}
return false;
}
private Collection<TypeExcludeFilter> getDelegates() {
Collection<TypeExcludeFilter> delegates = this.delegates;
if (delegates == null) {
// 從Spring容器獲取這個(gè)類型的Bean
delegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
this.delegates = delegates;
}
return delegates;
}
}
2.AutoConfigurationExcludeFilter.class
public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {
private ClassLoader beanClassLoader;
private volatile List<String> autoConfigurations;
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 這個(gè)方法就是驗(yàn)證當(dāng)前類是否是配置類并且是自動(dòng)配置類
// 如果符合体谒,就排除這個(gè)類杯聚,不去解析,讓@EnableAutoConfiguration那邊去處理
return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
}
// 當(dāng)前類是否有@Configuration注解
private boolean isConfiguration(MetadataReader metadataReader) {
return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
}
// 當(dāng)前類是否是自動(dòng)配置類
private boolean isAutoConfiguration(MetadataReader metadataReader) {
return getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
}
protected List<String> getAutoConfigurations() {
if (this.autoConfigurations == null) {
this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
this.beanClassLoader);
}
return this.autoConfigurations;
}
}
這兩個(gè)過濾器都是在掃描階段過濾掉部分類营密,而AutoConfigurationExcludeFilter則是過濾自動(dòng)配置類械媒;TypeExcludeFilter根據(jù)match方法匹配,符合就過濾掉评汰。
1.為什么要在掃描階段過濾自動(dòng)配置類呢纷捞?
因?yàn)锧EnableAutoConfiguration實(shí)現(xiàn)了DeferredImportSelector接口,而這個(gè)接口會(huì)在所有配置類解析完之后被去,才會(huì)調(diào)用的主儡,在掃描階段過濾自動(dòng)配置類可以提高性能,也保證了配置類的解析順序惨缆。
2.我們?cè)诶^承TypeExcludeFilter重寫match方法時(shí)糜值,如果是用@Bean注入Spring容器中,將不會(huì)生效坯墨。
和執(zhí)行順序有關(guān)寂汇,@Component骄瓣、@ComponentScan會(huì)先執(zhí)行榕栏,@Bean在后面執(zhí)行扒磁。當(dāng)掃描解析配置類時(shí)妨托,@Bean對(duì)應(yīng)的Bean對(duì)象還沒生成添加到Spring容器中。
對(duì)于這個(gè)問題的解決辦法脆贵,可以在掃描前卖氨,就將我們重寫的TypeExcludeFilter添加到容器中筒捺。
1)比如可以實(shí)現(xiàn)ApplicationContextInitializer初始化器系吭,然后再spring.factories中配置我們實(shí)現(xiàn)的類肯尺;
2)然后再initialize方法中將我們的實(shí)現(xiàn)類注冊(cè)到spring容器當(dāng)中则吟。
5.Starter機(jī)制
Springboot中的Starter機(jī)制氓仲,就是一個(gè)Maven依賴敬扛,當(dāng)我們?cè)陧?xiàng)目中引入spring-boot-starter-web依賴時(shí)啥箭,實(shí)際上引入了spring-boot-starter捉蚤、spring-boot-starter-json缆巧、spring-boot-starter-tomcat等和Web開發(fā)相關(guān)的依賴包陕悬。
然后再通過條件注解用來判斷當(dāng)前應(yīng)用的依賴中是否存在某個(gè)類或某些類捉超,這樣就可以動(dòng)態(tài)的注入某些類枝誊。
對(duì)于@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) 這個(gè)注解叶撒,如果Servlet.class類不存在,但是運(yùn)行時(shí)不報(bào)錯(cuò)压汪,SpringBoot是怎么處理的止剖?
1.我們引入某個(gè)依賴時(shí)穿香,依賴中的文件都是已經(jīng)編譯好的扔水,因此在我們項(xiàng)目編譯期間魔市,是不會(huì)再次編譯的待德。
2.運(yùn)行時(shí)不報(bào)錯(cuò)将宪,是因?yàn)镾pringboot使用了ASM技術(shù)较坛,直接處理字節(jié)碼文件丑勤,而不是使用反射生成實(shí)例法竞,通過獲取某個(gè)類的類名岔霸,再使用類加載器去驗(yàn)證是否存在呆细。
6.自動(dòng)裝配Tomcat
1.創(chuàng)建WebServer
ServletWebServerApplicationContext#onRefresh():
protected void onRefresh() {
super.onRefresh();
try {
// 啟動(dòng)Tomcat
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 獲取具體的WebServerFactory,比如TomcatServletWebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer()); // 這個(gè)方法啟動(dòng)tomcat
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
getWebServerFactory()獲取ServletWebServerFactory實(shí)例:
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don't consider the hierarchy
//通過類型獲取beanName
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
// 期間發(fā)現(xiàn)多個(gè)或沒有都會(huì)報(bào)錯(cuò)
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing "
+ "ServletWebServerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "
+ "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
}
// 這里才會(huì)返回對(duì)應(yīng)的Bean實(shí)例
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
2.ServletWebServerFactoryAutoConfiguration自動(dòng)配置類:
這個(gè)類Import了EmbeddedTomcat.class,EmbeddedJetty.class,EmbeddedUndertow.class 三個(gè)類,就是為了生成對(duì)應(yīng)的WebServer實(shí)例略水。
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class) //ServerProperties用于讀取properties配置文件渊涝,里面以server開頭的內(nèi)容
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
ObjectProvider<WebListenerRegistrar> webListenerRegistrars,
ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers) {
return new ServletWebServerFactoryCustomizer(serverProperties,
webListenerRegistrars.orderedStream().collect(Collectors.toList()),
cookieSameSiteSuppliers.orderedStream().collect(Collectors.toList()));
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
static class ForwardedHeaderFilterConfiguration {
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
}
@Bean
FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(
ObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
customizerProvider.ifAvailable((customizer) -> customizer.customize(filter));
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registration;
}
}
interface ForwardedHeaderFilterCustomizer {
void customize(ForwardedHeaderFilter filter);
}
/**
* Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
* {@link ImportBeanDefinitionRegistrar} for early registration.
*/
public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
// 往Spring容器中注冊(cè)一個(gè)WebServerFactoryCustomizerBeanPostProcessor
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class,
WebServerFactoryCustomizerBeanPostProcessor::new);
registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
}
private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name,
Class<T> beanClass, Supplier<T> instanceSupplier) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
}
我們以EmbeddedTomcat這個(gè)類為例:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); //這里new出來使用的是默認(rèn)的端口8080
// orderedStream()調(diào)用時(shí)會(huì)去Spring容器中找到TomcatConnectorCustomizer類型的Bean,默認(rèn)是沒有的缆娃,程序員可以自己定義
factory.getTomcatConnectorCustomizers()
.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatContextCustomizers()
.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatProtocolHandlerCustomizers()
.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
只有當(dāng)spring容器中沒有ServletWebServerFactory贯要,并且所依賴的三個(gè)類也都存在時(shí)崇渗,才會(huì)創(chuàng)建TomcatServletWebServerFactory宅广。
3.關(guān)于application.properties屬性是如何替換默認(rèn)值
BeanPostProcessorsRegistrar.class當(dāng)中跟狱,會(huì)調(diào)用registerBeanDefinitions()向spring容器中注冊(cè)WebServerFactoryCustomizerBeanPostProcessor兽肤。
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
// 往Spring容器中注冊(cè)一個(gè)WebServerFactoryCustomizerBeanPostProcessor
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class,
WebServerFactoryCustomizerBeanPostProcessor::new);
registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
}
然后會(huì)接著調(diào)用WebServerFactoryCustomizerBeanPostProcessor#postProcessBeforeInitialization()方法
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
// 獲取WebServerFactoryCustomizer對(duì)WebServerFactory進(jìn)行自定義资铡,默認(rèn)會(huì)拿到5個(gè)笤休,其中就包括ServletWebServerFactoryCustomizer
LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
.invoke((customizer) -> customizer.customize(webServerFactory));
}
最終會(huì)執(zhí)行對(duì)應(yīng)的customize()店雅,讀取properties文件中配置的信息闹啦,替換默認(rèn)值:
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(this.serverProperties::getPort).to(factory::setPort);
map.from(this.serverProperties::getAddress).to(factory::setAddress);
map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
map.from(this.serverProperties.getServlet()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);
map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
map.from(this.serverProperties::getSsl).to(factory::setSsl);
map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
map.from(this.serverProperties::getCompression).to(factory::setCompression);
map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
for (WebListenerRegistrar registrar : this.webListenerRegistrars) {
registrar.register(factory);
}
if (!CollectionUtils.isEmpty(this.cookieSameSiteSuppliers)) {
factory.setCookieSameSiteSuppliers(this.cookieSameSiteSuppliers);
}
}
4.通過自定義TomcatConnectorCustomizer更改tomcat信息
在TomcatServletWebServerFactory#getWebServer荐健,其中customizeConnector就會(huì)調(diào)用之前設(shè)置到factory里面的自定義的TomcatConnectorCustomizer江场,然后對(duì)connector進(jìn)行配置:
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
for (LifecycleListener listener : this.serverLifecycleListeners) {
tomcat.getServer().addLifecycleListener(listener);
}
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
// 配置tomcat端口號(hào)
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);// 這里啟動(dòng)tomcat
}
protected void customizeConnector(Connector connector) {
int port = Math.max(getPort(), 0);
connector.setPort(port);
if (StringUtils.hasText(getServerHeader())) {
connector.setProperty("server", getServerHeader());
}
if (connector.getProtocolHandler() instanceof AbstractProtocol) {
customizeProtocol((AbstractProtocol<?>) connector.getProtocolHandler());
}
invokeProtocolHandlerCustomizers(connector.getProtocolHandler());
if (getUriEncoding() != null) {
connector.setURIEncoding(getUriEncoding().name());
}
// Don't bind to the socket prematurely if ApplicationContext is slow to start
connector.setProperty("bindOnInit", "false");
if (getHttp2() != null && getHttp2().isEnabled()) {
connector.addUpgradeProtocol(new Http2Protocol());
}
if (getSsl() != null && getSsl().isEnabled()) {
customizeSsl(connector);
}
TomcatConnectorCustomizer compression = new CompressionConnectorCustomizer(getCompression());
compression.customize(connector);
// 這個(gè)customizer就是程序員自己定義的bean,然后覆蓋默認(rèn)的值
for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
customizer.customize(connector);
}
}
// 示例
// 通過自定義TomcatConnectorCustomizer佑附,實(shí)現(xiàn)更改tomcat的信息
@Bean
public TomcatConnectorCustomizer tomcatConnectorCustomizer(){
return new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setPort(8082);
}
};
}