spring mvc基于编码配置的原理
使用spring mvc的时候需要注册DispatcherServlet,DispatcherServlet是一个前端控制器,主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。我们配置DispatcherServlet最典型的是使用web.xml文件。如下:
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
但spring3.1引入了WebApplicationInitializer接口,有了它,我们不需要配置web.xml初始化web应用,只需要继承该接口,通过编码实现相应的配置:
public class Initializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebAppConfig.class);
servletContext.addListener(new ContextLoaderListener(ctx));
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
那通过编码方式有什么好处呢?它可以充分利用编译器,在编译期间检查出配置中的错误,另外,这增强了配置的灵活性和可控性,你可以在启动过程中自定义需要的检查验证条件。
Spring mvc是跟着更底层的接口标准servlet走的,servlet3+以后引入ServletContainerInitializer接口,这为去web.xml,基于代码配置提供了一种途径:
public interface ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx)
throws ServletException;
}
Spring的SpringServletContainerInitializer 类实现了该接口:
//HandlesTypes注解标识SpringServletContainerInitializer 类启动时需要处理的类,此处专门标识了WebApplicationInitializer,正如前面所展示的,我们正是通过实现WebApplicationInitializer接口.来作一些配置工作的。
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
//以下代码对前面我们实现的WebApplicationInitializer作了循环,实例化,调用onStartUp 等 操作。
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers())
&& WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer) waiClass.newInstance());
} catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
Collections.sort(initializers, new AnnotationAwareOrderComparator());
servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
tomcat7以后采用了servlet3标准,我们启动tomcat7(servlet3容器)时,容器通过JAR Services API 机制,探测到spring-web包下的一个文件META-INF/services/javax.servlet.ServletContainerInitializer,文件内声明实现类,进而调用其onStartup方法,如果以后我们要自己实现ServletContainerInitializer ,也需要在相应jar包的 META-INF/services目录下放置这样一个以接口的全限定名命名的文件。
程序员局限于框架的使用,将始终停留于浅层次的水平,只有深入框架,理解原理,甚至阅读优化其中的源码,才是升级打怪的王道,大家有空可以去看看源码,我们随时讨论。
- R语言实现混合模型
- 数据迁移判断非空约束(r2笔记45天)
- 【专业技术】linux下socket编程
- oracle并行的小细节(r2笔记44天)
- python实现朴素贝叶斯模型:文本分类+垃圾邮件分类
- 使用闪回查询备份数据(r2笔记43天)
- 生产环境sql语句调优实战第四篇(r2笔记41天)
- 生产环境sql语句调优实战第五篇(r2笔记41天)
- python实现逻辑logistic回归:预测病马的死亡率
- 开发 | 图片数据集太少?看我七十二变,Keras Image Data Augmentation 各参数详解
- linux过滤空文件的命令总结(r2笔记40天)
- shell脚本自动化采集性能sql(r2笔记39天)
- R语言与点估计学习笔记(EM算法与Bootstrap法)
- 开发 | 为个人深度学习机器选择合适的配置
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 【python-leetcode637-树的宽度遍历】二叉树的层平均值
- graphSAGE的python实现
- 【python-leetcode111-树的宽度遍历】二叉树的最小深度
- 基于TypeScript封装Axios笔记(四)
- spring之泛型依赖注入
- 【python-leetcode113-树的深度遍历】路径总和Ⅱ
- spring之为什么要使用AOP(面向切面编程)?
- useContext更佳实践
- 【论文笔记】张航和李沐等提出:ResNeSt: Split-Attention Networks(ResNet改进版本)
- [前端]GOFLY项目-响应式登录页的设计和实现
- [GO] golang练习项目-gorm与mysql的增删查改操作
- 设计模式~门面模式
- c语言之define和typedef的区别
- TSINGSEE青犀视频官网全新改版即将上线,系统界面迎来整体升级
- c语言之带参数的宏定义