Spring中对于WebApplicationInitializer的理解
文章目录
- 1、前言
- 2、WebApplicationInitializer的定义
- 3、实现原理
- 4、利用SPI我们能做什么?
- 4.1、定义一个`MyWebAppInitializer`
- 4.2、定义一个`MySpringServletContainerInitializer`
- 4.3、写一个`MyWebAppInitializer`的实现类
- 4.4、添加配置文件`javax.servlet.ServletContainerInitializerr`
- 4.5、启动项目测试
1、前言
在《SpringMVC学习(五)——零配置实现SpringMVC》这篇文章中我们没有使用Spring的配置实现了一个正常的SpringMVC的功能,里面核心的一个点就是使用了WebApplicationInitializer
,那这篇文章就详细说明一下这个接口的作用。
2、WebApplicationInitializer的定义
从起初的Spring配置文件,到后来的Spring支持注解到后来的SpringBoot,Spring框架在一步步的使用注解的方式来去除Spring的配置的发展过程。WebApplicationInitializer
就是取代web.xml
配置的一个接口。
public interface WebApplicationInitializer {void onStartup(ServletContext var1) throws ServletException;
}
通过覆盖接口提供的onStartup
方法我们可以往Servlet容器
里面添加我们需要的servlet
、listener
等,并且在Servlet容器
启动的过程中就会加载这个接口的实现类,从而起到和web.xml
相同的中作用,从而可以替代以前在web.xml中所做的配置。
3、实现原理
我们首先可以从Spring源码中找到SpringServletContainerInitializer
实现类。
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {public SpringServletContainerInitializer() {}public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {LinkedList initializers = new LinkedList();Iterator var4;if(webAppInitializerClasses != null) {var4 = webAppInitializerClasses.iterator();while(var4.hasNext()) {Class initializer = (Class)var4.next();if(!initializer.isInterface() && !Modifier.isAbstract(initializer.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(initializer)) {try {initializers.add((WebApplicationInitializer)initializer.newInstance());} catch (Throwable var7) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);}}}}if(initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");} else {servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);var4 = initializers.iterator();while(var4.hasNext()) {WebApplicationInitializer initializer1 = (WebApplicationInitializer)var4.next();initializer1.onStartup(servletContext);}}}
}
这个类上面有@HandlesTypes({WebApplicationInitializer.class})
这个注解,这个注解的作用是将其value中配置的一些类放入到ServletContainerInitializer
。
initializers.add((WebApplicationInitializer)initializer.newInstance());
最后通过循环去执行WebApplicationInitializer
中的onStartup
方法来实现里面的具体的具体的逻辑。
while(var4.hasNext()) {WebApplicationInitializer initializer1 = (WebApplicationInitializer)var4.next();initializer1.onStartup(servletContext);
}
那问题来了,Tomcat容器怎么知道先执行这个SpringServletContainerInitializer
类?
这里涉及一个知识点SPI机制
,SPI
全称为 Service Provider Interface
,是一种服务发现机制。SPI机制
是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI机制
为我们的程序提供拓展功能。
Tomcat启动过程中查找所有的ServletContainerInitializer
实现类然后添加到StandardContext的initializers
集合中,然后执行里面的onStartup
方法。
Spring中SPI就是通过SpringServletContainerInitializer
类来实现的
关于Web应用的启动过程在《一个基于注解配置的Web项目的启动流程分析》这篇文章写的很好。
4、利用SPI我们能做什么?
可以加一些自己的启动配置信息,把自己的Servlet打成jar包放到Tomcat服务器或者其他工程中执行。我们可以实现一个自己的SPI接口。
4.1、定义一个MyWebAppInitializer
public interface MyWebAppInitializer {void loadOnStart(ServletContext var1) throws ServletException;
}
4.2、定义一个MySpringServletContainerInitializer
- 实现
ServletContainerInitializer
接口 - 修改
@HandlesTypes
为我们自己定义的MyWebAppInitializer.class
- 实例化
MyWebAppInitializer
的实现类,并且调用接口的loadOnStart
方法
@HandlesTypes(MyWebAppInitializer.class)
public class MySpringServletContainerInitializer implements ServletContainerInitializer{@Overridepublic void onStartup(Set<Class<?>> set, ServletContext servletcontext)throws ServletException {if (set != null) {for (Class<?> waiClass : set) {if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&MyWebAppInitializer.class.isAssignableFrom(waiClass)) {try {//创建MyWebAppInitializer实现类的对象,并调用loadOnStart方法((MyWebAppInitializer) waiClass.newInstance()).loadOnStart(servletcontext);} catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}}
}
4.3、写一个MyWebAppInitializer
的实现类
public class MyWebApplicationInitializerTest implements MyWebAppInitializer{@Overridepublic void loadOnStart(ServletContext servletContext){System.out.println("启动执行MyWebApplicationInitializerTest的loadOnStart方法");//注册一个为名字call的servletServletRegistration.Dynamic servletReg = servletContext.addServlet("call", CallServlet.class);servletReg.setLoadOnStartup(1);servletReg.addMapping("/call");}
}
其中里面的CallServlet.java
如下
public class CallServlet extends HttpServlet {private static final long serialVersionUID = 3684613967452881093L;@Overridepublic void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String name = req.getParameter("name");resp.getWriter().write(name + ", if you like me, please call me!");}
}
4.4、添加配置文件javax.servlet.ServletContainerInitializerr
添加位置为:src -> main -> resources-> META-INF-> services ->javax.servlet.ServletContainerInitializerr
内容:com.leo.spi.MySpringServletContainerInitializer
4.5、启动项目测试
启动日志:
启动执行MyWebApplicationInitializerTest的loadOnStart方法
浏览器测试:http://localhost:8080/springmvc/call?name=leo825
上面也提到了,可以把这个SPI的方式打成jar包在其他项目或者直接在Tomcat容器这种运行。
本文的相关源码请参考:chapter-5-springmvc-zero-configuration
spi代码包路径:com.leo.spi
https://gitee.com/leo825/spring-framework-learning-example.git
Spring中对于WebApplicationInitializer的理解相关推荐
- spring 中单利模式的理解
一.Spring单例模式与线程安全 Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方. 单例模式的意思就是只有一个实例.单例模式确保某 ...
- spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入...
<spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...
- spring(7)---深入理解Spring核心技术——Spring中的各模块详解
深入理解Spring核心技术--Spring中的各模块详解 Spring框架的两个基本概念IOC容器和AOP,相信大家现在对Spring中的这两个部分的基本概念有了一定的认识,好了,那么今天我们就来正 ...
- SpringCloud学习笔记010---杂七杂八004:Spring中Bean及@Bean的理解
Bean在Spring和SpringMVC中无所不在,将这个概念内化很重要,下面分享一下我的想法: 一.Bean是啥 1.Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例 ...
- python ioc框架_轻松理解 Spring 中的 IOC
Spring 简介 Spring 是一个开源的轻量级的企业级框架,其核心是反转控制 (IoC) 和面向切面 (AOP) 的容器框架.我们可以把 Spring 看成是对象的容器,容器中可以包含很多对象, ...
- java day59【 AOP 的相关概念[理解] 、 Spring 中的 AOP[掌握] 、 Spring 整合 Junit[掌握] 】...
第1章 AOP 的相关概念[理解] 1.1AOP 概述 1.1.1 什么是 AOP 1.1.2 AOP 的作用及优势 1.1.3 AOP 的实现方式 1.2AOP 的具体应用 1.2.1 案例中问题 ...
- Spring中Bean及@Bean的理解
随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) from:https://www.cnblogs.com/bossen/p/5824067.html Bean ...
- java的lookup方法_深入理解Spring中的Lookup(方法注入)
前言 本文主要给大家介绍了关于Spring中Lookup(方法注入)的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 在使用Spring时,可能会遇到这种情况:一个单例的Be ...
- 谈谈自己对Spring中IOC和AOP的理解
Spring框架的核心思想主要是IOC和AOP的思想 IOC IOC概念 Spring中的IOC AOP AOP概念 百度百科的解释 个人理解 AOP思想 IOC IOC概念 所谓IOC即 Inver ...
最新文章
- 怎么让div显示一行,其余的隐藏。
- HDU 6143 Killer Names(排列+容斥,dp)
- 欢迎大家踊跃报名担当“讲师”
- Overview-ISA-2004-SP3
- java 只显示文本文件_Java设计并实现一个应用程序,能够读取一个文本文件中的内容并显示,同时能够计算出文本中的行数。...
- 扬尘监测系统_工地扬尘监测_工地扬尘监测解决方案
- php编译成二进制文件_2020年小米高级 PHP 工程师面试题
- mysql入门优化_MySQL数据库:MySQL十大优化技巧详解
- 小米键盘 键盘切换_“年轻人的第一把机械键盘”,小米机械键盘到底值不值...
- 所需即所获:像IDE一样使用 vim
- linux 部署 ibase4j,ibase4j学习
- C站一名 普通技术博主 的终端与【开端】,因为热爱,所以习惯,2021~2022
- 嵌入式软件开发到底是干什么的?
- 用idea对git的merge进行撤销
- php中怎么批量修改图片大小,怎么批量修改图片大小 光影魔术手批量处理图片...
- BugkuCTF 秋名山老司机wp
- js在ie下打开对话窗口的方式
- Nginx正则表达式locationrewrite
- 苹果7服务器是什么系统版本,最新系统 iOS14.7 Beta1 版本推出!
- 点餐系统-----数据库设计
热门文章
- 90年代谁最强?乔丹不可撼动石佛上榜
- SAP标准工单入库时产生成本差异-求解进行时
- 会计记忆总结之七:财产清查
- BASIS--Client 锁定和解锁
- 打车APP大数据宰客套路多:苹果比安卓贵、熟客比新客贵
- 2021热度不减的在线教育,正在努力成为线下教育的有益补充
- 华为q1设置虚拟服务器,如何使用华为华为Q1 Q1互联网路由设置图文教程 | 192.168.1.1手机登陆...
- 容易答错的java面试题_Java程序员面试中最容易答错的8道面试题,你中招了吗?...
- 基于c#的相关性分析_开源Math.NET基础数学类库使用(11)C#计算相关系数
- Swift 十进制二进制转换 (How to convert a decimal number to binary in Swift)