返回

SpringBoot——Servlet容器启动解析

发布时间:2023-04-07 12:06:22 293
# java# java# 容器# 服务器# 工具

前言

SpringBoot1.x只区分web环境和非web环境,而在2.x版本中引入了Reactive环境,即响应式环境.那么现在SpringBoot支持三种环境: Servlet的web环境、Reactive的web环境以及非web环境。90%以上的公司使用的是Servlet的web环境,而该环境默认使用的是tomcat容器,本章内容主要就是介绍Servlet容器启动流程。

Tomcat 是什么

Tomcat 是由 Apache 开发的一个 Servlet 容器,实现了对 Servlet 和 JSP 的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全域管理和Tomcat阀等。

 

由于 Tomcat 本身也内含了一个 HTTP 服务器,它也可以被视作一个单独的 Web 服务器。但是,不能将 Tomcat 和 Apache HTTP 服务器混淆,Apache HTTP 服务器是一个用 C 语言实现的 HTTP Web 服务器;这两个 HTTP web server 不是捆绑在一起的。Tomcat 包含了一个配置管理工具,也可以通过编辑XML格式的配置文件来进行配置。

容器架构

容器处理

启动流程解析

在SpringApplication.run(Application.class,args)里面会构造一个SpringApplication对象,进入其构造函数中

public class SpringApplication {
	private WebApplicationType webApplicationType;

	public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//webApplicationType属性决定了后续容器启动是servlet还是reactive
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}
}

public enum WebApplicationType {

	/**
	 * The application should not run as a web application and should not start an
	 * embedded web server.
	 */
	NONE,

	/**
	 * The application should run as a servlet-based web application and should start an
	 * embedded servlet web server.
	 */
	SERVLET,

	/**
	 * The application should run as a reactive web application and should start an
	 * embedded reactive web server.
	 */
	REACTIVE;

	private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework." + "web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org." + "springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

	private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

	//通过判断Classpath路径下是否存在某些特定的类,来决定当前是什么样的环境
	static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}
}

在SpringApplication的run方法中,context = createApplicationContext()代表创建应用上下文,其就是根据属性webApplicationType来构造什么类

public class SpringApplication {

	/**
	 * The class name of application context that will be used by default for non-web
	 * environments.
	 */
	public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";

	/**
	 * The class name of application context that will be used by default for web
	 * environments.
	 */
	public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
			+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

	/**
	 * The class name of application context that will be used by default for reactive web
	 * environments.
	 */
	public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

	public ConfigurableApplicationContext run(String... args) {
		......
		try {
			......
				
			//创建应用上下文
			context = createApplicationContext();
			......
		}
		catch (Throwable ex) {
			......
		}

		......
		return context;
	}

	protected ConfigurableApplicationContext createApplicationContext() {
		Class contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
}

servlet容器启动是在refreshContext(context)方法当中,该方法最终会调用AbstractApplicationContext类中的refresh()方法,该方法会调用onRefresh()方法

private void refreshContext(ConfigurableApplicationContext context) {
	refresh(context);
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
}

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		......

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

			......
		}

		catch (BeansException ex) {
			......
		}

		finally {
			......
		}
	}
}

onRefresh()方法由子类实现,根据不同的应用上下文去调用不同的方法,这里为Servlet容器环境,所以调用ServletWebServerApplicationContext类中的onRefresh()方法

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
		implements ConfigurableWebServerApplicationContext {
	@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			//构建web服务器
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

	private void createWebServer() {
		// 刚开始这两个属性都为null
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			// 走到这步获取WebServerFactory
			ServletWebServerFactory factory = getWebServerFactory();
			//获取WebServerFactory的具体实现之后,调用getWebServer获取一个具体的WebServer,
			//默认调用TomcatServletWebServerFactory中的getWebServer()方法
			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();
	}

	protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		// 默认返回只有一个,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));
		}
		// 获得BeanFactory后调用getBean创建单例bean
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}
}
public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory
		implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
	// 调用此方法创建webServer
	@Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		// 创建一个tomcat
		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) {
		// 这步就创建一个TomcatWebServer,里面还会做一些事情......
		return new TomcatWebServer(tomcat, getPort() >= 0);
	}
}

接着看initPropertySources()方法

protected void initPropertySources() {
	ConfigurableEnvironment env = this.getEnvironment();
	if (env instanceof ConfigurableWebEnvironment) {
		((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, (ServletConfig)null);
	}
}

public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
	WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);
}

public static void initServletPropertySources(MutablePropertySources sources, @Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
	Assert.notNull(sources, "'propertySources' must not be null");
	String name = "servletContextInitParams";
	 // 判断servletContext不为null且包含这个servletContextInitParams属性集
	if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
		// 封装一个ServletContextPropertySource属性集替换原有的
		sources.replace(name, new ServletContextPropertySource(name, servletContext));
	}

	name = "servletConfigInitParams";
	// servletConfig默认为null
	if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
		sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
	}

}

这样就完成了webServer即Tomcat服务器的创建 在进入AbstractApplicationContext中refresh()方法中的finishRefresh()方法中,该方法会根据web容器的环境进行调用,这里会进入ServletWebServerApplicationContext类中的finishRefresh()方法中

@Override
protected void finishRefresh() {
	super.finishRefresh();
	//启动WebServer
	WebServer webServer = startWebServer();
	if (webServer != null) {
		// 发布Server初始完毕事件
		publishEvent(new ServletWebServerInitializedEvent(webServer, this));
	}
}

private WebServer startWebServer() {
	WebServer webServer = this.webServer;
	if (webServer != null) {
		webServer.start();
	}
	return webServer;
}

@Override
public void start() throws WebServerException {
	synchronized (this.monitor) {
		if (this.started) {
			return;
		}
		try {
			addPreviouslyRemovedConnectors();
			Connector connector = this.tomcat.getConnector();
			if (connector != null && this.autoStart) {
				performDeferredLoadOnStartup();
			}
			checkThatConnectorsHaveStarted();
			this.started = true;
			logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
					+ getContextPath() + "'");
		}
		catch (ConnectorStartFailedException ex) {
			stopSilently();
			throw ex;
		}
		catch (Exception ex) {
			throw new WebServerException("Unable to start embedded Tomcat server", ex);
		}
		finally {
			Context context = findContext();
			ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
		}
	}
}

启动前准备

webServer创建入口

servlet启动

web容器工厂类加载解析

默认返回只有一个TomcatServletWebServerFactory,那么这个bean定义什么时候被加载到容器中

String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);

它是通过ConfigurationClassParser类中的parse方法,通过@Import注解导入到容器中的

class ConfigurationClassParser {
	public void parse(Set configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		// 这边会处理@Import注解导入的配置类
		this.deferredImportSelectorHandler.process();
	}
}
class ConfigurationClassParser {
	private class DeferredImportSelectorHandler {

		public void process() {
			List deferredImports = this.deferredImportSelectors;
			this.deferredImportSelectors = null;
			try {
				if (deferredImports != null) {
					DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
					deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
					// 排序并依此遍历调用register方法
					deferredImports.forEach(handler::register);
					handler.processGroupImports();
				}
			}
			finally {
				this.deferredImportSelectors = new ArrayList<>();
			}
		}

	}
}
class ConfigurationClassParser {
	private class DeferredImportSelectorGroupingHandler {
		private final Map groupings = new LinkedHashMap<>();

		private final Map configurationClasses = new HashMap<>();

		public void register(DeferredImportSelectorHolder deferredImport) {
			// 这个返回的Selector就是AutoConfigurationImportSelector,这也是@SpringBootApplication上通过@Import注解
			// 导入的Selector. getImportGroup返回的是AutoConfigurationGroup.class
			Class group = deferredImport.getImportSelector()
					.getImportGroup();
			// computeIfAbsent就是不存在就创建,这边也是创建一个grouping
			DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
					(group != null ? group : deferredImport),
					key -> new DeferredImportSelectorGrouping(createGroup(group)));
			// this.deferredImports.add(deferredImport);
			// 加入到了deferredImports中,List deferredImports = new ArrayList<>()
			grouping.add(deferredImport);
			 // 放入到configurationClasses中
			this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getConfigurationClass());
		}
	}
}

deferredImports.forEach(handler::register),这边主要是构造了一个grouping,在下一步进行处理handler.processGroupImports()

public void processGroupImports() {
	for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
		// 下面先分析这个getImports方法
		grouping.getImports().forEach(entry -> {
			ConfigurationClass configurationClass = this.configurationClasses.get(
					entry.getMetadata());
			try {
				processImports(configurationClass, asSourceClass(configurationClass),
						asSourceClasses(entry.getImportClassName()), false);
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
								configurationClass.getMetadata().getClassName() + "]", ex);
			}
		});
	}
}

public Iterable getImports() {
	// 这边的deferredImports是通过grouping.add(deferredImport)添加进去的
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	return this.group.selectImports();
}

// 两个参数如下图所示,annotationMetadata是主配置类上面的注解
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
			() -> String.format("Only %s implementations are supported, got %s",
					AutoConfigurationImportSelector.class.getSimpleName(),
					deferredImportSelector.getClass().getName()));
	// 下面先分析下这个getAutoConfigurationEntry方法
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
			.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
	this.autoConfigurationEntries.add(autoConfigurationEntry);
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		// 接着依次遍历放入到这个map中,Map entries = new LinkedHashMap()
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}

这边就到了AutoConfigurationImportSelector类的getAutoConfigurationEntry方法中

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
		AnnotationMetadata annotationMetadata) {
	// 判断是否支持自动配置
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	// 这个attributes属性就是上图中显示的,用来过滤自动配置类的
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	// 下面分析这个方法,这个就是加载容器中的自动配置类
	List configurations = getCandidateConfigurations(annotationMetadata, attributes);
	// 去除重复的,方法就是放入set再放入list中
	configurations = removeDuplicates(configurations);
	// 去除掉应该被排除的
	Set exclusions = getExclusions(annotationMetadata, attributes);
	checkExcludedClasses(configurations, exclusions);
	configurations.removeAll(exclusions);
	// 通过filter过滤,下面分析,过滤完发现只有22个了
	configurations = filter(configurations, autoConfigurationMetadata);
	// 发布一个事件,好像没有做啥关键的
	fireAutoConfigurationImportEvents(configurations, exclusions);
	// 将configurations封装成AutoConfigurationEntry返回
	return new AutoConfigurationEntry(configurations, exclusions);
}

protected boolean isEnabled(AnnotationMetadata metadata) {
	if (getClass() == AutoConfigurationImportSelector.class) {
		// 判断有没有配置这个属性,没有的话默认为true,
		// String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
		return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
	}
	return true;
}

通过filter方法过滤,过滤完发现只有22个了

private List filter(List configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
	long startTime = System.nanoTime();
	String[] candidates = StringUtils.toStringArray(configurations);
	boolean[] skip = new boolean[candidates.length];
	boolean skipped = false;
	for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
		invokeAwareMethods(filter);
		boolean[] match = filter.match(candidates, autoConfigurationMetadata);
		for (int i = 0; i < match.length; i++) {
			if (!match[i]) {
				skip[i] = true;
				candidates[i] = null;
				skipped = true;
			}
		}
	}
	if (!skipped) {
		return configurations;
	}
	List result = new ArrayList<>(candidates.length);
	for (int i = 0; i < candidates.length; i++) {
		if (!skip[i]) {
			result.add(candidates[i]);
		}
	}
	if (logger.isTraceEnabled()) {
		int numberFiltered = configurations.size() - result.size();
		logger.trace("Filtered " + numberFiltered + " auto configuration class in "
				+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
	}
	return new ArrayList<>(result);
}

protected List getAutoConfigurationImportFilters() {
	// 看一下这个过滤的逻辑,看下图它的实现类大概就知道它是怎样过滤了
	return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}

过滤完之后会发现此时List configurations集合中有29个,其中有一个org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		// 会Import一个这个
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
	......
}
@Configuration
class ServletWebServerFactoryConfiguration {

	@Configuration
	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
	@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
	public static class EmbeddedTomcat {

		@Bean
		public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
			// 这边就会创建一个TomcatServletWebServerFactory
			return new TomcatServletWebServerFactory();
		}

	}
}

到此为止grouping.getImports方法分析完了,它是返回之前加载的29个自动配置类

class ConfigurationClassParser {
	private class DeferredImportSelectorGroupingHandler {
		public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				grouping.getImports().forEach(entry -> {
					// 这边这个configurationClass获取的还是主配置类SpringbootApplication
					ConfigurationClass configurationClass = this.configurationClasses.get(
							entry.getMetadata());
					try {
						processImports(configurationClass, asSourceClass(configurationClass),
								asSourceClasses(entry.getImportClassName()), false);
					}
					catch (BeanDefinitionStoreException ex) {
						throw ex;
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
					}
				});
			}
		}
	}
}

web容器个性化配置解析

属性注入

工厂类初始化

BeanPostProcessor方法实现

定制化流程

入口,onRefresh方法中会创建webServer,走到这里

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
		implements ConfigurableWebServerApplicationContext {
	protected ServletWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
		// 默认返回只有一个,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));
		}
		// 调用getBean创建工厂类实例,这边会调用getBean开始创建bean实例对象
		return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
	}
}

在Bean初始化完成之后会遍历BeanFactory中所有的BeanPostProcessor实现,依次调用BeanPostProcessor接口的postProcessBeforeInitialization方法,在创建Web服务的工厂类的时候也会经历这个步骤,这个方法调用点就在AbstractAutowireCapableBeanFactory类中applyBeanPostProcessorsBeforeInitialization()方法

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			// 通过断点调试可以发现当中有一个WebServerFactoryCustomizerBeanPostProcessor
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
}

可以看到postProcessBeforeInitialization方法多个实现中有一个WebServerFactoryCustomizerBeanPostProcessor 点击进入WebServerFactoryCustomizerBeanPostProcessor类中的postProcessBeforeInitialization方法

public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (bean instanceof WebServerFactory) {
			postProcessBeforeInitialization((WebServerFactory) bean);
		}
		return bean;
	}

	private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
		// 先看下getCustomizers方法
		// 这边lamda表达式的意思就是遍历getCustomizers方法,通过invoke调用每个customizer.cutomize方法定制修改web容器
		LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
				.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
				.invoke((customizer) -> customizer.customize(webServerFactory));
	}

	private Collection> getCustomizers() {
		if (this.customizers == null) {
			// Look up does not include the parent context
			// 获取容器中的所有WebServerFactoryCustomizer
			this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
			this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.customizers = Collections.unmodifiableList(this.customizers);
		}
		return this.customizers;
	}

	private Collection> getWebServerFactoryCustomizerBeans() {
		return (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
	}
}

我们在来看下图中第二个定制器,ServletWebServerFactoryCustomizer是怎么注入的呢?

@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 {

	// 通过ServletWebServerFactoryAutoConfiguration的bean方法引入到的,
    // 并且赋值serverProperties
	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
		return new ServletWebServerFactoryCustomizer(serverProperties);
	}
}
//这就是我们在application.properties中修改port,会被赋值到这里,然后定制器就可以取到
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

	/**
	 * Server HTTP port.
	 */
	private Integer port;

	/**
	 * Network address to which the server should bind.
	 */
	private InetAddress address;
	......
}
// 然后我们再来看invoke((customizer) -> customizer.customize(webServerFactory))这个步骤,这会调用每个定制器的定制方法
// 具体我们看下ServletWebServerFactoryCustomizer的cutomize方法
public class ServletWebServerFactoryCustomizer
		implements WebServerFactoryCustomizer, Ordered {

	private final ServerProperties serverProperties;

	public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
		this.serverProperties = serverProperties;
	}

	@Override
	public int getOrder() {
		return 0;
	}

	@Override
	public void customize(ConfigurableServletWebServerFactory factory) {
		PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
		// 这边是lamda表达式,调用factory.setPort进行赋值
		map.from(this.serverProperties::getPort).to(factory::setPort);
		map.from(this.serverProperties::getAddress).to(factory::setAddress);
		map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
		map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
		map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
		map.from(this.serverProperties::getSsl).to(factory::setSsl);
		map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
		map.from(this.serverProperties::getCompression).to(factory::setCompression);
		map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
		map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
		map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
	}

}

参考: https://my.oschina.net/liwanghong/blog/3168322

https://www.cnblogs.com/hggen/p/6264475.html

https://www.cnblogs.com/jingmoxukong/p/8258837.html

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
SpringBoot——配置类解析 2023-04-07 09:08:35