通用的servlet容器配置 server.xx= 通用的Tomcat配置 server.tomcat.xx=
2.編寫一個嵌入式Servlet容器定製器來修改Servlet容器的配置
在SpringBoot中會有xxxCustomizer來進行擴展配置,注意學習!!前端
@Configuration public class MyServerConfig { // 註冊Servlet組件 @Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean servletRegistrationBean=new ServletRegistrationBean(new MyServlet(),"/my"); return servletRegistrationBean; } }
2.FilterRegistrationBeanjava
@Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(); filterRegistrationBean.setFilter(new MyFilter()); filterRegistrationBean.setUrlPatterns(Arrays.asList("/my")); return filterRegistrationBean; }
3.ServletListenerRegistrationBeanweb
@Bean public ServletListenerRegistrationBean myListener(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener()); return registrationBean; }
SpringBoot自動配置SpringMVC時,自動註冊SpringMVC的前端控制器:DispatcherServlet.spring
@Configuration @Conditional({DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition.class}) @ConditionalOnClass({ServletRegistration.class}) @EnableConfigurationProperties({WebMvcProperties.class}) @Import({DispatcherServletAutoConfiguration.DispatcherServletConfiguration.class}) protected static class DispatcherServletRegistrationConfiguration { private final WebMvcProperties webMvcProperties; private final MultipartConfigElement multipartConfig; public DispatcherServletRegistrationConfiguration(WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfigProvider) { this.webMvcProperties = webMvcProperties; this.multipartConfig = (MultipartConfigElement)multipartConfigProvider.getIfAvailable(); } @Bean( name = {"dispatcherServletRegistration"} ) @ConditionalOnBean( value = {DispatcherServlet.class}, name = {"dispatcherServlet"} ) public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet) { DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, this.webMvcProperties.getServlet().getPath()); //能夠經過修改servletpath來修改SpringMVC前端控制器默認攔截的請求路徑 registration.setName("dispatcherServlet"); registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup()); if (this.multipartConfig != null) { registration.setMultipartConfig(this.multipartConfig); } return registration; } }
- 注入Bean的幾種方式:
- @Bean註解
- 包掃描:
- @Controller
- @Service
- @Repository
- @Component
- @Import:
- 實現ImportSelector接口的類
- 實現ImportBeanDefinitionRegistry接口
- 實現FactoryBean
<dependency> <artifactId>spring-boot-starter-jetty</artifactId> <groupId>org.springframework.boot</groupId> </dependency>
<dependency> <artifactId>spring-boot-starter-undertow</artifactId> <groupId>org.springframework.boot</groupId> </dependency>
@Configuration @ConditionalOnWebApplication @EnableConfigurationProperties({ServerProperties.class}) public class EmbeddedWebServerFactoryCustomizerAutoConfiguration { public EmbeddedWebServerFactoryCustomizerAutoConfiguration() { } @Configuration @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}) // 判斷當前是否引入了Tomcat依賴 public static class TomcatWebServerFactoryCustomizerConfiguration { public TomcatWebServerFactoryCustomizerConfiguration() { }
public void customize(ConfigurableTomcatWebServerFactory factory) { ServerProperties properties = this.serverProperties; Tomcat tomcatProperties = properties.getTomcat(); PropertyMapper propertyMapper = PropertyMapper.get(); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull().as(Duration::getSeconds).as(Long::intValue).to(factory::setBackgroundProcessorDelay); this.customizeRemoteIpValve(factory); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getMaxThreads).when(this::isPositive).to((maxThreads) -> { this.customizeMaxThreads(factory, tomcatProperties.getMaxThreads()); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getMinSpareThreads).when(this::isPositive).to((minSpareThreads) -> { this.customizeMinThreads(factory, minSpareThreads); }); propertyMapper.from(this::determineMaxHttpHeaderSize).whenNonNull().asInt(DataSize::toBytes).when(this::isPositive).to((maxHttpHeaderSize) -> { this.customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull().asInt(DataSize::toBytes).to((maxSwallowSize) -> { this.customizeMaxSwallowSize(factory, maxSwallowSize); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getMaxHttpPostSize).asInt(DataSize::toBytes).when((maxHttpPostSize) -> { return maxHttpPostSize != 0; }).to((maxHttpPostSize) -> { this.customizeMaxHttpPostSize(factory, maxHttpPostSize); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getAccesslog).when(Accesslog::isEnabled).to((enabled) -> { this.customizeAccessLog(factory); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding); properties.getClass(); propertyMapper.from(properties::getConnectionTimeout).whenNonNull().to((connectionTimeout) -> { this.customizeConnectionTimeout(factory, connectionTimeout); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive).to((maxConnections) -> { this.customizeMaxConnections(factory, maxConnections); }); tomcatProperties.getClass(); propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive).to((acceptCount) -> { this.customizeAcceptCount(factory, acceptCount); }); this.customizeStaticResources(factory); this.customizeErrorReportValve(properties.getError(), factory); }
1.SpringBoot應用啓動run方法
2.SpringBoot刷新IOC容器refreshContext(建立IOC容器對象,並初始化容器,建立容器中的每個組件.若是是web應用就建立AnnotationConfigEmbeddedWebApplicationContext,不然建立默認的AnnotationConfigApplicationContext)
3.刷新建立好的容器refresh(context)
4.此時調用重寫的onRefresh()方法
5.web中IOC容器會建立嵌入式的Servlet容器:createEmbeddedServletContainer()
6.獲取嵌入式的Servlet容器工廠,從IOC容器中獲取嵌入式Servlet容器工廠組件,當該組件存在時,Tomcat嵌入式Servlet容器工廠建立對象,後置處理器就獲取全部定製器來定製Tomcat嵌入式Servlet容器的配置
7.使用Tomcat嵌入式Servlet容器工廠獲取嵌入式servlet容器
8.嵌入式的Servlet容器建立對象並啓動Servlet容器,先啓動嵌入式的Servlet容器,再將IOC容器中對象獲取出來
至此,完成IOC容器啓動建立嵌入式Servlet容器tomcat
嵌入式Servlet容器:springboot
org\springframework\spring-web\5.1.9.RELEASE\spring-web-5.1.9.RELEASE.jar\META-INF\services\javax.servlet.ServletContainerInitializer
Spring的web模塊中有這個文件:org.springframework.web.SpringServletContainerInitializer
3.SpringServletContainerInitializer將@HandleTypes({WebApplicationInitializer.class})標註的全部類型的類都傳入到onStartup方法的Set<Class<?>>中,爲WebApplicationInitializer類型的類建立實例
4.每個WebApplicationInitializer都調用本身的onStartup方法啓動
5.SpringBootServletInitializer類會建立對象並執行onStartup方法啓動
6.SpringBootServletInitializer執行onStartup方法會調用createRootApplicationContext建立容器服務器
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) { // 建立SpringApplicationBuilder構建器 SpringApplicationBuilder builder = this.createSpringApplicationBuilder(); builder.main(this.getClass()); ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext); if (parent != null) { this.logger.info("Root context already created (using as parent)."); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null); builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)}); } builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)}); builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class); // 調用configure方法,子類重寫該方法,將SpringBoot的主程序類傳入進來 builder = this.configure(builder); builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)}); // 使用builder建立一個Spring應用 SpringApplication application = builder.build(); if (application.getAllSources().isEmpty() && AnnotationUtils.findAnnotation(this.getClass(), Configuration.class) != null) { application.addPrimarySources(Collections.singleton(this.getClass())); } Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation"); if (this.registerErrorPageFilter) { application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class)); } // 啓動Spring應用 return this.run(application); }
7.Spring就啓動成功,而且建立IOC容器app
protected WebApplicationContext run(SpringApplication application) { return (WebApplicationContext)application.run(new String[0]); }