准备工作
我们知道SpringBoot的自动装配的秘密在 org.springframework.boot.autoconfigure
包下的 spring.factories
文件中,而嵌入Tomcat的原理就在这个文件中加载的一个配置类: org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
@Configuration
@AutoConfigureOrder (Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass (ServletRequest. class )
@ConditionalOnWebApplication (type = Type.SERVLET)
@EnableConfigurationProperties (ServerProperties. class )
@Import ({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar. class ,
ServletWebServerFactoryConfiguration.EmbeddedTomcat. class ,
ServletWebServerFactoryConfiguration.EmbeddedJetty. class ,
ServletWebServerFactoryConfiguration.EmbeddedUndertow. class })
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnClass (name = "org.apache.catalina.startup.Tomcat" )
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
/**
* 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 ;
}
registerSyntheticBeanIfMissing(registry,
"webServerFactoryCustomizerBeanPostProcessor" ,
WebServerFactoryCustomizerBeanPostProcessor. class );
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor" ,
ErrorPageRegistrarBeanPostProcessor. class );
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(
this .beanFactory.getBeanNamesForType(beanClass, true , false ))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic( true );
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
}
|
首先看一下上方的几个注解
- @AutoConfigureOrder 这个注解是决定配置类的加载顺序的,当注解里的值越小越先加载,而 Ordered.HIGHEST_PRECEDENCE 的值是 Integer.MIN_VALUE 也就是说这个类肯定是最先加载的那一批
- @ConditionalOnXXX 在之前的文章中已经无数次提到了,就不再阐述了
- @EnableConfigurationProperties 开启 ServerProperties 类的属性值配置。而这个类里面包含的就是Web服务的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@ConfigurationProperties (prefix = "server" , ignoreUnknownFields = true )
public class ServerProperties {
private Integer port;
private InetAddress address;
@NestedConfigurationProperty
private final ErrorProperties error = new ErrorProperties();
private Boolean useForwardHeaders;
private String serverHeader;
private int maxHttpHeaderSize = 0 ; // bytes
private Duration connectionTimeout;
@NestedConfigurationProperty
private Ssl ssl;
@NestedConfigurationProperty
private final Compression compression = new Compression();
@NestedConfigurationProperty
private final Http2 http2 = new Http2();
private final Servlet servlet = new Servlet();
private final Tomcat tomcat = new Tomcat();
private final Jetty jetty = new Jetty();
private final Undertow undertow = new Undertow();
}
|
这个类的代码太多了,这里就不一一贴出来了,我们平常在 application.properties
中配置的server.xxx就是这个类中属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@Import
BeanPostProcessorsRegistrar
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if ( this .beanFactory == null ) {
return ;
}
registerSyntheticBeanIfMissing(registry,
"webServerFactoryCustomizerBeanPostProcessor" ,
WebServerFactoryCustomizerBeanPostProcessor. class );
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor" ,
ErrorPageRegistrarBeanPostProcessor. class );
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(
this .beanFactory.getBeanNamesForType(beanClass, true , false ))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic( true );
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
|
这个类注册了两个bean: WebServerFactoryCustomizerBeanPostProcessor
和 ErrorPageRegistrarBeanPostProcessor
关于这两个bean的作用稍后再详细介绍
- EmbeddedTomcat
1
2
3
4
5
6
7
8
9
10
11
|
@Configuration
@ConditionalOnClass ({ Servlet. class , Tomcat. class , UpgradeProtocol. class })
@ConditionalOnMissingBean (value = ServletWebServerFactory. class , search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
|
这个类会在存在Tomcat相关jar包时添加一个 TomcatServletWebServerFactory bean
其他两个相信大家都知道怎么回事了
除了这些这个类还注入了两个类 ServletWebServerFactoryCustomizer
和 TomcatServletWebServerFactoryCustomizer
现在前期准备工作已经做好了,看一下这个Tomcat是如何启动的吧
启动
启动入口在 ServletWebServerApplicationContext 中的 onRefresh 方法
1
2
3
4
5
6
7
8
9
|
protected void onRefresh() {
super .onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException( "Unable to start web server" , ex);
}
}
|
Tomcat的启动就在 createWebServer
方法里面了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
private void createWebServer() {
WebServer webServer = this .webServer;
ServletContext servletContext = getServletContext();
//第一次访问的时候两个对象都为空
if (webServer == null && servletContext == null ) {
ServletWebServerFactory factory = getWebServerFactory();
this .webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null ) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException( "Cannot initialize servlet context" ,
ex);
}
}
initPropertySources();
}
|
首先看一下 getWebServerFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
protected ServletWebServerFactory getWebServerFactory() {
// 这里获取的beanname就是上方注册的tomcatServletWebServerFactory了
String[] beanNames = getBeanFactory()
.getBeanNamesForType(ServletWebServerFactory. class );
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));
}
return getBeanFactory().getBean(beanNames[ 0 ], ServletWebServerFactory. class );
}
|
准备环境里注册的bean现在出来一个了。注意,上方还注册了一个后置处理器 EmbeddedServletContainerCustomizerBeanPostProcessor
,获取bean tomcatServletWebServerFactory
的时候就会执行后置处理器的 postProcessBeforeInitialization
方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof WebServerFactory) {
postProcessBeforeInitialization((WebServerFactory) bean);
}
return bean;
}
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
LambdaSafe
.callbacks(WebServerFactoryCustomizer. class , getCustomizers(),
webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor. class )
.invoke((customizer) -> customizer.customize(webServerFactory));
}
private Collection<WebServerFactoryCustomizer<?>> 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;
}
@SuppressWarnings ({ "unchecked" , "rawtypes" })
private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
return (Collection) this .beanFactory
.getBeansOfType(WebServerFactoryCustomizer. class , false , false ).values();
}
|
这个处理器的作用是获得所有定制器,然后执行定制器的方法
接着往下看
这个时候就可以启动Tomcat了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = ( this .baseDirectory != null ? this .baseDirectory
: createTempDir( "tomcat" ));
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector( this .protocol);
tomcat.getService().addConnector(connector);
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);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0 );
}
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null" );
this .tomcat = tomcat;
this .autoStart = autoStart;
initialize();
}
private void initialize() throws WebServerException {
TomcatWebServer.logger.info( "Tomcat initialized with port(s): " + getPortsDescription( false ));
synchronized ( this .monitor) {
try {
addInstanceIdToEngineName();
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource())
&& Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
// happen when the service is started.
removeServiceConnectors();
}
});
// Start the server to trigger initialization listeners
this .tomcat.start();
// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(),
getClass().getClassLoader());
}
catch (NamingException ex) {
// Naming is not enabled. Continue
}
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
startDaemonAwaitThread();
}
catch (Exception ex) {
throw new WebServerException( "Unable to start embedded Tomcat" , ex);
}
}
}
|
以上就是SpringBoot如何实现Tomcat自动配置的详细内容,更多关于SpringBoot实现Tomcat自动配置的资料请关注服务器之家其它相关文章!
原文链接:https://www.cicoding.cn/springboot/tomcat-auto-configuration-in-springboot/