博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring MVC 源码解析(二)— 容器初始化
阅读量:7098 次
发布时间:2019-06-28

本文共 8163 字,大约阅读时间需要 27 分钟。

1、什么是servlet容器

servlet我们可以把它理解成是基于java语言的web组件,每一个servlet都有自己的生命周期包括init()service()destroy()而这些都是通过servlet container管理的。客户端通过servlet 容器实现的 request/response paradigm(请求/应答模式)与servlet进行交互。Servlet Container 是 Web 服务器或者应用服务器的一部分,用于提供基于请求/响应发送模式的网络服务,解码基于 MIME(全称是"Multipurpose Internet Mail Extensions",中译为"多用途互联网邮件扩展",指的是一系列的电子邮件技术规范) 的请求,并且格式化基于 MIME 的响应。Servlet 容器可以嵌入到宿主的 Web 服务器中,或者通过 Web 服务器的本地扩展 API 单独作为附加组件安装。Servelt 容器也可能内嵌或安装到启用 Web 功能的应用服务器中。目前 Spring boot 就内嵌了 tomcat、jetty等web容器。

2、Servlet 容器初始化时 Spring Mvc 都做了什么

在web.xml的文件中可看到如下配置:

org.springframework.web.context.ContextLoaderListener
复制代码

这个配置的意思是在servlet 容器中增加一个监听器,当容器初始化的时候会抛出ServletContextEvent事件,监听器监听到该事件就会调用 ContextLoaderListener.contextInitialized(ServletContextEvent event)方法来初始化Spring mvc rootContext

/**	 * Initialize the root web application context.	 */	@Override	public void contextInitialized(ServletContextEvent event) {		initWebApplicationContext(event.getServletContext());	}复制代码

3、Spring Mvc 容器结构

Spring Mvc 的容器是分层的,当我们的web应用有多个servlet的时候,一些公共的资源(bean)就可以放在root WebApplicationContext 中 比如dataSourceservice等,在Spring Mvc中 每一servlet 都有对应的属于自己的一个servlet WebApplicationContext 这些ControllersViewResolver等就可以放到与之相关连的WebapplicationContext 中:

当我们只有一个
servlet 时,当然可以把所以的
bean 都交由
root WebApplicationContext 来管理,这样
Spring Mvc 就会通过代理的形式生成一个空的与之对应的容器。

4、java 配置容器

servlet 3.0 以后支持用过java 代码来配置容器,servlet提供了一个接口:

public interface ServletContainerInitializer {    /**     * Receives notification during startup of a web application of the classes     * within the web application that matched the criteria defined via the     * {@link javax.servlet.annotation.HandlesTypes} annotation.     *     * @param c     The (possibly null) set of classes that met the specified     *              criteria     * @param ctx   The ServletContext of the web application in which the     *              classes were discovered     *     * @throws ServletException If an error occurs     */    void onStartup(Set
> c, ServletContext ctx) throws ServletException;}复制代码

servlet 容器在启动的时候回到 classpath 下扫描这个接口的实现。spring Mvc 分装了一层代理实现了这个接口:

@Override	public void onStartup(Set
> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List
initializers = new LinkedList
(); 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; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } }复制代码

在实际使用中只要实现Spring Mvc 为我们提供的接口即可;

public interface WebApplicationInitializer {	/**	 * Configure the given {@link ServletContext} with any servlets, filters, listeners	 * context-params and attributes necessary for initializing this web application. See	 * examples {@linkplain WebApplicationInitializer above}.	 * @param servletContext the {@code ServletContext} to initialize	 * @throws ServletException if any call against the given {@code ServletContext}	 * throws a {@code ServletException}	 */	void onStartup(ServletContext servletContext) throws ServletException;}复制代码

我们可以通过这个接口来完成servlet 容器 以及 Spring Mvc 容器的初始化工作,这样做就可以将项目中的配置文件彻底消灭掉。

5、如何消灭配置文件

去除 web.xml

demo
org.springframework.web.servlet.DispatcherServlet
1
contextConfigLocation
/WEB-INF/spring-mvc-servlet.xml
demo
/*
contextConfigLocation
/WEB-INF/spring-mvc-servlet.xml
org.springframework.web.context.ContextLoaderListener
CharacterEncoding
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncoding
/*
复制代码

通过java 代码可以将其改造为:

public class DemoServletinitializer implements WebApplicationInitializer {    @Override    public void onStartup(ServletContext servletContext) throws ServletException {        //初始化root WebApplicationContext        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();        rootContext.register(DemoRootApplicationContextConfiguration.class);        servletContext.addListener(new ContextLoaderListener(rootContext));        //初始化 servlet WebApplicationContext        AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();        webApplicationContext.register(DemoWebMvcConfiguration.class);        //注册 servlet        ServletRegistration.Dynamic registration = servletContext.addServlet("demo", new DispatcherServlet(webApplicationContext));        registration.setLoadOnStartup(1);        registration.addMapping("/");        //注册 filter        FilterRegistration.Dynamic characterEncoding = servletContext.addFilter("characterEncoding", CharacterEncodingFilter.class);        characterEncoding.setInitParameter("encoding", "UTF-8");        characterEncoding.setInitParameter("forceEncoding", "true");    }}复制代码

去除 xxx-servlet.xml

复制代码

等价于java 配置: Root WebAppicationContext 配置

@Configuration@ComponentScan("demo")public class DemoRootApplicationContextConfiguration {    @Bean    public ContentNegotiatingViewResolver contentNegotiatingViewResolver() {        ContentNegotiatingViewResolver viewResolver = new ContentNegotiatingViewResolver();        viewResolver.setDefaultViews(Lists.
newArrayList(mappingJackson2JsonView())); return viewResolver; } @Bean public MappingJackson2JsonView mappingJackson2JsonView() { MappingJackson2JsonView jsonView = new MappingJackson2JsonView(); jsonView.setExtractValueFromSingleKeyModel(true); return jsonView; } @Bean public DataSource dataSource() { // add data source config return null; }}复制代码

servlet WebApplicationContext 配置

@ComponentScan("demo")@Configuration@EnableWebMvcpublic class DemoWebMvcConfiguration extends WebMvcConfigurerAdapter {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new DemoInterceptor());    }    @Bean    public InternalResourceViewResolver internalResourceViewResolver() {        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();        viewResolver.setPrefix("/WEB-INF/jsp/");        viewResolver.setSuffix(".jsp");        return viewResolver;    }}复制代码

这样就可以将web.xml、xxx-servlet去除掉了,再也不用看到烦人的配置文件了。 当然 spring Mvc 还提供了一些抽象类来简化配置工作,这里为了更方便的解释java 配置的过程所以没有直接使用。对这一部分有兴趣的同学可以自己查看 AbstractAnnotationConfigDispatcherServletInitializer源码。

转载地址:http://rkeql.baihongyu.com/

你可能感兴趣的文章
rust安装
查看>>
CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI解析
查看>>
Ubuntu安装svn服务备忘录
查看>>
hadoop集群之间的hdfs文件拷贝
查看>>
JFileChooser to open multiple txt files
查看>>
我所遇到的GitLab 502问题的解决
查看>>
转 配置虚拟主机
查看>>
Linux服务器安装Redis数据库
查看>>
攻城狮的苦逼选车经历
查看>>
SVN设置忽略文件列表
查看>>
我的友情链接
查看>>
yii2.x之web配置
查看>>
Excel Automation & Windows Server 2008 x64
查看>>
带身份验证的Cisco NTP 实验详解
查看>>
Chrome还原“应用”标签页
查看>>
openstack组件之keystone
查看>>
小球从100米高空落下,来会反弹10次后经过的路程和第10次反弹的高度
查看>>
二进制编译 http
查看>>
redis集群
查看>>
etcd 安装与集群配置
查看>>