SprBoot Embedded Servlet Container Automatic Configuration Principle

Keywords: Tomcat Spring SpringBoot Jetty

1. Automatic Configuration Principle of Embedded Servlet Container

Embedded Servlet Container AutoConfiguration: Automatic Configuration of Embedded Servlet Containers

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//Import BeanPost Processors Registrar: Spring annotation; import some components into the container
//Import Embedded Servlet Container Customizer Bean PostProcessor:
//Post Processor: Before and after bean initialization (object creation, not assignment) to perform initialization
public class EmbeddedServletContainerAutoConfiguration {
    
    @Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class })//Determine whether Tomcat dependencies are currently introduced;
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//Judging that the current container does not have user-defined Embedded Servlet Container Factory: Embedded Servlet Container Factory; Role: Create Embedded Servlet Container
	public static class EmbeddedTomcat {

		@Bean
		public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
			return new TomcatEmbeddedServletContainerFactory();
		}

	}
    
    /**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
			WebAppContext.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedJetty {

		@Bean
		public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
			return new JettyEmbeddedServletContainerFactory();
		}

	}

	/**
	 * Nested configuration if Undertow is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedUndertow {

		@Bean
		public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
			return new UndertowEmbeddedServletContainerFactory();
		}

	}

1) Embedded Servlet Container Factory (Embedded Servlet Container Factory)

public interface EmbeddedServletContainerFactory {

   //Getting Embedded Servlet Containers
   EmbeddedServletContainer getEmbeddedServletContainer(
         ServletContextInitializer... initializers);

}

Embedded Servlet Container: (Embedded Servlet Container)


3) Take Tomcat Embedded Servlet Container Factory as an example

@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
      ServletContextInitializer... initializers) {
    //Create a Tomcat
   Tomcat tomcat = new Tomcat();
    
    //Basic links for configuring 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);
    
    //Pass in the configured Tomcat, return an Embedded Servlet Container, and start the Tomcat server
   return getTomcatEmbeddedServletContainer(tomcat);
}

4) How does the configuration modification of the embedded container work?

ServerProperties,EmbeddedServletContainerCustomizer

Embedded Servlet Container Customizer: Customizer helps us modify the configuration of Servlet containers

Principle of modification:
5) Import Embedded Servlet Container Customizer Bean PostProcessor into the container

//Before initialization
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    //If the current initialization is a component of Configurable Embedded ServletContainer type
   if (bean instanceof ConfigurableEmbeddedServletContainer) {
       //
      postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
   }
   return bean;
}

private void postProcessBeforeInitialization(
			ConfigurableEmbeddedServletContainer bean) {
    //Get all the customizers and call the customize method of each customizer to assign attributes to the Servlet container.
    for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
        customizer.customize(bean);
    }
}

private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
    if (this.customizers == null) {
        // Look up does not include the parent context
        this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
            this.beanFactory
            //Get all components of this type from the container: Embedded Servlet Container Customizer
            //Customize the Servlet container to add an Embedded Servlet Container Customizer-type component to the container
            .getBeansOfType(EmbeddedServletContainerCustomizer.class,
                            false, false)
            .values());
        Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
        this.customizers = Collections.unmodifiableList(this.customizers);
    }
    return this.customizers;
}

Steps:

1) SpringBoot adds the corresponding Embedded Servlet Container Factory to the container according to the dependency of the import.

2) A component in the container will start the post processor if it wants to create an object; Embedded Servlet Container Customizer Bean PostProcessor;

As long as it is an embedded Servlet container factory, the post processor will work.

3) Postprocessor, get all Embedded Servlet Container Customizer from container, call customization method of customizer

5) Embedded Servlet Container Startup Principle

When will an embedded Servlet container factory be created? When to get the embedded Servlet container and start Tomcat?

Get the embedded Servlet container factory:

1) SpringBoot Application Start run Method

2), refreshContext (context); SpringBook refreshes IOC container (create IOC container object, initialize container, create each component in container); If a web application creates Annotation Config Embedded Web Application Context, otherwise: Annotation Config Application Context

3) refresh(context); refresh the ioc container just created;

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

4) onRefresh (); the ioc container of the web rewrites the onRefresh method

5) webioc container will create embedded Servlet container; create Embedded Servlet Container ();

6) Get the Embedded Servlet Container Factory:

EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

Get the Embedded Servlet ContainerFactory component from the ioc container; Tomcat Embedded Servlet ContainerFactory creates an object, and as soon as the post processor sees this object, it gets all the customizers to customize the configuration of the Servlet container first.

7) Get embedded Servlet containers using container factories: this. embedded Servlet Container = containerFactory. getEmbedded Servlet Container (getSelfInitializer ());

8) The embedded Servlet container creates objects and starts the Servlet container;

Firstly, the embedded Servlet container is started, and then the remaining objects in the ioc container are retrieved.

IOC Container Start to Create Embedded Servlet Container

Posted by zerogreen on Thu, 05 Sep 2019 22:51:26 -0700