前置内容: servlet的多种注册方式

SpringBoot启用 ServletContainerInitializer

ServletContainerInitializer-SPI

SPI部分内容参照 servlet的多种注册方式

开启SPI

默认情况下,springboot 使用 embedded-tomcat,没有启用ServletContainerInitializer,这就需要我们做改造。

pom.xml

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!--添加servlet的依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency>

App.java 继承 SpringBootServletInitializer

@SpringBootApplication
public class App extends SpringBootServletInitializer {/*   public static void main(String[] args) {SpringApplication.run(App.class, args);}
*//*    @Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(App.class);}*/
}

springboot SPI

增加Filter配置类

@Configuration
public class SpringFilterConfiguration {@Beanpublic FilterRegistrationBean<SpringFilter1> SpringFilter1() {FilterRegistrationBean<SpringFilter1> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new SpringFilter1());registrationBean.setName("springfilter11");registrationBean.addUrlPatterns("/*");registrationBean.setOrder(11);return registrationBean;}@Beanpublic FilterRegistrationBean<SpringFilter2> SpringFilter2() {FilterRegistrationBean<SpringFilter2> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new SpringFilter2());registrationBean.setName("springfilter22");registrationBean.addUrlPatterns("/*");registrationBean.setOrder(22);return registrationBean;}
}

源码分析

1. SpringServletContainerInitializer

@HandlesTypes(WebApplicationInitializer.class) //lookup 实现WebApplicationInitializer的类
public class SpringServletContainerInitializer implements ServletContainerInitializer {@Overridepublic void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new ArrayList<>(webAppInitializerClasses.size());for (Class<?> waiClass : webAppInitializerClasses) {initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());}AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) { //  2. 此时值为App.classinitializer.onStartup(servletContext); }}
}

2.App

类图

App为我们的主类,它的泪如如下。

3.SpringBootServletInitializer.onStartup(servletContext)

程序的最终入口就在此了。

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {WebApplicationContext rootApplicationContext = createRootApplicationContext(servletContext); // 3.1if (rootApplicationContext != null) {servletContext.addListener(new SpringBootContextLoaderListener(rootApplicationContext, servletContext)); //3.2}}//3.1protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {SpringApplicationBuilder builder = createSpringApplicationBuilder(); // new SpringApplicationBuilder()builder.main(getClass()); // getClass() == App.class//parent部分略....builder.initializers(new ServletContextApplicationContextInitializer(servletContext));  //3.1.1builder.contextFactory((webApplicationType) -> new AnnotationConfigServletWebServerApplicationContext()); //3.1.2 factory 直接返回new AnnotationConfigServletWebServerApplicationContext(); extends ServletWebServerApplicationContextbuilder = configure(builder); //do nothingbuilder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext)); //3.1.3SpringApplication application = builder.build(); // 返回 SpringApplicationapplication.addPrimarySources(Collections.singleton(getClass())); //3.1.4application.setRegisterShutdownHook(false);return run(application);}protected WebApplicationContext run(SpringApplication application) {return (WebApplicationContext) application.run(); //执行 SpringApplication.run()}}

4. SpringApplication.run()

SpringApplication.run()的逻辑不再赘述, 最终会调用AbstractApplicationContext.onRefresh(),而此时的ApplicationContext的具体实现类为AnnotationConfigServletWebServerApplicationContext

public class SpringApplication {private List<ApplicationContextInitializer<?>> initializers;         //3.1.1private List<ApplicationListener<?>> listeners;                //3.1.3private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT; //3.1.2private Set<Class<?>> primarySources;  //3.1.4public ConfigurableApplicationContext run(String... args) {DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;configureHeadlessProperty();SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);Banner printedBanner = printBanner(environment);context = createApplicationContext(); // applicationContextFactory.create()//3.1.2 return AnnotationConfigServletWebServerApplicationContext();context.setApplicationStartup(this.applicationStartup);prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context); // ConfigurableApplicationContext.refresh();   ---> AbstractApplicationContext.onRefresh();afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);callRunners(context, applicationArguments);return context;}}

5.AnnotationConfigServletWebServerApplicationContext.onRefresh()

类图

ServletWebServerApplicationContext.onRefresh()

public class ServletWebServerApplicationContext extends GenericWebApplicationContextimplements ConfigurableWebServerApplicationContext {@Overrideprotected void onRefresh() {super.onRefresh();createWebServer(); // factory.getWebServer(getSelfInitializer());}private void selfInitialize(ServletContext servletContext) throws ServletException {prepareWebApplicationContext(servletContext);registerApplicationScope(servletContext);WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);for (ServletContextInitializer beans : getServletContextInitializerBeans()) {  beanFactory.getBeanNamesForType(ServletContextInitializer.class);beans.onStartup(servletContext); //6}}
}

6.ServletContextInitializer.onStartup

类图

AbstractFilterRegistrationBean.addRegistration()

//6. FilterRegistrationBean -> AbstractFilterRegistrationBean -> DynamicRegistrationBean  -> RegistrationBean
public abstract class AbstractFilterRegistrationBean<T extends Filter> extends DynamicRegistrationBean<Dynamic> {@Overrideprotected Dynamic addRegistration(String description, ServletContext servletContext) {Filter filter = getFilter();return servletContext.addFilter(getOrDeduceName(filter), filter);}}

springboot 自动注入servlet原理相关推荐

  1. SpringBoot自动配置Redis原理

    SpringBoot自动配置Redis原理 目录 SpringBoot自动配置Redis原理 一.SpringBoot自动配置Redis原理 一.自动配置redis RedisAutoConfigur ...

  2. 面试高频题:springboot自动装配的原理你能说出来吗?

    引言 最近有个读者在面试,面试中被问到了这样一个问题"看你项目中用到了springboot,你说下springboot的自动配置是怎么实现的?"这应该是一个springboot里面 ...

  3. SpringBoot自动配置的原理及实现

    SpringBoot的核心就是自动配置,自动配置是基于条件判断配置Bean 自动配置的源码在spring-boot-autoconfigure-2.2.13.RELEASE SpringBoot运行原 ...

  4. springboot自动配置的原理_SpringBoot实战:详解SpringBoot自动配置原理

    SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...

  5. springboot自动配置的原理_SpringBoot自动配置原理

    SpringBoot的启动入口就是一个非常简单的run方法,这个run方法会加载一个应用所需要的所有资源和配置,最后启动应用. 通过查看run方法的源码,我们发现,run方法首先启动了一个监听器,然后 ...

  6. SpringBoot自动配置MVC原理

    SpringBoot自动配置了MVC究竟都配置了那些东西,该如何自定义呢? 摸了!直接看官方文档(其实我也看不大懂英语) https://docs.spring.io/spring-boot/docs ...

  7. 自定义平台MQ,SpringBoot自动注入【xdx-mq-starter】

    视频地址:https://www.bilibili.com/video/BV1mr4y1J77n 之前面试的时候都会被问到为什么使用MQ,使用MQ的好处是什么,我都会照本宣科的说:异步.解耦.削峰,这 ...

  8. 聊一聊 SpringBoot 自动配置的原理

    解析思路 我们建立好一个SpringBoot的工程后,我们将从启动类,SpringBootApplication开始进行探究. 开始解析 首先我们建立一个 Springboot的工程.找到启动类,我们 ...

  9. SpringBoot 自动开启事务原理

    2019独角兽企业重金招聘Python工程师标准>>> 1,TransactionAutoConfiguration ①,这是SpringBoot 的事务注解自动配置类,位于spri ...

最新文章

  1. mysql www.school.com_MySQL 基础学习
  2. 贫血模型,充血模型(领域驱动设计)
  3. js中json的添加和指定位置的删除
  4. 安装配置RocketMQ,并配置Console
  5. 骚出天际!一个程序员女装照片的开源项目
  6. rman backup database force 功能
  7. 暑假集训-8.06总结
  8. 利用 Flask 动态展示 Pyecharts 图表数据的几种方法
  9. MyEclipse中流程定义文件保存时自动生成流程图
  10. 算法笔记_面试题_13.二叉树的最近公共祖先
  11. datagrid嵌套使用ajax,关于easyui datagrid多层嵌套动态合并列的问题
  12. 周立功TinyM0开发板1114使用教程
  13. 灰色系统理论及其应用 (一) :灰色系统概论、关联分析、与传统统计方法的比较
  14. 简单功能强大的jQuery在线图片裁剪插件croppic
  15. 第五十三回 关云长义释黄汉升  孙仲谋大战张文远
  16. 嵌入式算法19---国家商用密码SM算法
  17. 为什么滴滴裁员2000人,被裁员工却像中奖一样开心?...
  18. android support v13,java – 程序类型已存在:android.support.v13.v...
  19. 服务器安全加固三件套
  20. python实现雪花飘落效果_python实现雪花飘落效果实例讲解及源码分享!

热门文章

  1. java从github下载项目_在github下载的java项目通过idea打开(全流程图文,傻瓜式)
  2. 拓嘉辰丰:拼多多赠品链接是怎样做出来的
  3. 回顾一波春招找实习的艰苦岁月
  4. 智慧楼宇、智能社区、园区、楼宇管理系统、可视化、可视化数据、送排风、给排水、能源、运维、变配电、门禁、停车场、楼控系统、智能照明、电梯系统、安防系统、视频监控、防盗报警、电子巡更、设备台账、运维管理
  5. GPU--图形处理器
  6. Linux jar包 后台运行命令
  7. 测试员薪资两极分化,如何成为年薪百万的阿里测开?
  8. 数组的赋值机制和赋值原理
  9. 800字让你搞懂:掩码,反掩码,通配符。
  10. 注册表桌面显示计算机,电脑开机后不显示桌面图标怎么办?修改注册表解决开机后不显示桌面图标的3种方法...