准备工作
我们知道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/