好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

SpringBoot如何实现Tomcat自动配置

准备工作

我们知道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://HdhCmsTestcicoding.cn/springboot/tomcat-auto-configuration-in-springboot/

查看更多关于SpringBoot如何实现Tomcat自动配置的详细内容...

  阅读:18次