Announcement Announcement Module
Collapse
No announcement yet.
'PostDestroy' and need for registerShutdownHook Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 'PostDestroy' and need for registerShutdownHook

    I have noticed some things about the way that the 'PostDestroy' annotated methods seem to get invoked or not, and was just wondering if someone could confirm what I am seeing.

    I am running Spring Batch 2.0.0/Spring2.5.6 in an ordinary JVM. I have a Parent/root application context, which has one child application context.

    'PostDestroy' annotated methods on beans in the child application context seem to get run without any bother, whilst 'PostDestroy' annotated methods in the parent application context do not get run unless I call the 'registerShutdownHook' method explicitly on that parent application context when I create it. Both application contexts use the '<context:annotation-config />' entry in the config. I have no problem with it, but it is not clear from the documentation (I have seen) if this is what is expected, and I just want to understand better. The full story seems to be that by default, when a job ends the 'doClose' method on the lower/child application context is the only 'doClose' method that runs. The 'doClose' methods on other application contexts’ up the hierarchy only seem to run if the shutdown hook has been explicitly registered on them.

    I know certain activities are scoped to the containing application context, (componet-scan; annotation-config; aspectj-autoproxy etc), but was not aware of what I appear to be seeing here.

    Is this as expected? If so, are there any other aspects which are confined to the lower level application context like this, unless explicitly activated on the parent application contexts’?

  • #2
    This probably isn't the right forum for this type of question, since it's really about spring DI in general, and not specific to batch. I will say that most people use @AfterJob for cleanup that needs to be done after a job finishes, and I would say that is the recommended approach, since it will work regardless of the ApplicationContext lifecyle.

    Comment


    • #3
      Thanks for the reply. Yes, looking back, this clearly is not a 'Batch' question and @AfterJob does seem the natural thing for Batch. I got side tracked and distracted down that path! Thanks for the pointer.

      Comment


      • #4
        I have been thinking about this some more.

        I am to provide a number of 'Service' type beans which numerous Jobs across many applications are to utilise. I got onto the @PreDestroy mechanism as it seemed a good way to release the resources of these services. If I go the @AfterJob way, I have to then get each application to include all/many of my services as listeners on their jobs or a number of 'parent' Jobs. @PreDestroy does not necessitate this action, and so makes my services less intrusive and impacting on the application. Having explained myself more, does it make sense to use @PreDestroy over @AfterJob?

        I will also pose the original question on the Core Container forum.

        Thanks

        Simon

        Comment


        • #5
          I think I would need to hear more about these services. It sounds like a very online pattern applied to batch jobs, and would potentially prevent any type of optimizations you might try to make. For example, in a batch job, taking a couple of minutes to load up and cache some reference data is no problem, and it can just be stored in memory since it really only needs to be accurate for that run of the job. That same approach doesn't really apply to online necessarily for the same reasons that your services used by multiple jobs might have issues. Of course, there's always exceptions, and your individual case might be fine.

          Comment


          • #6
            I think I see what you are saying. But I think I may have misled you a bit, I am sure my ‘services’ are not as grand as you might think. All ‘services’ I talk about are just beans within the Job’s application context – more like utilities and helpers really I suppose. For instance, one such service bean provides a common logging mechanism to our scheduler’s job specific output file (or other nominated file). In this case, I wanted to close the stream for the file when the job ended/application context closed, and so thought @PreDestroy would suit.

            Comment


            • #7
              @PreDestroy is a good solution for that kind of use case. The callback comes only one ConfigurableApplicationContext.close() and only if it is regsistered with the context (by including a CommonAnnotationBeanPostProcessor or using the <context:annotation-config/> shortcut). That's it really. Call the close method on all contexts that you create, and include the post processor ditto. The shutdown hook is a lazy alternative to calling close() (I would not use it unless I had to).

              This is definitely not a Batch discussion.

              Comment


              • #8
                Cheers. Thanks for the info. I agree - it is a last resort to use it, but my service does not know when 'Job end' is and so has to rely on being told (via @PreDestroy).

                Thanks again

                Simon

                Comment


                • #9
                  Dave - apologies. I now see what you are saying! Avoid the 'shutdownhook' mechanism and simply 'close' all the Application Contexts in my hierarchy to get @PreDestroy activated. Doh!, seems so obvious now you say and I read it properly. I am already closing one in my runner (giving me my 'odd' situation) why not close the others!?

                  Code:
                  private void closeContextHierachy(ApplicationContext context) {
                  
                      if (context != null) {
                          if (context instanceof ConfigurableApplicationContext) {
                              ((ConfigurableApplicationContext) context).close();
                          }
                  
                          closeContextHierachy(context.getParent());
                      }
                  
                      return;
                  }
                  Thanks

                  Simon

                  Comment

                  Working...
                  X