Spring MVC,两个配置实例而不是一个

时间:2013-01-08 00:40:54

标签: java spring web-applications spring-mvc

我开始学习Spring MVC了。我正试图摆脱所有Spring XML配置。这是我的web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_3_0.xsd"
    version="3.0">
  <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
       instead of the default XmlWebApplicationContext -->
  <context-param>
      <param-name>contextClass</param-name>
      <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
  </context-param>

  <!-- Configuration locations must consist of one or more comma- or space-delimited
       fully-qualified @Configuration classes. Fully-qualified packages may also be
       specified for component-scanning -->
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>pl.mbrnwsk.sklep.config.AppConfiguration</param-value>
  </context-param>

  <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- Declare a Spring MVC DispatcherServlet as usual -->
  <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
           instead of the default XmlWebApplicationContext -->
      <init-param>
          <param-name>contextClass</param-name>
          <param-value>
              org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
      </init-param>
      <!-- Again, config locations must consist of one or more comma- or space-delimited
           and fully-qualified @Configuration classes -->
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>pl.mbrnwsk.sklep.config.AppConfiguration</param-value>
      </init-param>
  </servlet>

  <!-- map all requests for / to the dispatcher servlet -->
  <servlet-mapping>
      <servlet-name>dispatcher</servlet-name>
      <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

Appconfiguration.java:

@Configuration
@EnableTransactionManagement
@ComponentScan("pl.mbrnwsk.sklep")
public class AppConfiguration {

    public String hbm2ddl_auto = "update";

    public AppConfiguration(){
        System.out.println("AppConfiguration");
    }

    @Bean
    public ViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("org.hsqldb.jdbcDriver");
        ds.setUrl("jdbc:hsqldb:file:/SklepDB/");
        ds.setUsername("SA");
        ds.setPassword("");
        return ds;
    }

    @Bean
    public SessionFactory sessionFactory() {
        LocalSessionFactoryBuilder ss = new LocalSessionFactoryBuilder(dataSource());
        ss.scanPackages("pl.mbrnwsk.sklep.model");
        ss.setProperty("hibernate.show_sql", "true");
        ss.setProperty("hibernate.hbm2ddl.auto", hbm2ddl_auto);
        ss.setProperty("hibernate.dialect",
                "org.hibernate.dialect.HSQLDialect");
        return ss.buildSessionFactory();
    }

    @Bean
    public PlatformTransactionManager txManager(){
        return new HibernateTransactionManager(sessionFactory());   
    }
}

AppConfiguration的实例正在创建两次:一次是在我启动Tomcat时,两次是在我输入一些应该由调度程序处理的URL时。这不是期望的行为。我想在Tomcat启动时创建AppConfiguration。怎么做到这一点? 第二个问题,听众做了什么?

2 个答案:

答案 0 :(得分:4)

这里的问题是您对servlet和根上下文使用相同的配置。这就是为什么你有两个配置实例。在Spring MVC中,您有两个上下文,即servlet上下文和根上下文。 servlet上下文适用于您的控制器以及业务对象和服务的根上下文。

如果您不想使用XML,请创建两个配置类。像这样:

根目录

@Configuration
@EnableTransactionManagement
@ComponentScan("pl.mbrnwsk.sklep")
public class AppConfiguration {

    public String hbm2ddl_auto = "update";

    public AppConfiguration(){
        System.out.println("AppConfiguration");
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("org.hsqldb.jdbcDriver");
        ds.setUrl("jdbc:hsqldb:file:/SklepDB/");
        ds.setUsername("SA");
        ds.setPassword("");
        return ds;
    }

    @Bean
    public SessionFactory sessionFactory() {
        LocalSessionFactoryBuilder ss = new LocalSessionFactoryBuilder(dataSource());
        ss.scanPackages("pl.mbrnwsk.sklep.model");
        ss.setProperty("hibernate.show_sql", "true");
        ss.setProperty("hibernate.hbm2ddl.auto", hbm2ddl_auto);
        ss.setProperty("hibernate.dialect",
                "org.hibernate.dialect.HSQLDialect");
        return ss.buildSessionFactory();
    }

    @Bean
    public PlatformTransactionManager txManager(){
        return new HibernateTransactionManager(sessionFactory());   
    }
}

Servlet上下文

@Configuration
@ComponentScan("pl.mbrnwsk.sklep.controller")
public class ServletConfiguration {

    public AppConfiguration(){
        System.out.println("ServletConfiguration");
    }

    @Bean
    public ViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_3_0.xsd"
        version="3.0">
      <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
           instead of the default XmlWebApplicationContext -->
      <context-param>
          <param-name>contextClass</param-name>
          <param-value>
              org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
      </context-param>

      <!-- Configuration locations must consist of one or more comma- or space-delimited
           fully-qualified @Configuration classes. Fully-qualified packages may also be
           specified for component-scanning -->
      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>pl.mbrnwsk.sklep.config.AppConfiguration</param-value>
      </context-param>

      <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
      <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>

      <!-- Declare a Spring MVC DispatcherServlet as usual -->
      <servlet>
          <servlet-name>dispatcher</servlet-name>
          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
               instead of the default XmlWebApplicationContext -->
          <init-param>
              <param-name>contextClass</param-name>
              <param-value>
                  org.springframework.web.context.support.AnnotationConfigWebApplicationContext
              </param-value>
          </init-param>
          <!-- Again, config locations must consist of one or more comma- or space-delimited
               and fully-qualified @Configuration classes -->
          <init-param>
              <param-name>contextConfigLocation</param-name>
              <param-value>pl.mbrnwsk.sklep.config.ServletConfiguration</param-value>
          </init-param>
      </servlet>

      <!-- map all requests for / to the dispatcher servlet -->
      <servlet-mapping>
          <servlet-name>dispatcher</servlet-name>
          <url-pattern>/</url-pattern>
      </servlet-mapping>
</web-app>

答案 1 :(得分:0)

我发现通过将我的@Configuration类包含为ContextConfigLocation而不是通过组件扫描来识别它们,我避免了内存泄漏,其中将创建重复的ListableBeanFactories并锁定Hibernate SessionFactory。