java web初始化实例,SpringBoot源码分析-初始化Tomcat-ServletWebServerFactory实例化
发布日期:2021-06-24 14:00:33 浏览次数:2 分类:技术文章

本文共 11018 字,大约阅读时间需要 36 分钟。

概要

详细剖析ServletWebServerFactory实例化过程,整个过程使用多次后置处理对Bean实例化进行干预,完成TomcatServletWebServerFactory进行初始化

ServletWebServerFactory实例化

Spring容器在刷新容器的时候创建WebServer之前,先要创建ServletWebServerFactory

ServletWebServerFactory factory = getWebServerFactory();

从前面的自动配置类代码可以看出,要想得到TomcatServletWebServerFactory,得先实例化FactoryBean:EmbeddedTomcat

public static class EmbeddedTomcat {

@Bean

public TomcatServletWebServerFactory tomcatServletWebServerFactory() {

return new TomcatServletWebServerFactory();

}

}

Spring在实例化TomcatServletWebServerFactory过程中会经过几次后置处理器的干预,它们分别是:

applyBeanPostProcessorsBeforeInitialization

这里面的CommonAnnotationPostProcessor对JSR-250@PostConstruct @PreDestroy处理

postProcessAfterInstantiation

postProcessProperties

postProcessPropertyValues

invokeInitMethods(类似后置处理器)

applyBeanPostProcessorsAfterInitialization

后置处理:applyBeanPostProcessorsBeforeInitialization

org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization对servletWebServerFactory的处理

ApplicationContextAwareProcessor

因为TomcatServletWebServerFactory没有实现什么XxxAware接口,所以无需处理

WebApplicationContextServletContextAwareProcessor

是对ServletContextAware的处理,因为Spring自带的ApplicationContextAwareProcessor不包含ServletContextAware

ImportAwareBeanPostProcessor

ImportAwareBeanPostProcessor是ConfigurationClassPostProcessor的内部类,因为TomcatServletWebServerFactory没有实现什么ImportAware接口,所以无需处理

BeanPostProcessorChecker

BeanPostProcessorChecker是PostProcessorRegistrationDelegate的内部类,重写的postProcessBeforeInitialization方法本身不包含任何处理

ConfigurationPropertiesBindingPostProcessor

如果Bean被@ConfigurationProperties修饰,则使用该后置处理器将PropertySources与该Bean绑定

MethodValidationPostProcessor

它没有重写postProcessBeforeInitialization方法,而是他的抽象父类AbstractAdvisingBeanPostProcessor重写的,但是犯方法内并没有任何处理

WebServerFactoryCustomizerBeanPostProcessor

它完成了对TomcatServletWebServerFactory Bean(还不是完整的Spring Bean)的一些初始化操作

它的BeanDefinition由ServletWebServerFactoryAutoConfiguration完成注册,并在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors中完成实例化

private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {

/**

* 依次调用从容器中拿出来的WebServerFactoryCustomizer.customize方法

*/

LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)

.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)

.invoke((customizer) -> customizer.customize(webServerFactory));

}

getCustomizers()从自动配置类导入的BeanDefinitions当中找到WebServerFactoryCustomizer,并实例化

/**

* 从容器中拿WebServerFactoryCustomizer Bean,默认会拿出以下几个Customizer出来:

* TomcatWebSocketServletWebServerCustomizer来自于:WebSocketServletAutoConfiguration#webSocketServletWebServerCustomizer()

* ——实例化TomcatWebSocketServletWebServerCustomizer同时实例化WebSocketServletAutoConfiguration

* ServletWebServerFactoryCustomizer来自于:ServletWebServerFactoryAutoConfiguration#servletWebServerFactoryCustomizer()

* ——实例化ServletWebServerFactoryCustomizer同时实例化ServerProperties、ServletWebServerFactoryAutoConfiguration

* TomcatServletWebServerFactoryCustomizer来自于:ServletWebServerFactoryAutoConfiguration#tomcatServletWebServerFactoryCustomizer()

* ——实例化TomcatServletWebServerFactoryCustomizer

* TomcatWebServerFactoryCustomizer来自于:TomcatWebServerFactoryCustomizerConfiguration#tomcatWebServerFactoryCustomizer()

* ——实例化TomcatWebServerFactoryCustomizer同时实例化TomcatWebServerFactoryCustomizerConfiguration

* HttpEncodingAutoConfiguration$LocaleCharsetMappingsCustomizer来自于:HttpEncodingAutoConfiguration#localeCharsetMappingsCustomizer()

* ——实例化LocaleCharsetMappingsCustomizer同时实例化了HttpProperties、HttpEncodingAutoConfiguration

*/

private Collection> getCustomizers() {

if (this.customizers == null) {

// Look up does not include the parent context

this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());

this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);

this.customizers = Collections.unmodifiableList(this.customizers);

}

return this.customizers;

}

实例化这些Customizer之后,就要循环调用它们的customize方法对TomcatServletWebServerFactory进行初始化,比如添加ContextCustomer(Lamda表达式),设置Server和Context的核心参数等等

TomcatWebSocketServletWebServerCustomizer

public void customize(TomcatServletWebServerFactory factory) {

//给TomcatServletWebServerFactory添加ContextCustomizer

factory.addContextCustomizers((context) -> context.addApplicationListener(WsContextListener.class.getName()));

}

在获取TomcatWebServer的时候会使用添加的ContextCustomizer,代码如下

TomcatServletWebServerFactory#configureContext(

/**

* 使用TomcatServletWebServerFactory准备好的参数配置TomcatEmbeddedContext

*/

protected void configureContext(Context context, ServletContextInitializer[] initializers) {

TomcatStarter starter = new TomcatStarter(initializers);

if (context instanceof TomcatEmbeddedContext) {

TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext) context;

embeddedContext.setStarter(starter);

embeddedContext.setFailCtxIfServletStartFails(true);

}

/**

* 将当前ApplicationContext的initializer与TomcatEmbeddedContext绑定

*/

context.addServletContainerInitializer(starter, NO_CLASSES);

for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {

context.addLifecycleListener(lifecycleListener);

}

for (Valve valve : this.contextValves) {

context.getPipeline().addValve(valve);

}

for (ErrorPage errorPage : getErrorPages()) {

new TomcatErrorPage(errorPage).addToContext(context);

}

for (MimeMappings.Mapping mapping : getMimeMappings()) {

context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());

}

configureSession(context);

new DisableReferenceClearingContextCustomizer().customize(context);

/**

* 使用在实例化TomcatServletWebServerFactory时添加的ContextCustomizer改变TomcatEmbeddedContext状态

*/

for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {

customizer.customize(context);

}

}

ServletWebServerFactoryCustomizer

public void customize(ConfigurableServletWebServerFactory factory) {

PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();

//设置端口:8080

map.from(this.serverProperties::getPort).to(factory::setPort);

//设置地址,比如:localhost

map.from(this.serverProperties::getAddress).to(factory::setAddress);

//设置ContextPath,比如:www.xxx.com/ContextPath/

map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);

//设置应用名称

map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);

//设置Session

map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);

//设置SSL

map.from(this.serverProperties::getSsl).to(factory::setSsl);

//设置JSP,用以支持JSP SERVLET

map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);

map.from(this.serverProperties::getCompression).to(factory::setCompression);

//设置HTTP2,用以支持HTTP/2

map.from(this.serverProperties::getHttp2).to(factory::setHttp2);

//设置Header

map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);

//设置初始化参数

map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);

}

TomcatServletWebServerFactoryCustomizer

public void customize(TomcatServletWebServerFactory factory) {

ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat();

if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) {

factory.getTldSkipPatterns().addAll(tomcatProperties.getAdditionalTldSkipPatterns());

}

//是否支持使用"/"重定向到根路径

if (tomcatProperties.getRedirectContextRoot() != null) {

customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot());

}

//是否支持相对或者绝对路径的重定向

if (tomcatProperties.getUseRelativeRedirects() != null) {

customizeUseRelativeRedirects(factory, tomcatProperties.getUseRelativeRedirects());

}

}

TomcatWebServerFactoryCustomizer

/**

* 设置容器的相关核心参数,比如Basedir,最大最小线程数等等

*/

public void customize(ConfigurableTomcatWebServerFactory factory) {

ServerProperties properties = this.serverProperties;

ServerProperties.Tomcat tomcatProperties = properties.getTomcat();

PropertyMapper propertyMapper = PropertyMapper.get();

propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory);

。。。省略部分代码。。。

//设置

propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive)

.to((maxThreads) -> customizeMaxThreads(factory, tomcatProperties.getMaxThreads()));

propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive)

.to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));

。。。省略部分代码。。。

//添加关于Resource的ContextCustomizer

customizeStaticResources(factory);

//添加一个功能是"错误日志报告Valve"的ContextCustomizer,如果看过Tomcat源码,它自己也有这么一个类似的ErrorReportValve

customizeErrorReportValve(properties.getError(), factory);

}

LocaleCharsetMappingsCustomizer

/**

* 设置本地字符集

*/

public void customize(ConfigurableServletWebServerFactory factory) {

if (this.properties.getMapping() != null) {

factory.setLocaleCharsetMappings(this.properties.getMapping());

}

}

ErrorPageRegistrarBeanPostProcessor

完成默认错误页的相关注册工作

private void postProcessBeforeInitialization(ErrorPageRegistry registry) {

/**

* 调用getRegistrars()实例化ErrorPageCustomizer implements ErrorPageRegistrar,SpringBoot自动配置类ErrorMvcAutoConfiguration完成的ErrorPageCustomizer配置

* 往TomcatServletWebServerFactory中添加了一个path="/error"的ErrorPage

*/

for (ErrorPageRegistrar registrar : getRegistrars()) {

registrar.registerErrorPages(registry);

}

}

CommonAnnotationBeanPostProcessor

调用它父类的postProcessBeforeInitialization,在这会调用被@PostConstruct注解修饰的方法。它还有另外一个功能就是调用被@PreDestroy修饰的方法

不过TomcatServletWebServerFactory并没有

AutowiredAnnotationBeanPostProcessor

本身不包含任何处理

ApplicationListenerDetector

本身不包含任何处理

调用afterPropertiesSet方法invokeInitMethods

调用接口InitializingBean接口实现类的afterPropertiesSet方法

很遗憾,TomcatServletWebServerFactory并没有实现InitializingBean接口

applyBeanPostProcessorsAfterInitialization

接下来又像applicationBeanPostProcessorsBeforInitialization一样,循环11个PostProcessor

ApplicationContextAwareProcessor

本身不包含任何处理

WebApplicationContextServletContextAwareProcessor

本身不包含任何处理

ImportAwareBeanPostProcessor

本身不包含任何处理

BeanPostProcessorChecker

这个类可以不关注它,是用来校验Bean理论上应该被多少BeanPostProcessor处理与实际数量是否一致,如果不一致就会答应日志,提示没有被所有符合条件的PostProcessor处理

ConfigurationPropertiesBindingPostProcessor

本身不包含任何处理

MethodValidationPostProcessor

TomcatServletWebServerFactory不是它的处理对象,该Processor和AOP相关:使Spring AOP Advisor作用到指定的特殊 bean上

WebServerFactoryCustomizerBeanPostProcessor

本身不包含任何处理

ErrorPageRegistrarBeanPostProcessor

本身不包含任何处理

CommonAnnotationBeanPostProcessor

本身不包含任何处理

AutowiredAnnotationBeanPostProcessor

本身不包含任何处理

ApplicationListenerDetector

TomcatServletWebServerFactory不是它的处理对象,该Processor可以将一个实现了ApplicationListener接口的类对应的Bean添加到容器的ApplicationListener列表中。Spring的又一个扩展点

小结

梳理完这个过程,把Spring实例化Bean的主要过程又走了一遍,复习复习也好。但是关于

postProcessAfterInstantiation:实例化后置处理

postProcessProperties:在postProcessAfterInstantiation执行之后并返回true, 返回的PropertyValues将作用于给定bean属性赋值(applyPropertyValues()). spring 5.1之后出现以替换@Deprecated标注的postProcessPropertyValues

总结

如果真的把SpringBoot所有自动配置类如何配置与实例化都看完,这个工作量真的好大。。。。决定把Tomcat这块整完后,如果有时间再把DispatcherServlet实例化过程梳理完,就暂停SpringBoot源码分析了。以后遇到情况或者有时间再补充,接下来还要看其它的。

TomcatServletWebServerFactory实例化只是Tomcat 初始化阶段的一个对象,在这里准备好了Server Context相关的参数等。通过看它的实例化过程加深了Spring Bean实例化过程。

转载地址:https://blog.csdn.net/weixin_33303537/article/details/115781910 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:php键值重新组成新的数组,array_keys::PHP所有键值组合新数组
下一篇:php清除账号登录,PHP artisan cache:clear 避免把用户登录信息也清空

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月15日 07时39分48秒