微服务架构Day05-SpringBoot之Servlet
旧版
配置嵌入式Servlet容器
- SpringBoot默认使用Tomcat作为嵌入式Servlet容器
- 如何定制和修改Servlet容器相关配置
1.在配置文件中定制和修改Servlet容器有关的配置,本质上是使用SpringBoot的默认的嵌入式Servlet容器的定制器来修改配置.
通用的servlet容器配置
server.xx=
通用的Tomcat配置
server.tomcat.xx=
2.编写一个嵌入式Servlet容器定制器来修改Servlet容器的配置
在SpringBoot中会有xxxCustomizer来进行扩展配置,注意学习!!
注册Servlet三大组件(Servlet,Filter,Listener)
- 由于SpringBoot默认以jar包的方式启动嵌入式Servlet容器来启动SpringBoot应用,没有web.xml文件.
- 注册三大组件方式:
1.ServletRegistrationBean
@Configuration
public class MyServerConfig {
// 注册Servlet组件
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean servletRegistrationBean=new ServletRegistrationBean(new MyServlet(),"/my");
return servletRegistrationBean;
}
}
2.FilterRegistrationBean
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my"));
return filterRegistrationBean;
}
3.ServletListenerRegistrationBean
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
SpringBoot自动配置SpringMVC时,自动注册SpringMVC的前端控制器:DispatcherServlet.
@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;
}
}
- " / ":表示拦截所有请求,包括静态资源,但是不拦截jsp请求," /* ":表示拦截所有请求,包括jsp请求
- 注入Bean的几种方式:
- @Bean注解
- 包扫描:
- @Controller
- @Service
- @Repository
- @Component
- @Import:
- 实现ImportSelector接口的类
- 实现ImportBeanDefinitionRegistry接口
- 实现FactoryBean
SpringBoot支持其它的Servlet容器
- 默认支持:Tomcat(默认),Jetty,Undertow
- Tomcat是最稳定的服务器,一般情况下推荐使用
- Jetty更适合长连接的服务,但是长连接的服务Netty比Jetty更优秀
- Undertow更适合于IO密集型服务器或者文件服务器,比Tomcat优秀
- Jetty(长连接):
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
- Undertow(不支持jsp):
<dependency>
<artifactId>spring-boot-starter-undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
嵌入式Servlet容器自动配置原理
- EmbeddedWebServerFactoryCustomizerAutoConfiguration: 嵌入式容器的自动配置
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties({ServerProperties.class})
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
public EmbeddedWebServerFactoryCustomizerAutoConfiguration() {
}
@Configuration
@ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}) // 判断当前是否引入了Tomcat依赖
public static class TomcatWebServerFactoryCustomizerConfiguration {
public TomcatWebServerFactoryCustomizerConfiguration() {
}
- 以TomcatWebServerFactoryCustomizer为例:
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.ServerProperties,也是Servlet容器定制器
2.嵌入式Servlet容器定制器来修改
原理:BeanPostProcessorsRegistrar:给容器导入组件
BeanPostProcessor:后置处理器,在bean初始化(创建完对象,还没有赋值)时执行初始化工作
步骤:
1.SpringBoot根据导入的依赖情况,给容器中添加相应的嵌入式容器工厂
2.容器中某个组件要创建对象时,便会调用后置处理器,只要是嵌入式Servlet容器工厂,后置处理器就会工作.
3.后置处理器从容器中获取所有嵌入式容器处理器定制器,调用嵌入式容器处理器定制器中的方法对嵌入式容器处理器进行配置
嵌入式Servlet容器启动原理
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容器
使用外置的Servlet容器
嵌入式Servlet容器:
- 优点:简单,便捷
- 缺点:默认不支持jsp,优化定制复杂(使用定制器[ ServerProperties,自定义定制器],自己创建嵌入式Servlet容器的创建工厂)
- 外置的Servlet容器:外置安装Tomcat-应用war包的方式打包
步骤
1.创建一个war项目,配置好项目的Project Structure
2.将嵌入式的Tomcat指定为provided
3.编写一个SpringBootServletInitializer的子类,并调用configure方法,传入SpringBoot应用主程序
4.启动服务器就可以启动项目
原理: - jar包:执行SpringBoot主类的main方法,启动IOC容器,创建嵌入式Servlet容器
- war包:启动服务器,服务器启动SpringBoot应用(SpringBootServletInitializer),然后才能启动IOC容器
- servlet3.0的8.2.4 Shared libraries / runtimes pluggability中的规则:
1.服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例
2.ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个javax.servlet.ServletContainerInitializer的文件,内容是ServletContainerInitializer实现类的全类名
3.可以使用 @HandleTypes注解,在应用启动时加载需要的类
流程:
1.启动Tomcat
2.
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容器
protected WebApplicationContext run(SpringApplication application) {
return (WebApplicationContext)application.run(new String[0]);
}
- 先启动Servlet容器,再启动SpringBoot应用
微服务架构Day05-SpringBoot之Servlet的更多相关文章
- Aibabelx-shop 大型微服务架构系列实战之技术选型
一.本项目涉及编程语言java,scala,python,涉及的技术如下: 1.微服务架构: springboot springcloud mybatisplus shiro 2.全文检索技术 sol ...
- SpringBoot微服务架构下的MVC模型总结
SpringBoot微服务架构下的MVC模型产生的原因: 微服务概念改变着软件开发领域,传统的开源框架结构开发,由于其繁琐的配置流程 , 复杂的设置行为,为项目的开发增加了繁重的工作量,微服务致力于解 ...
- 使用Redis为注册中心的Dubbo微服务架构(基于SpringBoot)
title: 使用Redis为注册中心的Dubbo微服务架构(基于SpringBoot) date: 2019-07-30 14:06:29 categories: 架构 author: mrzhou ...
- spring-boot+spring-cloud+maven-module 一个 maven多模块的微服务架构模版
spring-boot-cloud-module spring-boot+spring-cloud+maven-module 一个 maven多模块的微服务架构模版. 新手上路的绝佳模版,只有必要的配 ...
- SpringCloud SpringBoot 前后端分离企业级微服务架构源码赠送
基于SpringBoot2.x.SpringCloud和SpringCloudAlibaba并采用前后端分离的企业级微服务敏捷开发系统架构.并引入组件化的思想实现高内聚低耦合,项目代码简洁注释丰富上手 ...
- springcloud微服务架构搭建
SpringCloud微服务框架搭建 一.微服务架构 1.1什么是分布式 不同模块部署在不同服务器上 作用:分布式解决网站高并发带来问题 1.2什么是集群 多台服务器部署相同应用构成一个集群 作用:通 ...
- 学习一下 SpringCloud (一)-- 从单体架构到微服务架构、代码拆分(maven 聚合)
一.架构演变 1.系统架构.集群.分布式系统 简单理解 (1)什么是系统架构? [什么是系统架构?] 系统架构 描述了 在应用程序内部,如何根据 业务.技术.灵活性.可扩展性.可维护性 等因素,将系统 ...
- Dubbo和Spring Cloud微服务架构'
微服务架构是互联网很热门的话题,是互联网技术发展的必然结果.它提倡将单一应用程序划分成一组小的服务,服务之间互相协调.互相配合,为用户提供最终价值.虽然微服务架构没有公认的技术标准和规范或者草案,但业 ...
- 微服务架构-选择Spring Cloud,放弃Dubbo
Spring Cloud 在国内中小型公司能用起来吗?从 2016 年初一直到现在,我们在这条路上已经走了一年多. 在使用 Spring Cloud 之前,我们对微服务实践是没有太多的体会和经验的.从 ...
- Spring Cloud 微服务架构的五脏六腑,统统晒一晒!
Spring Cloud 是一个基于 Spring Boot 实现的微服务框架,它包含了实现微服务架构所需的各种组件. 注:Spring Boot 简单理解就是简化 Spring 项目的搭建.配置.组 ...
随机推荐
- SICP 解题集 — SICP 解题集 https://sicp.readthedocs.io/en/latest/
SICP 解题集 - SICP 解题集 https://sicp.readthedocs.io/en/latest/
- git commit前检测husky与pre-commit 提交钩子
git commit前检测husky与pre-commit git commit前检测husky与pre-commit - 简书 https://www.jianshu.com/p/f0d31f92b ...
- C++ Primer Plus读书笔记(九)内存模型和名称空间
1.作用域和链接 int num3; static int num4; int main() { } void func1() { static int num1; int num2; } 上边的代码 ...
- calc, support, media各自的含义及用法?
@support主要是用于检测浏览器是否支持CSS的某个属性,其实就是条件判断,如果支持某个属性,你可以写一套样式,如果不支持某个属性,你也可以提供另外一套样式作为替补. calc() 函数用于动态计 ...
- 小步前进之WebService
WebService Web Service 什么是Web Service? 为什么使用Web Service XML 什么是XML? 为什么使用XML? SOAP(Simple Object Acc ...
- P1837 单人纸牌
写在前面 感谢巨佬 yu__xuan 的帮助! 原本题解区的大佬们大都写的九层循环,其实此题如果写成状压,可以将这九层循环写成一层,非但简洁.代码可读性强,常数也比直接九维 dp 小. 算法思路 由于 ...
- 小w、小j和小z
n个月没更了,现在学的东西很难,掌握不好,不敢更! 这个题目既不超范围又足够难想,反正我没想出来,很好的题目! 我发现noi.ac上的题目很不错!!! ------------------------ ...
- 内网渗透之信息收集-linux
linux 系统信息 grep MemTotal /proc/meminfo #查看系统内存总量 cat /etc/issue #查看系统名称 ...
- 分层图最短路( LYOi Online Judge 初中的最后一天)
代码参照: LYOI Online Judge #374. 初中的最后一天 分层图最短路模板题 1 #include<iostream> 2 #include<cstdi ...
- NOIP组合数选题
前言: "所有的组合数问题都是好题" ----清华某高材生zhx 组合数问题在近几年的NOIP的考试中多次露面,感觉有必要好好学一学 组合数的常见公式: C ( ...