两学一做纪实评价系统登陆网站,网络营销与策划形考任务答案,公司网站怎么做关键字,做网站备案须知SpringBoot的嵌入式Servlet容器 嵌入式Servlet容器servlet容器-嵌入式servlet容器配置修改通过全局配置文件修改修改添加实现了WebServerFactoryCustomizer接口的bean来进行修改 servlet容器-注册servlet三大组件应该如何注册呢#xff1f;servlet3.0规范提供的注解方式进行注… SpringBoot的嵌入式Servlet容器 嵌入式Servlet容器servlet容器-嵌入式servlet容器配置修改通过全局配置文件修改修改添加实现了WebServerFactoryCustomizer接口的bean来进行修改 servlet容器-注册servlet三大组件应该如何注册呢servlet3.0规范提供的注解方式进行注册springboot提供的注册方式 servlet容器-切换到其他servlet容器servlet容器-嵌入式servlet容器自动配置原理ServletWebServerFactoryAutoConfiguration配置类源码分析为什么可以根据配置依赖自动使用servlet容器怎么根据配置文件中的server.xxx以及实现了WebServerFactoryCustomizer的类去设置serverlet容器配置嵌入式servlet容器如何启动 servlet容器-使用外部servlet容器SpringBoot使用外部servlet servlet容器-外部servlet启动SpringBoot原理启动原理 嵌入式Servlet容器
SpringBoot包含对嵌入式Tomcat、Jetty、Undertow等服务器的支持。大多数开发人员使用适当的“”启动器“” 来获取完全配置的实例。默认情况下嵌入式服务器在port上监听HTTP请求8080
servlet容器-嵌入式servlet容器配置修改 通过全局配置文件修改修改 可以通过server.xxx 来进行web服务配置,没有带服务器名称的则是通用配置 通常带了具体服务器名称则是单独对该服务器进行设置比如server.tomcat.xxx就是专门针对tomcat的配置
添加实现了WebServerFactoryCustomizer接口的bean来进行修改
这儿的泛型添加的tomcat的ConfigurableTomcatWebServerFactory
Component
public class CustomizationBean implements WebServerFactoryCustomizerConfigurableTomcatWebServerFactory {Overridepublic void customize(ConfigurableTomcatWebServerFactory server) {server.setPort(8088);}
}servlet容器-注册servlet三大组件 servlet三大组件servlet监听器listenser过滤器filter
应该如何注册呢 servlet3.0规范提供的注解方式进行注册 springboot提供的注册方式
servlet3.0规范提供的注解方式进行注册 WebServlet注册servlet的注解 WebListener注册监听器的注解 WebFilter注册过滤器的注解 以webservlet进行演示定义一个servlet
WebServlet(name HelloServlet,urlPatterns /HelloServlet)
public class HelloServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().println(hello servlet);}
}在springboot启动类上加上ServletComponentScan,让springboot可以扫描到serverlet的bean
SpringBootApplication
ServletComponentScan
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class,args);}
}springboot提供的注册方式
自定义一个servlet
public class BeanServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().println(bean servlet);}
}定义一个bean注册的配置类 可以使用ServletRegistrationBean、ServletListenerRegistrationBean、FilterRegistrationBean分别来管理servlet、监听器、过滤器
Configuration
public class RegistryBeanConfigration {Beanpublic ServletRegistrationBean myServlet(){ServletRegistrationBeanServlet registrationBean new ServletRegistrationBean();//设置相应的servletregistrationBean.setServlet(new BeanServlet());//设置名称registrationBean.setName(beanServlet);//添加映射规则registrationBean.addUrlMappings(/beanServlet);return registrationBean;}
}
测试
servlet容器-切换到其他servlet容器
srpingboot默认服务器是tomcat服务器
排除内嵌tomcat dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId!--排除内嵌tomcat--exclusionsexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactId/exclusion/exclusions/dependency引入Jetty依赖 !--引入jetty依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jetty/artifactId/dependency启动项目 测试
servlet容器-嵌入式servlet容器自动配置原理
内嵌servelet自动配置类ServletWebServerFactoryAutoConfiguration 问题为什么可以根据配置依赖自动使用servlet容器怎么根据配置文件中的server.xxx以及实现了WebServerFactoryCustomizer的类去设置serverlet容器配置嵌入式servlet容器如何启动
ServletWebServerFactoryAutoConfiguration配置类源码分析 //启用配置文件的属性类那么所有的配置信息都会绑定到ServerProperties.class EnableConfigurationProperties(ServerProperties.class) Configuration(proxyBeanMethods false)
AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//只要依赖了任何一个servlet容器它就会生效
ConditionalOnClass(ServletRequest.class)
ConditionalOnWebApplication(type Type.SERVLET)
//启用配置文件的属性类那么所有的配置信息都会绑定到ServerProperties.class
EnableConfigurationProperties(ServerProperties.class)
Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {为什么可以根据配置依赖自动使用servlet容器
Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })通过imort导入Embeddel类每个Embeddel类 中都配置了相应的ConditionalOnClass会根据当前servlet容器启动器依赖判断classpath是否存在对应的类如果存在就使用对应的sevlet容器比如tomcat:
Configuration(proxyBeanMethods false)//只要添加了tomcat的场景启动器 则该注解才会匹配如果没有对应的tomcat场景启动器该注解就不会匹配ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })ConditionalOnMissingBean(value ServletWebServerFactory.class, search SearchStrategy.CURRENT)static class EmbeddedTomcat {怎么根据配置文件中的server.xxx以及实现了WebServerFactoryCustomizer的类去设置serverlet容器配置
ServletWebServerFactoryAutoConfiguration类 Beanpublic ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,ObjectProviderWebListenerRegistrar webListenerRegistrars,ObjectProviderCookieSameSiteSupplier cookieSameSiteSuppliers) {return new ServletWebServerFactoryCustomizer(serverProperties,webListenerRegistrars.orderedStream().collect(Collectors.toList()),cookieSameSiteSuppliers.orderedStream().collect(Collectors.toList()));}ServletWebServerFactoryCustomizer 也实现了WebServerFactoryCustomizer说明它也是定制servlet容器的
ServletWebServerFactoryCustomizer类 根据配置文件中server.xxx来进行定制servlet容器 Overridepublic void customize(ConfigurableServletWebServerFactory factory) {PropertyMapper map PropertyMapper.get().alwaysApplyingWhenNonNull();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()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);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);map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);for (WebListenerRegistrar registrar : this.webListenerRegistrars) {registrar.register(factory);}if (!CollectionUtils.isEmpty(this.cookieSameSiteSuppliers)) {factory.setCookieSameSiteSuppliers(this.cookieSameSiteSuppliers);}}实现了WebServerFactoryCustomizer接口的类如何进行配置呢 BeanConditionalOnClass(name org.apache.catalina.startup.Tomcat)public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {return new TomcatServletWebServerFactoryCustomizer(serverProperties);}TomcatServletWebServerFactoryCustomizer 也实现了WebServerFactoryCustomizer说明它也是定制servlet容器的
TomcatServletWebServerFactoryCustomizer也重写了customize方法 Overridepublic void customize(TomcatServletWebServerFactory factory) {ServerProperties.Tomcat tomcatProperties this.serverProperties.getTomcat();if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) {factory.getTldSkipPatterns().addAll(tomcatProperties.getAdditionalTldSkipPatterns());}if (tomcatProperties.getRedirectContextRoot() ! null) {customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot());}customizeUseRelativeRedirects(factory, tomcatProperties.isUseRelativeRedirects());factory.setDisableMBeanRegistry(!tomcatProperties.getMbeanregistry().isEnabled());}怎么让所有的WebServerFactoryCustomizer bean一一调用呢BeanPostProcessorsRegistrar 注册WebServerFactoryCustomizerBeanPostProcessor为bean Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {if (this.beanFactory null) {return;}registerSyntheticBeanIfMissing(registry, webServerFactoryCustomizerBeanPostProcessor,//注册了WebServerFactoryCustomizerBeanPostProcessor beanWebServerFactoryCustomizerBeanPostProcessor.class,WebServerFactoryCustomizerBeanPostProcessor::new);registerSyntheticBeanIfMissing(registry, errorPageRegistrarBeanPostProcessor,ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);}
WebServerFactoryCustomizerBeanPostProcessor 实现了BeanPostProcessor在spring初始化bean的时候会被调用
public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 判断当前创建的bean是不是webserverfactofyif (bean instanceof WebServerFactory) {this.postProcessBeforeInitialization((WebServerFactory)bean);}return bean;}当前对应的Embeddedxxx 启用时就会在里面配置一个WebServerFactory类型的bean负责创建对应的容器和启动 BeanTomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProviderTomcatConnectorCustomizer connectorCustomizers,ObjectProviderTomcatContextCustomizer contextCustomizers,ObjectProviderTomcatProtocolHandlerCustomizer? protocolHandlerCustomizers) {TomcatServletWebServerFactory factory new TomcatServletWebServerFactory();factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));return factory;}spring bean初始化前就会调用postProcessBeforeInitialization方法从而执行customize方法
调用getCustomizers()方法调用getWebServerFactoryCustomizerBeans()方法获取所有实现了WebServerFactoryCustomizer接口的bean获取自定义的、ServletWebServerFactoryCustomizer、TomcatServletWebServerFactoryCustomizer在invoke方法中循环调用所有实现了WebServerFactoryCustomizer接口 的bean并调用customize()方法进行一一定制 private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {((LambdaSafe.Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) - {customizer.customize(webServerFactory);});}private CollectionWebServerFactoryCustomizer? getCustomizers() {if (this.customizers null) {this.customizers new ArrayList(this.getWebServerFactoryCustomizerBeans());this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);this.customizers Collections.unmodifiableList(this.customizers);}return this.customizers;}private CollectionWebServerFactoryCustomizer? getWebServerFactoryCustomizerBeans() {return this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();}嵌入式servlet容器如何启动 TomcatServletWebServerFactory自动配置根据不同的依赖启动对应一个Enbenddedxxx然后配置一个对应的servlet工厂类比如TomcatServletWebServerFactory在springboot应用启动的时候就会调用refresh方法onRefresh方法调用getWebServer创建servlet容器并且启动
TomcatServletWebServerFactory类 public WebServer getWebServer(ServletContextInitializer... initializers) {if (this.disableMBeanRegistry) {Registry.disableRegistry();}Tomcat tomcat new Tomcat();File baseDir this.baseDirectory ! null ? this.baseDirectory : this.createTempDir(tomcat);tomcat.setBaseDir(baseDir.getAbsolutePath());Iterator var4 this.serverLifecycleListeners.iterator();while(var4.hasNext()) {LifecycleListener listener (LifecycleListener)var4.next();tomcat.getServer().addLifecycleListener(listener);}Connector connector new Connector(this.protocol);connector.setThrowOnFailure(true);tomcat.getService().addConnector(connector);this.customizeConnector(connector);tomcat.setConnector(connector);tomcat.getHost().setAutoDeploy(false);this.configureEngine(tomcat.getEngine());Iterator var8 this.additionalTomcatConnectors.iterator();while(var8.hasNext()) {Connector additionalConnector (Connector)var8.next();tomcat.getService().addConnector(additionalConnector);}this.prepareContext(tomcat.getHost(), initializers);//启动方法在getTomcatWebServerreturn this.getTomcatWebServer(tomcat);}protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {return new TomcatWebServer(tomcat, this.getPort() 0, this.getShutdown());}
TomcatWebServer类 在TomcatWebServer中调用initialize方法进行启动 private void initialize() throws WebServerException {logger.info(Tomcat initialized with port(s): this.getPortsDescription(false));synchronized(this.monitor) {try {this.addInstanceIdToEngineName();Context context this.findContext();context.addLifecycleListener((event) - {if (context.equals(event.getSource()) start.equals(event.getType())) {this.removeServiceConnectors();}});this.tomcat.start();this.rethrowDeferredStartupExceptions();try {ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());} catch (NamingException var5) {}this.startDaemonAwaitThread();} catch (Exception var6) {this.stopSilently();this.destroySilently();throw new WebServerException(Unable to start embedded Tomcat, var6);}}}servlet容器-使用外部servlet容器
外部servlet容器 服务器 安装tomcat 配置环境变量部署 war包—运维—tomcat webapp startup.sh 启动开发将开发绑定本地tomcat 内嵌servlet容器 部署jar—运维—java -jar 启动
SpringBoot使用外部servlet
修改pom.xml的打包方式修改为war包形式 设置tomcat依赖设置scope为provided让内嵌tomcat不参与打包 !--让它不参与打包部署--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactIdscopeprovided/scope/dependencytypepom/type //用在父子类模块中一般使用在父模块中此时它相当于一个一个依赖管理Maven Parent POM文件
optionaltrue/optional //用在父模块中此时子模块不会继承父模块的该依赖true不传递false传递
scopeprovided/scope //让依赖不参与打包设置tomcat的启动类 目的是tomcat启动的时候调用configure方法来启动springboot的启动类
/*** 当tomcat启动时就会调用configure方法,去启动springboot的启动类*/
public class TomcatStartSpringBoot extends SpringBootServletInitializer {Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(MyApplication.class);}
}添加本地tomcat测试-使用本地tomcat启动 servlet容器-外部servlet启动SpringBoot原理
tomcat --web.xml—filter servlet listener tomcat不会主动去启动springboot应用所以tomcat启动的时候肯定调用了SpringBootServletInitializer 的configure方法
public class TomcatStartSpringBoot extends SpringBootServletInitializer {Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(MyApplication.class);}
}启动原理 当servlet容器启动的时候就会去META-INF/service/文件下去找javax.servlet.ServletContainerInitializer文件 这个文件肯定绑定了一个ServletContainerInitializer
org.springframework.web.SpringServletContainerInitializer当servlet容器启动的时候就会去该文件夹中找到ServletContainerInitializer的实现类SpringServletContainerInitializer从而创建它实例(SPI机制)并且调用onStartup方法
HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {public SpringServletContainerInitializer() {}public void onStartup(Nullable SetClass? webAppInitializerClasses, ServletContext servletContext) throws ServletException {ListWebApplicationInitializer initializers Collections.emptyList();Iterator var4;if (webAppInitializerClasses ! null) {initializers new ArrayList(webAppInitializerClasses.size());var4 webAppInitializerClasses.iterator();while(var4.hasNext()) {Class? waiClass (Class)var4.next();if (!waiClass.isInterface() !Modifier.isAbstract(waiClass.getModifiers()) WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {((List)initializers).add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());} catch (Throwable var7) {throw new ServletException(Failed to instantiate WebApplicationInitializer class, var7);}}}}if (((List)initializers).isEmpty()) {servletContext.log(No Spring WebApplicationInitializer types detected on classpath);} else {servletContext.log(((List)initializers).size() Spring WebApplicationInitializers detected on classpath);AnnotationAwareOrderComparator.sort((List)initializers);var4 ((List)initializers).iterator();while(var4.hasNext()) {WebApplicationInitializer initializer (WebApplicationInitializer)var4.next();initializer.onStartup(servletContext);}}}
}HandlesTypes({WebApplicationInitializer.class})HandlesTypes({WebApplicationInitializer.class})传入的类为ServletContainerInitializer感兴趣的类容器会自动在classpath中找到WebApplicationInitializer 会传入到onStartup方法的webAppInitializerClasses 参数中也包括了之前自定义的TomcatStartSpringBoot
HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements 启动WebApplicationInitializer的onStartup方法 循环调用所有WebApplicationInitializer实例的onstartup方法 if (((List)initializers).isEmpty()) {servletContext.log(No Spring WebApplicationInitializer types detected on classpath);} else {servletContext.log(((List)initializers).size() Spring WebApplicationInitializers detected on classpath);AnnotationAwareOrderComparator.sort((List)initializers);var4 ((List)initializers).iterator();while(var4.hasNext()) {WebApplicationInitializer initializer (WebApplicationInitializer)var4.next();//循环调用所有WebApplicationInitializer实例的onstartup方法initializer.onStartup(servletContext);} 调用SpringBootServletInitializer onStartup方法 public void onStartup(ServletContext servletContext) throws ServletException {servletContext.setAttribute(logging.register-shutdown-hook, false);this.logger LogFactory.getLog(this.getClass());//创建对对对 ,这个方法里就会去调用configure方法WebApplicationContext rootApplicationContext this.createRootApplicationContext(servletContext);if (rootApplicationContext ! null) {servletContext.addListener(new SpringBootContextLoaderListener(rootApplicationContext, servletContext));} else {this.logger.debug(No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context);}}createRootApplicationContext 当调用configure方法的时候就会调用我们自己的configure方法(为了更好的理解才去父类里看)因为TomcatStartSpringBoot是继承了SpringBootServletInitializer又继承了WebApplicationInitializer(我们自己定义的TomcatStartSpringBoot也是一个WebApplicationInitializer)
public class TomcatStartSpringBoot extends SpringBootServletInitializer {Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(MyApplication.class);}
}createRootApplicationContext 调用build方法就会根据传入的SpringBoot的启动类来构建一个springapplication
SpringApplicationBuilder public SpringApplication build(String... args) {this.configureAsChildIfNecessary(args);this.application.addPrimarySources(this.sources);return this.application;}最后再调用run方法来启动springboot 启动springboot protected WebApplicationContext run(SpringApplication application) {return (WebApplicationContext)application.run(new String[0]);}