1. 程式人生 > >Spring Boot 嵌入式 Servlet 容器自動配置原理

Spring Boot 嵌入式 Servlet 容器自動配置原理

Spring Boot 做 嵌入式 Servlet 容器自動配置的原始碼包:EmbeddedServletContainerAutoConfiguration

原始碼如下:

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {

	/**
	 * Nested configuration if Tomcat is being used.
	 */
	@Configuration
	//判斷當前專案是否引入了 Tomcat 依賴, 如果引入了 Tomcat 依賴,就建立 Tomcat 工廠
	@ConditionalOnClass({ Servlet.class, Tomcat.class })
	//判斷當前容器中沒有 EmbeddedServletContainerFactory(嵌入式的容器工廠, 作用就是建立 Servlet 容器) 元件就自己建立
	@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedTomcat {

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

	}

	/**
	 * Nested configuration if Jetty is being used.
	 */
	@Configuration
     //判斷當前專案是否引入了 Jetty 依賴, 如果引入了 Jetty 依賴,就建立 Jetty 工廠
	@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
	//判斷當前專案是否引入了 Undertow 依賴, 如果引入了 Undertow 依賴,就建立 Undertow 工廠
	@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();
		}

	}

	/**
	 * Registers a {@link EmbeddedServletContainerCustomizerBeanPostProcessor}. 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, "embeddedServletContainerCustomizerBeanPostProcessor", EmbeddedServletContainerCustomizerBeanPostProcessor.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);
			}
		}
	}

}

EmbeddedServletContainerFactory(嵌入式的容器工廠, 作用就是建立 Servlet 容器) 原始碼:

public interface EmbeddedServletContainerFactory {

	/**
	 * Gets a new fully configured but paused {@link EmbeddedServletContainer} instance.
	 * Clients should not be able to connect to the returned server until
	 * {@link EmbeddedServletContainer#start()} is called (which happens when the
	 * {@link ApplicationContext} has been fully refreshed).
	 * @param initializers {@link ServletContextInitializer}s that should be applied as
	 * the container starts
	 * @return a fully configured and started {@link EmbeddedServletContainer}
	 * @see EmbeddedServletContainer#stop()
	 */
	 //獲取嵌入式的 Servlet 容器
	EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers);

}

在這裡插入圖片描述 EmbeddedServletContainer(獲取嵌入式的 Servlet 容器):

在這裡插入圖片描述

Toncat 嵌入式容器工廠(TomcatEmbeddedServletContainerFactory) 部分原始碼:

@Override
public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {
	//建立一個 Toncat
	Tomcat tomcat = new Tomcat();
	/**** Start  配置 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);
	/**** End  配置 Tomcat 工作的基本環節   ***/
	//將配置好的 Tomcat 傳入進去,返回一個嵌入式的 Servlet 容器, 並且啟動 Tomcat 伺服器
	return getTomcatEmbeddedServletContainer(tomcat);
}

getTomcatEmbeddedServletContainer(tomcat) 方法執行原始碼:

public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
	Assert.notNull(tomcat, "Tomcat Server must not be null");
	this.tomcat = tomcat;
	this.autoStart = autoStart;
	initialize();
}

private void initialize() throws EmbeddedServletContainerException {
	TomcatEmbeddedServletContainer.logger
			.info("Tomcat initialized with port(s): " + getPortsDescription(false));
	synchronized (this.monitor) {
		try {
			addInstanceIdToEngineName();
			try {
				final Context context = findContext();
				context.addLifecycleListener(new LifecycleListener() {

					@Override
					public void lifecycleEvent(LifecycleEvent 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
				// ************************* 啟動 Tomcat **************************
				this.tomcat.start();

				// We can re-throw failure exception directly in the main thread
				rethrowDeferredStartupExceptions();

				try {
					ContextBindings.bindClassLoader(context, getNamingToken(context),
							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) {
				containerCounter.decrementAndGet();
				throw ex;
			}
		}
		catch (Exception ex) {
			stopSilently();
			throw new EmbeddedServletContainerException(
					"Unable to start embedded Tomcat", ex);
		}
	}
}

自己對嵌入式容器配置的修改是怎麼生效的?

第一種配置檔案的方式,第二種嵌入式容器定製器(EmbeddedServletContainerCustomizer)

兩種方式實際上都用的是EmbeddedServletContainerCustomizer,那麼肯定就是 EmbeddedServletContainerCustomizer幫我們修改了嵌入式容器的配置。

幫我們修改嵌入式容器的配置原理:   此文最開頭

//匯入 BeanPostProcessorsRegistrar,作用: 給容器中匯入一些元件
//匯入了 EmbeddedServletContainerCustomizerBeanPostProcessor 後置處理器
//後置處理器: 在 bean 初始化前後(剛建立完物件,還沒屬性賦值)執行初始化工作
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {

BeanPostProcessorsRegistrar 原始碼如下

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,
					"embeddedServletContainerCustomizerBeanPostProcessor",
					EmbeddedServletContainerCustomizerBeanPostProcessor.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);
			}
		}

	}

EmbeddedServletContainerCustomizerBeanPostProcessor 原始碼如下:

public class EmbeddedServletContainerCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

	private ListableBeanFactory beanFactory;

	private List<EmbeddedServletContainerCustomizer> customizers;

	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
				"EmbeddedServletContainerCustomizerBeanPostProcessor can only be used "
						+ "with a ListableBeanFactory");
		this.beanFactory = (ListableBeanFactory) beanFactory;
	}
	
	//初始化之前
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		//如果當前初始化的是一個 ConfigurableEmbeddedServletContainer 型別的元件, 就呼叫 postProcessBeforeInitialization方法
		if (bean instanceof ConfigurableEmbeddedServletContainer) {
			postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		return bean;
	}
	
	private void postProcessBeforeInitialization(ConfigurableEmbeddedServletContainer bean) {
		//獲取所有的定製器, 呼叫每一個 定製器的 customizer 方法給Servlet 容器屬性賦值
		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>(
					//從容器中獲取所有的這個型別(EmbeddedServletContainerCustomizer)的元件
					//定製 Servlet 容器, 給容器中可以新增一個 EmbeddedServletContainerCustomizer 型別的元件
					this.beanFactory
							.getBeansOfType(EmbeddedServletContainerCustomizer.class,
									false, false)
							.values());
			Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
			this.customizers = Collections.unmodifiableList(this.customizers);
		}
		return this.customizers;
	}

}

總結: 1)、Spring Boot 根據匯入的依賴情況, 給容器中新增響應的嵌入式容器工廠(EmbeddedServletContainerFactory:TomcatEmbeddedServletContainerFactory)

2)、容器中某個元件要建立物件就會呼叫 後置處理器: EmbeddedServletContainerCustomizerBeanPostProcessor

只要是嵌入式的 Servlet 容器工廠,後置處理器就工作

3)、後置處理器,從容器中獲取的 EmbeddedServletContainerCustomizer,呼叫定製器的定製方法