SpringMVC源码深度解析之SpringServletContainerInitializer原理分析
SpringMVC
对SpringMVC或者其它比较成熟的MVC框架而言,解决的问题无外乎以下几点:
- 将web页面的请求传给服务器
- 根据不同的请求处理不同的逻辑单元
- 返回处理结果数据并跳转至响应的页面
Servlet与SpringMVC之间的关系
Spring的MVC是基于Servlet功能实现的,通过实现Servlet接口的DispatcherServlet来封装其核心功能实现。
快速搭建Servlet环境
<dependencies> <!-- 添加Servlet支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> </dependencies>
servlet线程是否安全?
不安全,构造函数只执行一次
ServletContainerInitializer接口
在web容器启动时会做一些初始化的工作,例如注册servlet或者filtes等,servlet规范中通过ServletContainerInitializer实现此功能。
每个框架要使用ServletContainerInitializer就必须在对应的jar包的META-INF/services 目录创建一个名为javax.servlet.ServletContainerInitializer的文件,文件内容指定具体的ServletContainerInitializer实现类。
1、Servlet容器启动会扫描,当前应用里面每一个jar包的ServletContainerInitializer的实现
2、提供ServletContainerInitializer的实现类;必须绑定在META-INF/services/javax.servlet.ServletContainerInitializer,文件的内容就是ServletContainerInitializer实现类的全类名;META-INF:tomcat默认就会去读取的
案例演示:
@HandlesTypes(value = MyHandlesType.class)//该注解声明的类,会被注入到set中,如果没有合适的类,set为null public class MyServletContainerInitializer implements ServletContainerInitializer { /** * @param set 感兴趣类型 也就是MyHandlesType 所有子类型 * @param servletContext * @throws ServletException */ public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException { // 1.打印所有感兴趣的类型 for (Class<?> c : set) { System.out.println(c); } // 2.servletContext 手动注册过滤器、servlet、监听器 ServletRegistration.Dynamic payServlet = servletContext.addServlet("payServlet", new PayServlet()); payServlet.addMapping("/pay"); } }
基于注解方式构建SpringMVC框架
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <!-- 添加Servlet支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> </dependencies>
springmvc是如何实现无web.xml配置,靠的就是ServletContainerInitializer
SpringServletContainerInitializer的作用:加载一些第三方的依赖信息
@RestController public class IndexController { @RequestMapping(value = "/",produces="text/html;charset=UTF-8") public String index() { return "success..."; } /** * springmvc环境的时候需要配置那些东西? * SpringMVC启动的时候如何实现没有web.xml */ }
@Configuration @ComponentScan("com.mayikt.controller") @EnableWebMvc public class SpringMvcConfig { //@EnableWebMvc 等于开启SpringMVC注解方式 //@Configuration xml // @ComponentScan("com.mayikt.controller") mvc 扫包范围 //DispatcherServlet }
public class WebInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { // 1.启动SpringMVC 容器 类注入到Spring中 AnnotationConfigWebApplicationContext app = new AnnotationConfigWebApplicationContext();// 启动SpringMVC Web // 2.注入我们的springmvc 的配置文件 app.register(SpringMvcConfig.class); // 3. 将我们的DispatcherServlet 注入到 serlvet容器中 ServletRegistration.Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(app)); // 4.填写url路径映射 dynamic.addMapping("/"); dynamic.setLoadOnStartup(1);// 优先级最高表示 最早被加载 } // 基本配置已经ok呢? web.xml ? 使用WebApplicationInitializer 替代web.xml //为什么这个类WebInitializer 不需要注解呢? 能够自动的找到该类呢? }
SpringServletContainerInitializer源码分析
SpringServletContainerInitializer:
Servlet3.0引入的接口,用在web应用启动时动态添加servlet、filter和listener
基于spi机制,
META-INF/services/javax.servlet.ServletContainerInitializer文件中存放实现该接口的类,这些类会被容器调用;只能使用在jar文件中,不能在web项目中使用。
进入:org.springframework.web.SpringServletContainerInitializer
@HandlesTypes({WebApplicationInitializer.class}) public class SpringServletContainerInitializer implements ServletContainerInitializer { public SpringServletContainerInitializer() { } public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { ... }
SpringServletContainerInitializer 为spring中实现ServletContainerInitializer接口的唯一类,该类主要是从容器获取实现WebApplicationInitializer的类,并且按照次序(javax.annotation.Priority
)调用其onStartup
方法
我们定义的WebInitializer实现了WebApplicationInitializer接口
public class WebInitializer implements WebApplicationInitializer { public void onStartup(javax.servlet.ServletContext servletContext) throws ServletException { .... } }
原理:实现了WebApplicationInitializer 接口的类会被Spring初始化;由于web项目中不能使用spi机制(未定位),所以如果需要动态添加servlet、filter和listener,就可以实现该接口,交由spring初始化。
springmvc是如何替代web.xml
使用:SpringServletContainerInitializer 提供给SpringMVC实现初始化
debug:可以看到WebApplicationInitializer子类有我们自定义的WebInitializer
本文参考:
文档:https://docs.oracle.com/javaee/7/api/javax/servlet/ServletContainerInitializer.html?is-external=true
转载于:https://my.oschina.net/u/3995125/blog/3081947
- Spring-web源码解析之Initializer2-SpringServletContainerInitializer
- SpringBoot2 | Spring AOP 原理深度源码分析
- (Spring源码解析)一步一步分析,springMVC项目启动过程(一)
- Spring-boot之启动原理--源码分析+实现ApplicationContextInitializer和SpringApplicationRunListener
- Jsp/Servlet整合Spring原理及源码分析
- SpringMVC源码深度解析之拦截器&过滤器&视图层&异步源码分析
- SpringMVC源码深度解析之DispatcherServlet源码分析
- springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
- Spring源码解析之四 ------ AOP原理和源码分析
- springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
- springMVC源码分析--@SessionAttribute用法及原理解析SessionAttributesHandler和SessionAttributeStore
- springmvc应用程序使用maven部署到tomcat中时产生的异常的解决(javax/servlet/ServletContext&SpringServletContainerInitializer->javax.servlet.ServletContainerInitializer)
- (Spring源码解析)一步一步分析,springMVC项目启动过程(二)
- Spring MVC源码分析—Servlet解析
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]
- Spring MVC - 理解 SpringServletContainerInitializer
- cvMorphology形态学原理解析及源码分析
- Spring2.5源码解读 之 基于annotation的Controller实现原理分析(1)
- Spring之SpringMVC的RequestToViewNameTranslator(源码)分析
- Caused by:....SpringServletContainerInitializer cannot be cast to javax.servlet.ServletContainerInit