0

I have a question about spring context. My application's using spring and spring scheduler. In web.xml, i declared:

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

My question is:

If I declared org.springframework.web.context.ContextLoaderListener in web.xml, the scheduler will run twice, all beans are duplicate, and App start-up time about 160 seconds.

If I remove org.springframework.web.context.ContextLoaderListener, spring throws exception: No WebApplicationContext found: no ContextLoaderListener registered. And App start-up time reduce to 80 seconds.

How can i solve it? Thanks all!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
namtn
  • 71
  • 1
  • 6
  • 1
    Split your configuration. Don't make the `ContextLoaderListener` and `DispatcherServlet` load the same configuration files. If you do that everything will be loaded twice. – M. Deinum Mar 31 '15 at 08:41
  • Why do you even think about using XML config? It's 2015 - http://www.kubrynski.com/2014/01/understanding-spring-web-initialization.html – Jakub Kubrynski Mar 31 '15 at 10:14

3 Answers3

0

Thanks @M.Deinum, but i don't understand your idea. Here is my web.xml:

<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.htc.epos.api.bootstrap</param-value>
  </context-param>

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

  <servlet>
    <servlet-name>webapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <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.htc.epos.api.bootstrap.WebAppConfig
              com.htc.epos.api.bootstrap.AppConfig
      </param-value>
    </init-param>
  </servlet>
namtn
  • 71
  • 1
  • 6
0

Think @M.Deinum is right; split your beans via what is remoting and what is normal. I do this in my web.xml:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/classes/spring/root-context.xml</param-value>
</context-param>

<servlet>
    <servlet-name>remoting</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/spring/remoting-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>remoting</servlet-name>
    <url-pattern>/remoting/*</url-pattern>
</servlet-mapping>

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

root-context.xml contains all my normal beans (services, helpers, calculator, jms listeners, scheduled tasks, etc).

remoting-servlet.xml only specifies those services that need to be exposed via the HttpInvokerServiceExporter. There are no imports or links to beans defined in the root, other than things like ref="historyWebService" for the exporter.

From what I understand, you end up with 2 application context: 1 root and 1 remoting. The remoting one inherits all the beans from the root so you don't declare or instantiate beans twice (i think)!!! I certain don't appear to have duplicate beans produced (i.e. 2 task, 2 jms listeners, etc).

shuttsy
  • 1,585
  • 2
  • 19
  • 34
  • Actually, I'm using annotation for configuration. – namtn Mar 31 '15 at 10:34
  • Then the 2 xml files can be simple component-scan over the appropriate packages. That way, you maintain some level of control of which beans are loaded into which context. – shuttsy Mar 31 '15 at 10:49
0

I have 2 file config:

1. AppConfig:

    @Configuration
    @EnableScheduling
    @EnableTransactionManagement
    @EnableJpaRepositories("com.test.api.repository")
    @PropertySource("classpath:application.properties")
    public class AppConfig {
          ...............
    }

2. WebInitializer

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

  @Override
  protected Class<?>[] getRootConfigClasses() {
    return new Class<?>[0];
  }

  @Override
  protected Class<?>[] getServletConfigClasses() {
    return new Class<?>[] { WebAppConfig.class };
  }

  @Override
  protected String[] getServletMappings() {
    return new String[] { "/" };
  }

  @Configuration
  @EnableWebMvc
  @ComponentScan(basePackages = {"com.test.api"})
  public static class WebAppConfig extends WebMvcConfigurerAdapter {

    ...................
   }
}

In WebAppConfig, if I change @ComponentScan(basePackages = {"com.test.api"}) to web package @ComponentScan(basePackages = {"com.test.api.web"}), so spring bean's not duplicate and scheduler not run twice. But sometime it throw exception:

 error: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
namtn
  • 71
  • 1
  • 6