1、spring父子容器配置

父子容器

spring设计了两个容器,它们作为父子关系存在,如图所示:

 

父容器将被包含在子容器里,所以子容器可以拿到父容器内的bean,但父容器却拿不到子容器的bean;这也保证了controller可以注入service或者dao,但是service和dao不能注入controller;

当然,你也可以只使用一个容器,如图所示:

但是这样将会存在注入的风险,所以构建父子容器可以提升安全。

web.xml配置父子容器

搭建springmvc项目,实际上也就是配置这两个容器。而一个web容器(如tomcat)加载web应用将从web.xml这个配置文件开始,所以构建springmvc的父子容器也就是配置web.xml。

我们先看一个web.xml简化示例:

为显得清晰web.xml去掉了filter,session等配置,剩下两块内容:

1、ServletContextListener监听器的实现ContextLoaderListener和contextConfigLocation;

contextLoaderListener实现了ServletContextListener,它将会监听ServletContext的生命周期。当ServletContext初始化以后将会触发contextLoaderListener实现的contextInitialized方法。spring的父容器也就是从这里切入,构建spring自己的容器。

父容器的配置文件从哪里来呢?也就是context-param标签定义的contextConfigLocation的值。context-param定义的键值对将会在解析web.xml的时候加载到servletContext中,在contextInitialized方法构建spring容器的时候将从servletContext中获取该配置,从而构建spring父容器。

2、DispatcherServlet前端控制器以及其contextConfigLocation;

web.xml下半部分是关于子容器的配置,子容器的切入点是从Servlet的init方法开始的。这里定义了DispatcherServlet,并且设置了初始化参数contextConfigLocation,用于初始化子容器的配置文件。

web容器在ServletContext初始化完了以后会开始实例化Servlet,并调用Servlet的init方法执行初始化,子容器将在这里创建。init-param定义了contextConfigLocation可以从servletConfig里面获取。另外,子容器创建以后,之前ContextLoaderListener创建的父容器将被组合到子容器里(如果构建的是父子容器)。

contextClass

我们注意到web.xml中无论context-param或者init-param添加的配置只有contextConfigLocation而没有contextClass,也就是仅仅指定了容器的配置文件但是未指定使用何种容器。

web项目中较长使用的contextClass有两种

1、AnnotationConfigWebApplicationContext:基于Java注解配置

2、XmlWebApplicationContext:基于XML文件配置的

较早的时候基本上都是采用XmlWebApplicationContext,而后推行 “注解化” 思想开始走向AnnotationConfigWebApplicationContext。但是如果并没有指定使用何种contextClass就会降级选择XmlWebApplicationContext。

如果你想指定父容器的contextClass可以这样指定:

如果你想指定子容器的contextClass可以这样指定:

SPI机制Java配置父子容器

上面我们都是基于web.xml配置,而Java在新的Servlet规范中提供了SPI机制来配置可以去除web.xml完全转而使用Java。

下面我们看一个无web.xml的配置示例:

配置的结构与web.xml基本没有区别。

Servlet3.0规范中提供了ServletContainerInitializer接口

单从接口的命名也可以了解到它意图用作Servlet的容器初始化,通过SPI的发现机制将会找到该接口的实现类。

spring针对该接口的实现如下

@HandlesTypes注解中定义了WebApplicationInitializer.class接口,web容器通过SPI机制回调SpringServletContainerInitializer的时候会从类路径中找到所有WebApplicationInitializer的实现类,并通过webApplicationInitializerClasses集合传入onStartup方法,所以实现WebApplicationInitializer接口的实现类将基于SPI机制,被用作初始化ServletContext。

大体是这样一个过程:

web容器 -> 通过SPI机制 -> 调用ServletContainerInitializer接口的实现类 -> 调用WebApplicationInitializer的实现类

总结

springmvc项目的配置过程始终围绕着容器,无关乎采用传统的web.xml配置方式还是采用SPI。

父容器的配置切入点是ServletContextListener监听器,在ServletContext初始化完以后触发,子容器的配置在Servlet实例化以后init方法调用触发。

你可以通过contextClass指定容器的类是XML还是Java注解,也可以通过contextConfigLocation指定容器配置的位置,如果是xml指定文件路径,如果是Java注解指定类路径。

最后,如果你不想配置父子容器只想配置单个容器,需要注意注入的安全问题。

猜你喜欢

转载自www.cnblogs.com/lay2017/p/11258731.html