71

What is the correct way to use the two contexts: dispatcher-servlet.xml and applicationContext.xml? What goes where?

I want to write a fairly typical app deployed in a servlet container. It has some controllers with JSP views. It also has some nontrivial logic on the back-end. Do I really need both contexts? How are they related to each other? How can I decide what to put in which?

Also, I want to use Spring-security for my application. I may want to use its features (like declarative security with annotations) in web controllers as well as in deeper layers. How should I configure security to work in this case? Should it be in one of those files (which?), or both?

Konrad Garus
  • 53,145
  • 43
  • 157
  • 230

6 Answers6

85

The dispatcher-servlet.xml file contains all of your configuration for Spring MVC. So in it you will find beans such as ViewHandlerResolvers, ConverterFactories, Interceptors and so forth. All of these beans are part of Spring MVC which is a framework that structures how you handle web requests, providing useful features such as databinding, view resolution and request mapping.

The application-context.xml can optionally be included when using Spring MVC or any other framework for that matter. This gives you a container that may be used to configure other types of spring beans that provide support for things like data persistence. Basically, in this configuration file is where you pull in all of the other goodies Spring offers.

These configuration files are configured in the web.xml file as shown:

Dispatcher Config

<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/servlet-context.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>

Application Config

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/application-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>

To configure controllers, annotate them with @Controller then include the following in the dispatcher-context.xml file:

<mvc:annotation-driven/>
<context:component-scan base-package="package.with.controllers.**" />
Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
  • 11
    Where should I put my MVC controllers? Where should I configure spring security? – Konrad Garus May 09 '13 at 09:55
  • 2
    @KonradGarus Can you answer this question yourself now? How did you eventually configure your project? – dev_feed Jul 21 '14 at 11:34
  • 1
    @Kevin Bowersox does that mean there will be two separate containers instantiated? If so, how does one relate to the other? I followed this approach and it seems that the beans defined in the general application-context.xml can be accessed from MVC controllers defined in the dispatcher-servlet.xml. – AtomHeartFather Jul 27 '14 at 17:19
  • can we use @Configuration also even if we have dispatcher servlet ? – Ashish Parab Aug 29 '20 at 12:32
47

To add to Kevin's answer, I find that in practice nearly all of your non-trivial Spring MVC applications will require an application context (as opposed to only the spring MVC dispatcher servlet context). It is in the application context that you should configure all non-web related concerns such as:

  • Security
  • Persistence
  • Scheduled Tasks
  • Others?

To make this a bit more concrete, here's an example of the Spring configuration I've used when setting up a modern (Spring version 4.1.2) Spring MVC application. Personally, I prefer to still use a WEB-INF/web.xml file but that's really the only xml configuration in sight.

WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  
  <filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
  </filter>
  
  <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>

  <filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <servlet>
    <servlet-name>springMvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.company.config.WebConfig</param-value>
    </init-param>
  </servlet>
  
  <context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.company.config.AppConfig</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet-mapping>
    <servlet-name>springMvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>

  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
  </jsp-config>
  
</web-app>

WebConfig.java

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.company.controller")
public class WebConfig {

  @Bean
  public InternalResourceViewResolver getInternalResourceViewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/views/");
    resolver.setSuffix(".jsp");
    return resolver;
  }
}

AppConfig.java

@Configuration
@ComponentScan(basePackages = "com.company")
@Import(value = {SecurityConfig.class, PersistenceConfig.class, ScheduleConfig.class})
public class AppConfig {
  // application domain @Beans here...
}

Security.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  private LdapUserDetailsMapper ldapUserDetailsMapper;

  @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
      .antMatchers("/").permitAll()
      .antMatchers("/**/js/**").permitAll()
      .antMatchers("/**/images/**").permitAll()
      .antMatchers("/**").access("hasRole('ROLE_ADMIN')")
      .and().formLogin();

    http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
    }

  @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth.ldapAuthentication()
      .userSearchBase("OU=App Users")
      .userSearchFilter("sAMAccountName={0}")
      .groupSearchBase("OU=Development")
      .groupSearchFilter("member={0}")
      .userDetailsContextMapper(ldapUserDetailsMapper)
      .contextSource(getLdapContextSource());
    }

  private LdapContextSource getLdapContextSource() {
    LdapContextSource cs = new LdapContextSource();
    cs.setUrl("ldaps://ldapServer:636");
    cs.setBase("DC=COMPANY,DC=COM");
    cs.setUserDn("CN=administrator,CN=Users,DC=COMPANY,DC=COM");
    cs.setPassword("password");
    cs.afterPropertiesSet();
    return cs;
  }
}

PersistenceConfig.java

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(transactionManagerRef = "getTransactionManager", entityManagerFactoryRef = "getEntityManagerFactory", basePackages = "com.company")
public class PersistenceConfig {

  @Bean
  public LocalContainerEntityManagerFactoryBean getEntityManagerFactory(DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
    lef.setDataSource(dataSource);
    lef.setJpaVendorAdapter(getHibernateJpaVendorAdapter());
    lef.setPackagesToScan("com.company");
    return lef;
  }

  private HibernateJpaVendorAdapter getHibernateJpaVendorAdapter() {
    HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
    hibernateJpaVendorAdapter.setDatabase(Database.ORACLE);
    hibernateJpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");
    hibernateJpaVendorAdapter.setShowSql(false);
    hibernateJpaVendorAdapter.setGenerateDdl(false);
    return hibernateJpaVendorAdapter;
  }

  @Bean
  public JndiObjectFactoryBean getDataSource() {
    JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
    jndiFactoryBean.setJndiName("java:comp/env/jdbc/AppDS");
    return jndiFactoryBean;
  }

  @Bean
  public JpaTransactionManager getTransactionManager(DataSource dataSource) {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(getEntityManagerFactory(dataSource).getObject());
    jpaTransactionManager.setDataSource(dataSource);
    return jpaTransactionManager;
  }
}

ScheduleConfig.java

@Configuration
@EnableScheduling
public class ScheduleConfig {
  @Autowired
  private EmployeeSynchronizer employeeSynchronizer;

  // cron pattern: sec, min, hr, day-of-month, month, day-of-week, year (optional)
  @Scheduled(cron="0 0 0 * * *")
  public void employeeSync() {
    employeeSynchronizer.syncEmployees();
  }
}

As you can see, the web configuration is only a small part of the overall spring web application configuration. Most web applications I've worked with have many concerns that lie outside of the dispatcher servlet configuration that require a full-blown application context bootstrapped via the org.springframework.web.context.ContextLoaderListener in the web.xml.

Community
  • 1
  • 1
Brice Roncace
  • 10,110
  • 9
  • 60
  • 69
1
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  http://www.springframework.org/schema/cache 
        http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

        <mvc:annotation-driven/>
        <context:component-scan base-package="com.testpoc.controller"/>

        <bean id="ViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="ViewClass" value="org.springframework.web.servlet.view.JstlView"></property>
            <property name="prefix">
                <value>/WEB-INF/pages/</value>
            </property>
            <property name="suffix">
                <value>.jsp</value>
            </property>
        </bean>

</beans>
0
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<mvc:resources mapping="/resources/**" location="/resources/" />

<context:component-scan base-package="com.tridenthyundai.ains" />

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

<bean id="messageSource" 
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="/WEB-INF/messages" />
</bean>

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="prefix">
        <value>/WEB-INF/pages/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

mohan
  • 9
0
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd ">

    <mvc:annotation-driven />
    <mvc:default-servlet-handler />
    <mvc:resources mapping="/resources/**" location="/resources/" />

    <context:component-scan base-package="com.sapta.hr" />

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

    <bean id="messageSource" 
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/messages" />
    </bean>

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

</beans>
-2
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>TestPOC</display-name>

  <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • The mvc-dispatcher-servlet.xml should be declared as an init-param to the mvc-dispatcher servlet entry, not in context-param (that is for the app context.) – Glen Mazza May 30 '18 at 07:43