Announcement Announcement Module
Collapse
No announcement yet.
Why my ContextClosedEvent is fired three times? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Why my ContextClosedEvent is fired three times?

    Hi

    Everything is working fine but when I don't know why the ContextClosedEvent is fired 3 times when I shutdown my Spring web application.

    [16:29:55] INFO [TEST] - SHUTDOWN TASKS[http-bio-8084-exec-2]
    [16:29:55] INFO [TEST] - SHUTDOWN TASKS[http-bio-8084-exec-2]
    [16:29:55] INFO [TEST] - SHUTDOWN TASKS[http-bio-8084-exec-2]

    Any ideas? Many thanks!

    Code:
    @Component
    public class ContextClosedEventHandler implements ApplicationListener<ContextClosedEvent> {
        private static final Logger logger = Logger.getLogger("[TEST]");
        @Autowired
        private ThreadPoolTaskExecutor taskExecutor;
        @Autowired
        private ThreadPoolTaskScheduler scheduler;
    
        @Override
        public void onApplicationEvent(ContextClosedEvent e) {
            logger.info("SHUTDOWN TASKS["+ Thread.currentThread().getName()+"]");
            taskExecutor.shutdown(); 
            scheduler.shutdown();
        }
    }

  • #2
    And why should it be fired three times? COuld it be that there are 3 different instances of your Handler?... You might want to print the hashcode for the event and handler that way you have a little more information...

    Also I don't really see the point for this handler, the ThreadPoolTaskExecutor and ThreadPoolTaskScheduler are automatically shutdown when the ApplicationContext is destroyed so no need to do it yourself.

    Comment


    • #3
      Originally posted by Marten Deinum View Post
      And why should it be fired three times? COuld it be that there are 3 different instances of your Handler?... You might want to print the hashcode for the event and handler that way you have a little more information...

      Also I don't really see the point for this handler, the ThreadPoolTaskExecutor and ThreadPoolTaskScheduler are automatically shutdown when the ApplicationContext is destroyed so no need to do it yourself.
      Thanks for your reply. The code is just for testing. Also, the ContextRefreshedEvent is fired 3 times. What I want is just fire once. The event info and the hashcode is logged as follows.

      [09:59:02] INFO [TEST] - START TASKS[http-bio-8084-exec-40][org.springframework.context.event.ContextRefreshed Event[source=Root WebApplicationContext: startup date [Wed Sep 26 09:58:57 BST 2012]; root of context hierarchy]][HASHCODE=29694798]

      [09:59:02] INFO [TEST] - START TASKS[http-bio-8084-exec-40][org.springframework.context.event.ContextRefreshed Event[source=WebApplicationContext for namespace 'dispatcher-servlet': startup date [Wed Sep 26 09:59:02 BST 2012]; parent: Root WebApplicationContext]][HASHCODE=32879300]

      [09:59:02] INFO [TEST] - START TASKS[http-bio-8084-exec-40][org.springframework.context.event.ContextRefreshed Event[source=WebApplicationContext for namespace 'dispatcher-servlet': startup date [Wed Sep 26 09:59:02 BST 2012]; parent: Root WebApplicationContext]][HASHCODE=32879300]

      Comment


      • #4
        I suggest you read the logging again ...

        First there are 2 ContextClosedEvents fired which makes sense as there are 2 ApplicationContexts (ContextLoaderListener and DispatcherServlet). And both are fired once as the hashcode for the one from the dispatcherservlet is processed twice (so I suspect 2 instances of your listener).

        Comment


        • #5
          Originally posted by Marten Deinum View Post
          I suggest you read the logging again ...

          First there are 2 ContextClosedEvents fired which makes sense as there are 2 ApplicationContexts (ContextLoaderListener and DispatcherServlet). And both are fired once as the hashcode for the one from the dispatcherservlet is processed twice (so I suspect 2 instances of your listener).
          Thanks. But I don't know why there are 2 instances of the listener. Can I make it only fire once?
          Here is my web.xml.

          Code:
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app version="3.0" 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">
              <context-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>/WEB-INF/applicationContext.xml</param-value>
              </context-param>
              <listener>
                  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
              </listener>
              <servlet>
                  <servlet-name>dispatcher</servlet-name>
                  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                  <load-on-startup>1</load-on-startup>
              </servlet>
              <servlet-mapping>
                  <servlet-name>dispatcher</servlet-name>
                  <url-pattern>/</url-pattern>
              </servlet-mapping>
              <session-config>
                  <session-timeout>
                      30
                  </session-timeout>
              </session-config>
              <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>
              <welcome-file-list>
                  <welcome-file>/home</welcome-file>
              </welcome-file-list>
          </web-app>

          Comment


          • #6
            You cannot make it fire once it will at least fire twice once for each context...

            Judging from your class you use component scanning and I suspect you are scanning for the same components in both the ContextLoaderListener and DispatcherServlet.

            Comment


            • #7
              Originally posted by Marten Deinum View Post
              You cannot make it fire once it will at least fire twice once for each context...

              Judging from your class you use component scanning and I suspect you are scanning for the same components in both the ContextLoaderListener and DispatcherServlet.

              Many thanks!! I checked the component scanning and removed the overlapping then the event is fired twice. Btw, does it mean all Spring web applications need both ContextLoderListener and DispatcherServlet? Can I bind them to a single context?

              [10:58:53] INFO [TEST] - START TASKS[http-bio-8084-exec-1][org.springframework.context.event.ContextRefreshed Event[source=Root WebApplicationContext: startup date [Wed Sep 26 10:58:47 BST 2012]; root of context hierarchy]][14802865]

              [10:58:54] INFO [TEST] - START TASKS[http-bio-8084-exec-1][org.springframework.context.event.ContextRefreshed Event[source=WebApplicationContext for namespace 'dispatcher-servlet': startup date [Wed Sep 26 10:58:53 BST 2012]; parent: Root WebApplicationContext]][17925607]

              Comment


              • #8
                That depends (and in your case you cannot)... If you don't need any additional components that rely on the root context there is nothing preventing you from doing so. However in many cases there are additional components (OpenSessionInViewFilter or, as in your case, a security filter).

                It also depends on your application if you have 1 or more (Message)DispatcherServlets it is also a good practice to have a single root context that holds the shared beans.

                A solution to your problem could be to only react to events from the applicationcontext your listener is defined in (make your listener ApplicationContextAware and check that the event source is the given ApplicationContext).

                Comment


                • #9
                  Originally posted by Marten Deinum View Post
                  That depends (and in your case you cannot)... If you don't need any additional components that rely on the root context there is nothing preventing you from doing so. However in many cases there are additional components (OpenSessionInViewFilter or, as in your case, a security filter).

                  It also depends on your application if you have 1 or more (Message)DispatcherServlets it is also a good practice to have a single root context that holds the shared beans.

                  A solution to your problem could be to only react to events from the applicationcontext your listener is defined in (make your listener ApplicationContextAware and check that the event source is the given ApplicationContext).

                  How to make it ApplicationContextAware? I'm new to Spring...

                  Comment


                  • #10
                    Read the docs I would say.. You make it so by letting it implement the ApplicationContextAware interface....

                    Comment


                    • #11
                      Originally posted by Marten Deinum View Post
                      Read the docs I would say.. You make it so by letting it implement the ApplicationContextAware interface....
                      OK Thanks a lot!!

                      Comment


                      • #12
                        Originally posted by Marten Deinum View Post
                        Read the docs I would say.. You make it so by letting it implement the ApplicationContextAware interface....
                        Finally the problem is solved by using the code below.

                        Code:
                        @Autowired
                        ApplicationContext appContext;
                        
                        if (e.getApplicationContext().equals(appContext)) {
                            // do something
                        }

                        Comment

                        Working...
                        X