微服务架构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 项目的搭建.配置.组 ...
随机推荐
- JVM(四)打破双亲委派和SPI机制
前言: 我们都知道判断两个类是不是同一个,要根据类加载器和全限定名.这是为什么呢?为什么不同的类加载器加载同一个类是不同的呢? 答案就是,不同的类加载器所加载的类在方法区的存储空间是不同的即Insta ...
- 【IDEA】Lombok--是否值得我们去使用
官网 https://projectlombok.org/ 简介 Project Lombok is a java library that automatically plugs into your ...
- 糊糊的学习笔记--Fiddle抓包
Fiddle简述 Fiddler是一个http调试代理,它能 够记录所有的你电脑和互联网之间的http通讯,Fiddler 可以也可以让你检查所有的http通讯,设置断点,以及Fiddle 所有的&q ...
- join 查询优化
在开发中往往会出现查询多表联查的情况,那么就会用到 join 查询. Join查询种类 为了方便说明,先定义一个统一的表,下面再做例子. CREATE TABLE `t2` ( `id` int(11 ...
- Vue3 源码之 reactivity
注: 为了直观的看到 Vue3 的实现逻辑, 本文移除了边缘情况处理.兼容处理.DEV环境的特殊逻辑等, 只保留了核心逻辑 vue-next/reactivity 实现了 Vue3 的响应性, rea ...
- EMA algorithm: https://blog.csdn.net/m0_38106113/article/details/81542863
EMA algorithm: https://blog.csdn.net/m0_38106113/article/details/81542863
- (转载)微软数据挖掘算法:Microsoft 决策树分析算法(1)
微软数据挖掘算法:Microsoft 目录篇 介绍: Microsoft 决策树算法是分类和回归算法,用于对离散和连续属性进行预测性建模. 对于离散属性,该算法根据数据集中输入列之间的关系进行预测. ...
- 二:整合Spring Security
整合Spring Security 1.项目创建 2.初次体验 3.用户名配置 3.1 配置文件配置用户名/密码 3.2 Java 配置用户名/密码 4.登录配置 5.忽略拦截 江南一点雨:Sprin ...
- 后台获取日期值,前台Js对日期进行操作
需求描述: 方法一: 方法二: 一些标签常用隐藏方法: 需求描述: 在初始化页面的时候,需要根据系统当前的时间对前台JSP页面的某项进行值的初始化,若前台JSP标签没有相关可以初始化的属性,那么可以从 ...
- redis学习教程一《Redis的安装和配置》
redis学习教程一<Redis的安装和配置> Redis的优点 以下是Redis的一些优点. 异常快 - Redis非常快,每秒可执行大约110000次的设置(SET)操作,每秒大约可执 ...