简体   繁体   中英

is there any benefit of loading application context in root context and in servlet context?

I followed some spring mvc tutorial and my web.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>


        <param-value>/WEB-INF/spring/root-context.xml, /WEB-INF/spring/appServlet/servlet-context.xml</param-value>


    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>


            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>

        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
  <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

<session-config>
  <session-timeout>1</session-timeout>
</session-config>

</web-app>

My question is, what is the benefit of loading servlet-context.xml in root context and in servlet context both? I am a spring framework newbie and I do not understand spring framework very well.

There is no good reason to inject the exact same configuration twice in both the servlet and the root context.

The idea for having multiple contexts is the following: Most Spring MVC applications have one root context containing all service layer / DAO layer beans, and one servlet context per spring dispatcher servlet of the application, which contains (at least) the controllers of each servlet.

The idea being that is that one application might have several servlet dispatchers, for example one for URL /desktop/* and the other for URL /mobile/*, each with it's own set of different controllers.

The controllers of one servlet dispatcher are isolated from each other, meaning although they are also Spring beans, they cannot be injected in each other.

Service layer and DAO beans in the root context are visible in all servlet contexts, so Service layer beans can be injected in any controller, but not the other way around.

The root context is said to be the parent of the controller servlet context/contexts.

It's all meant to be a mechanism of isolating groups of beans from each other to ensure no unmeant dependencies are possible.

Also there are components of the Spring framework that need a root context, for example OpenSessionInViewFilter .

TLDR : it's not that it's impossible to inject servlet-context.xml in both contexts, but that is not how it's meant to be used: there will two beans of each type in two separate contexts, one can have transactions applied while the other doesn't, etc., it can quickly originate errors that are hard to troubleshoot

In Spring, ApplicationContext can be hierarchical. If you have multiple webapps in a single EAR, EAR can have its own context, which is the parent of the individual webapp contexts. Also in each webapp, you can have one root context and individual children context as well. You can define this hierarchy in web.xml. Parent context can be specified through context parameters: locatorFactorySelector and parentContextKey. Root context through context parameter contextConfigLocation(the one in context-param). Child context can be specified in the init param - param-name attribute of each of the servlet definition.

Have one jar in EAR holding all your common service and DAO layer code and define them in beanRefContext.xml(which is basically another application context xml). make this jar available in classpath.

In web.xml of each app where you want to refer parent context code:

<!--  root application context -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:rootContextBeans.xml</param-value>
</context-param>
<!--  start shared service layer - parent application context -->
<context-param>
    <param-name>locatorFactorySelector</param-name>
    <param-value>classpath:beanRefContext.xml</param-value>
</context-param>
<context-param>
    <param-name>parentContextKey</param-name>
    <param-value>servicelayer-context</param-value>
</context-param>
<!--  end shared service layer - parent application context -->
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>     
<servlet>
    <servlet-name>dispatcherServletApp1</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
        <param-name>contextConfigLocation</param-name> 
        <param-value>classpath*:webApp1.xml</param-value> 
    </init-param> 
</servlet> where beanRefContext.xml will be like:

<beans>
  <bean id="servicelayer-context" class="org.springframework.context.support.ClassPathXmlApplicationContext">
    <constructor-arg>
      <list>
        <value>data-layer-context.xml</value>
      </list>
    </constructor-arg>
  </bean>
</beans>

If your project doesn't have multi web app type, then you don't require to specify parent application context. You can move common service and DAO layer code, security to root application context(in above web.xml to rootContextBeans.xml) which can be accessed(visible) by dispatcherServlet beans (remember reverse visibility is not possible).
In your web.xml you specified, servlet-context.xml in root context contextConfigLocation and in servlet contextConfigLocation. So you need to check what beans are defined in it and where it fits exactly and remove the refernce in other place.

All of the Spring configuration files in the root directory of 'WEB-INF/spring' are loaded in the root Spring context.

This configuration is for loading anything web related into the root context, in this case it's just the web security.

For Reference: http://www.springbyexample.org/examples/contact-webapp-spring-config.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM