springboot采用大量的自动配置,开发者通过少量的配置,就可开发spring应用,可以用来开发单个微服务应用,下面来介绍一下springboot的内置servlet的原理。
导入相关依赖:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.3.RELEASEversion>
<relativePath/>
parent>
<groupId>com.kuakegroupId>
<artifactId>springboot02-logartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot02-logname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
找到与内置容器先关的自动配置类,我们知道spring-boot
的配置类都在spring-boot-autoconfigure-xxx.RELEASE.jar
包下,进入web相关的自动配置类,里面有一个配置类叫做EmbeddedServletContainerAutoConfiguration
,翻译也就是嵌入式的servlet容器的自动配置类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
/**
* Nested configuration if Tomcat is being used.
*/
@Configuration
//判断是否缺少相关jar 如果没有就不创建 springboot默认是支持 tomcat的
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@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
//判断是否缺少相关jar 如果没有就不创建
@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
//判断是否缺少相关jar 如果没有就不创建
@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();
}
}
springboot支持三个内置容器 分别是Tomcat,Jetty,Undertow,默认支持的是Tomcat容器
因为有tomcat的相关jar包,所以容器在启动过程中会创建一个TomcatEmbeddedServletContainerFactory
//创建出一个Tomcat容器的生产工厂
@Configuration
//判断是否缺少相关jar 如果没有就不创建 springboot默认是支持 tomcat的
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
注意在这个类的顶部还有一个注解:@Import(BeanPostProcessorsRegistrar.class)
导入了一个类到容器中,看一下这个类的源码:
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);
}
}
}
在这个类中(上图),有一个很重要的方法registerBeanDefinitions
方法中定义了一个类EmbeddedServletContainerCustomizerBeanPostProcessor
在容器中,容器中某组件要创建ContainerFactory对象就会惊动动这个后置处理器EmbeddedServletContainerCustomizerBeanPostProcessor,详细的后面解释
总结一下自动配置干了啥:
1、往容器中添加了一个TomcatEmbeddedServletContainerFactory
2、通过注解添加了EmbeddedServletContainerCustomizerBeanPostProcessor,与容器自定义相关的后置处理器
(简要记录一下几个主要的方法)
1)、SpringBoot应用启动运行run方法
@SpringBootApplication
public class MicroCloudServiceConsumer80Application {
public static void main(String[] args) {
SpringApplication.run(MicroCloudServiceConsumer80Application.class,args);
}
2)、创建SpringApplication
//
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
其中new SpringApplication(sources)
initialize(sources);
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
// 判断是否为web应用
this.webEnvironment = deduceWebEnvironment();
// 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener;然后保存起来
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 从配置类中找到有main主方法的配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// 从类路径下找到META-INF/spring.factories配置的所有SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
// 调用所有监听器的start()方法
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 表示准备环境 并且当环境准备好之后 调用所有的listener#environmentPrepared 表示环境准备完成
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
// 根据webEnvironment判断是创建普通ioc容器 还是web的ioc容器
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
// 准备容器 (主要作用如下:)
// 1、设置context中添加environment
// 2、回调所有ApplicationContextInitializer#initialize方法
// 3、回调所有listener#contextPrepared(context)方法
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 刷新容器 扫描加载组件 bean等 tomcat容器也就这里面被启动的,稍后介绍
refreshContext(context);
// 刷新完成之后
// 从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
// ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context, applicationArguments);
// 回调所有listener#finished(context, exception)方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 返回ioc容器
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
重要的refreshContext(context)
方法 这个方法很熟悉,就是传统spring里面的容器刷新方法(以后有时间要记录一下其中每一个方法的作用)
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();
}
3)、执行onRefresh()
方法
上面这些方法中 onRefresh()
方法是留个子类去实现,然后再回调的,我们用debug
模式执行到此处,是调用哪一个方法(debug模式,进入下面代码)
@Override
protected void onRefresh() {
super.onRefresh();
try {
// 创建EmbeddedServletContainer
createEmbeddedServletContainer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container",
ex);
}
}
createEmbeddedServletContainer
源码如下:
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
ServletContext localServletContext = getServletContext();
// 因为第一次访问 所以localContainer 和localServletContext都为null
if (localContainer == null && localServletContext == null) {
// 从容器中获得EmbeddedServletContainerFactory 所以容器创建该对象的时候
// 对应的后置处理器(EmbeddedServletContainerCustomizerBeanPostProcessor)会执行相关操作 稍后记录
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();
}
获得容器containerFactory.getEmbeddedServletContainer
代码如下:
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
// 创建一个tomcat
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null ? this.baseDirectory
: createTempDir("tomcat"));
// 设置路径属性 下面的方法都是对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);
// 获得嵌入式的tomcat容器 并且有一句代码:this.tomcat.start()启动tomcat
return getTomcatEmbeddedServletContainer(tomcat);
}
我们在回过头看一下EmbeddedServletContainerCustomizerBeanPostProcessor
这个后置处理器有什么作用:
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
// 调用每一个EmbeddedServletContainerCustomizer#customize方法
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// 获得容器中所有的EmbeddedServletContainerCustomizerr容器自定义器 用来定制servlet容器
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
这个后置处理器的作用就是,获得所有定制器,然后执行定制器的方法。(可以往容器中添加一个EmbeddedServletContainerCustomizer)来定制嵌入式容器
总结:
1、执行EmbeddedWebApplicationContext的onRefresh()中的createEmbeddedServletContainer()
2、从容器中获得工厂getEmbeddedServletContainerFactory()【TomcatEmbeddedServletContainerFactory创建对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置】
3、containerFactory.getEmbeddedServletContainer(getSelfInitializer())方法,创建tomcat容器,并且启动【this.tomcat.start()】