SpringBoot嵌入式Servlet配置原理
阿新 • • 發佈:2020-02-23
SpringBoot嵌入式Servlet配置原理
SpringBoot修改伺服器配置
- 配置檔案方式方式修改,實際修改的是ServerProperties檔案中的值
server.servlet.context-path=/crud
server.port=8081
Java
程式碼方式修改。通過實現WebServerFactoryCusomizer
介面來獲取到達ConfigurableServletWebServerFactory
的通道,ConfigurableServletWebServerFactory
中提供了很多的方法用來修改伺服器配置。
@Component public class ServletHandler implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> { @Override public void customize(ConfigurableServletWebServerFactory factory) { factory.setPort(8083); } }
SpringBoot使用原生web元件
在之前的Web專案中,我們會通過web.xml來註冊三大元件,在springboot中我們通過提供的類註冊三大元件
- Servlet。通過
ServletRegistrationBean
來註冊一個Servlet
@Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean registration = new ServletRegistrationBean(new MyServlet(),"/hello"); return registration; }
- Filter。通過
FilterRegistrationBean
來祖冊Filter
@Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new MyFilter()); filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello")); return filterRegistrationBean ; }
- Listener。通過
ServletListenerRegistrationBean
來註冊一個監聽器
@Bean
public ServletListenerRegistrationBean myServletListener(){
ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean();
registrationBean.setListener(new MyServletContextListener());
return registrationBean ;
}
Spring使用其他伺服器
SpringBoot提供了三個伺服器工廠,Tomcat,Jetty,Undertow,預設使用了Tomcat
- 使用Jetty。需要排除Tomcat依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
- 使用
Undertow
伺服器。同Jetty一樣
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<artifactId>spring-boot-starter-undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
SpringBoot伺服器自動配置原理
Springboot
通過WebServerInitializedEvent
來實現伺服器自動配置,通過這個類來載入一個WebServer
public abstract class WebServerInitializedEvent extends ApplicationEvent {
protected WebServerInitializedEvent(WebServer webServer) {
super(webServer);
}
- 通過
WebServer
來建立固定的伺服器。TomcatWebServer
JettyWebServer
NettyWebServer
UndertowWebServer
public interface WebServer {
void start() throws WebServerException;
void stop() throws WebServerException;
int getPort();
}
SpringBoot啟動Tomcat伺服器的過程
SpringBoot
啟動方法
SpringApplication.run(DemoApplication.class, args)
- 呼叫
SpringAllication.run
方法返回了ConfigurableApplicationContext
物件
public ConfigurableApplicationContext run(String... args) {
context = this.createApplicationContext();//建立了一個Application物件
this.refreshContext(context);//重新整理ApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
- 建立了
AnnotationConfigReactiveWebServerApplicationContext
這個類最終實現了AbstractApplicationContext
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
//呼叫子類的重新整理方法,最終呼叫的是建立ApplicationContext容器中所選擇的容器即ServletWebServerApplicationContext類中的方法
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
protected void onRefresh() {
super.onRefresh();
try {
//建立了web容器
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
//當容器中沒有伺服器的時候
if (webServer == null && servletContext == null) {
//建立一個web伺服器,
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
throw new ApplicationContextException("Cannot initialize servlet context", var4);
}
}
this.initPropertySources();
}
protected ServletWebServerFactory getWebServerFactory() {
//獲取了容器中ServletWebServerFactory型別的容器
String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
} else if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
} else {
//建立了web伺服器
return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
}
- 通過
this.getWebServerFactory
方法建立了web伺服器,通過this.getBeanFactory()
獲取了容器中所存在的型別為ServletWebServerFactory
型別的容器,然後獲取bean
建立了Tomcat
物件