SpringBoot嵌入式Servlet配置原理
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对象
SpringBoot嵌入式Servlet配置原理的更多相关文章
- SpringBoot嵌入式Servlet容器
		SpringBoot默认是将Tomcat作为嵌入式的servlet容器. 问题: 如何修改嵌入式的servlet容器? 1)在配置文件中设置对应的属性值 server.port=8081 # Tomc ... 
- SpringBoot的自动配置原理过程解析
		SpringBoot的最大好处就是实现了大部分的自动配置,使得开发者可以更多的关注于业务开发,避免繁琐的业务开发,但是SpringBoot如此好用的 自动注解过程着实让人忍不住的去了解一番,因为本文的 ... 
- SpringBoot之自动配置原理
		我在前面的Helloworld的程序中已经分析过一次,配置原理了: 1).SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration 2).@En ... 
- 面试题: SpringBoot 的自动配置原理
		个人博客网:https://wushaopei.github.io/ (你想要这里多有) 3.Spring Boot 的自动配置原理 package com.mmall; import org. ... 
- SpringBoot的自动配置原理
		一.入口 上篇注解@SpringBootApplication简单分析,说到了@SpringBootApplication注解的内部结构, 其中@EnableAutoConfiguration利用En ... 
- SpringBoot的启动配置原理
		一.启动流程 创建SpringApplication对象 public class SpringApplication { public SpringApplication(Class... prim ... 
- 18、配置嵌入式servlet容器(2)
		使用其他Servlet容器 -Jetty(长连接) -Undertow(不支持jsp) 替换为其他嵌入式Servlet容器 默认支持: Tomcat(默认使用) Jetty: <depend ... 
- SpringBoot源码学习系列之嵌入式Servlet容器
		目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ... 
- SpringBoot自动配置原理
		前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾前面Spring的文章(以学习的顺序排好): S ... 
随机推荐
- 关于SDWebImage的一点小坑
			做项目遇到一个问题,是用sd加载图片,明明本地有图片,使用sd的内部方法也可以拿到那些个图片,但是就是加载缓慢,如果网络还行,网络加载图片都比加载本地图片快.而使用[[SDImageCache ... 
- 求树上任意一点所能到达的最远距离 - 树上dp
			A school bought the first computer some time ago(so this computer's id is 1). During the recent year ... 
- 假期续命充电——简单上手tesorflow2 框架
			谈到深度学习,就不得不谈到tensorflow 在tensorflow之后出了2.0版本,相比之前有了很大的改变,趁着假期赶紧冲冲冲! 稍微学习了一些基础,做一个自我总结,作为一些基础的知识不再过多重 ... 
- 【python系统学习06】一张图看懂列表并学会操作
			点击跳转-原文地址 数据类型 - 列表(list) 「目录:」 一张图了解列表 列表是什么 列表长啥样 语法格式 代码示例 格式特征 列表定义 列表操作 - 提取单个:偏移量 什么是偏移量 偏移量提取 ... 
- Java入门 - 面向对象 - 06.接口
			原文地址:http://www.work100.net/training/java-interface.html 更多教程:光束云 - 免费课程 接口 序号 文内章节 视频 1 概述 2 接口的声明 ... 
- ssm项目中中文字符乱码
			昨天给同学改一个错,在SSM项目中,表单输入的String类型中,中文字符值,总是乱码,在控制器层获取的数据就开始乱码,先后进行了如下排查: web.xml中配置设置字符编码的监听器(过滤器), js ... 
- python接口自动化测试 - unittest框架suite、runner详细使用
			test suite 测试套件,理解成测试用例集 一系列的测试用例,或测试套件,理解成测试用例的集合和测试套件的集合 当运行测试套件时,则运行里面添加的所有测试用例 test runner 测试运行器 ... 
- Creating Custom Helper Methods 创建自定义辅助器方法----辅助器方法  ------ 精通ASP.NET MVC 5
			创建内联的辅助器方法 和 拓展方法 好像类似的功能. 不过写在前台更直观 
- 废旧手机改造之给你的手机安装win10系统
			最近又开始琢磨把我这个即将退出的二手手机再利用一下 发现了一个不错的软件 先上图 是不是感觉逼格很高啊 点击下面链接即可下载使用 https://www.lanzous.com/i4gpsib 欢迎交 ... 
- Day9-Python3基础-多线程、多进程
			1.进程.与线程区别 2.python GIL全局解释器锁 3.线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Que ... 
