servlet自动配置是EmbeddedServletContainerAutoConfiguration,我们以tomcat容器来分析一下这个类代码
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
自动导入BeanPostProcessorsRegistrar,我们修改servlet配置通过这个类生效
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
这个是tomcat容器
@Configuration
必须存在类tomcat.class
@ConditionalOnClass({ Servlet.class, Tomcat.class })
如果不存在EmbeddedServletContainerFactory则配置tomcat服务器
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
配置类返回了TomcatEmbeddedServletContainerFactory,这个类继承了AbstractEmbeddedServletContainerFactory,而它实现了EmbeddedServletContainerFactory,
public interface EmbeddedServletContainerFactory {
EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers);
这里面只有一个方法getEmbeddedServletContainer,所以我们需要查看TomcatEmbeddedServletContainerFactory中对这个方法的重写
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
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 getTomcatEmbeddedServletContainer(tomcat);
}
这个方法创建了tomcat对象,并且设置了它的属性,最后返回了EmbeddedServletContainer,我们查看一下方法getTomcatEmbeddedServletContainer
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 {
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
try {
removeServiceConnectors();
this.tomcat.start();
rethrowDeferredStartupExceptions();
Context context = findContext();
try {
ContextBindings.bindClassLoader(context, getNamingToken(context),
getClass().getClassLoader());
}
catch (NamingException ex) {
}
startDaemonAwaitThread();
}
catch (Exception ex) {
containerCounter.decrementAndGet();
throw ex;
}
}
catch (Exception ex) {
throw new EmbeddedServletContainerException(
"Unable to start embedded Tomcat", ex);
}
}
}
这个方法里创建tomcat对象的最后启动了tomcat容器this.tomcat.start();
下面来介绍一下我们修改servlet容器是在哪里生效的,我们看看类BeanPostProcessorsRegistrar
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
registerSyntheticBeanIfMissing(registry,
"embeddedServletContainerCustomizerBeanPostProcessor",
EmbeddedServletContainerCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
这里注册了类EmbeddedServletContainerCustomizerBeanPostProcessor,这个类就是servlet属性的定制类,它实现了BeanPostProcessor,这个类的作用是在创建bean实例前后可以对修改bean的属性,这里对前置方法postProcessBeforeInitialization进行了重写,前置方法里调用了EmbeddedServletContainerCustomizer的customize,所以我们对容器配置的修改就生效了
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ConfigurableEmbeddedServletContainer) {
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
这里获取了所有的EmbeddedServletContainerCustomizer,进行了调用customize
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
我们在application.properties中修改servlet属性,ServerProperties同样实现了EmbeddedServletContainerCustomizer
启动web服务时会创建GenericWebApplicationContext,而我们的servlet容器EmbeddedWebApplicationContext继承了GenericWebApplicationContext,在重写方法里有个onrefresh,这个方法是bean容器的扩展方法,在这个方法里创建了EmbeddedServletContainerFactory
@Override
protected void onRefresh() {
super.onRefresh();
try {
createEmbeddedServletContainer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container",
ex);
}
}
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
ServletContext localServletContext = getServletContext();
if (localContainer == null && localServletContext == null) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
}
else if (localServletContext != null) {
try {
getSelfInitializer().onStartup(localServletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
这里创建了EmbeddedServletContainerFactory,而tomcat容器实现了这个类,所以在这时创建tomcat对象的过程就执行了,从而就启动了tomcat