1

I have a spring boot application. I have implemented caching using the ehcahce in my spring boot application. The caching is working fine, but the tomcat is not shutting down when the shutdown script is triggered. I have skipped the default container in my build and I have tested using jstack and could find the ehcache is preventing the application to shutdown. I need to implement the shutdown for ehcache when the spring boot shut down. I know I need to implement a shutdown listener for ehcahce. I have tried setting the property in application.properties.

net.sf.ehcache.enableShutdownHook=true

But it did not work out. This should be the last option to try out ideally. I need to try adding a listener in web.xml

    <listener> 
    <listener-class> 
       net.sf.ehcache.constructs.web.ShutdownListener</listener-class> 
   </listener>

But as spring boot does not have a web.xml how can implement this listener? Can i do it in webconfig? Any one implemented this please help.

I have looked into some of the older posts Tomcat not shutting down when Spring boot app is deployed with ehcache but does not look like having any proper response.

Adding configuration.(As per comment below) This is my main class, I have configured @EnableCaching

@SpringBootApplication
@EnableAsync
@EnableCaching
public class Application extends SpringBootServletInitializer implements AsyncConfigurer 

{

My ehcache.xml in root class path name ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="java.io.tmpdir" />
    <defaultCache maxElementsInMemory="10" eternal="false"
        timeToIdleSeconds="1200" timeToLiveSeconds="600" overflowToDisk="true" />
    <cache name="cache1" maxElementsInMemory="60000" eternal="false"
        overflowToDisk="false" timeToIdleSeconds="0" timeToLiveSeconds="43200"  memoryStoreEvictionPolicy="LFU"/>
    <cache name="cache2" maxElementsInMemory="500" eternal="false"
        overflowToDisk="false" timeToIdleSeconds="0" timeToLiveSeconds="43200"  memoryStoreEvictionPolicy="LFU"/>
</ehcache>

I have configured to load it on start up.

public class ApplicationStartupService implements
        ApplicationListener<ApplicationReadyEvent> {


@Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
    //load cache
}

Method annotated with caching.

@Cacheable(value = CACHE_1, key = "#root.target.KEY")
    public Map<String, String> cache1() {

}

in pom.xml I have configured the cache start up.

<packaging>war</packaging>
<name>myapp</name>
<description>my test application</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.7.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <jcl.slf4j.version>1.7.12</jcl.slf4j.version>
    <logback.version>1.1.3</logback.version>
    <rootDir>${project.basedir}</rootDir>
</properties>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

As per comment I have tried adding bean and it did not help.

@Bean
    public CacheManager cacheManager() {
        net.sf.ehcache.CacheManager cacheManager = new net.sf.ehcache.CacheManager();
        return new EhCacheCacheManager(cacheManager);
    }
Community
  • 1
  • 1
Adam
  • 11
  • 1
  • 4
  • 1
    How are you using EhCache? If you are using the Spring provider classes to bootstrap EhCache shutdown is already going to be taken care of. – M. Deinum Oct 24 '16 at 06:09
  • I am using spring boot and spring boot will automatically create the cache manger if ehcache.xml is in class path. https://spring.io/blog/2015/06/15/cache-auto-configuration-in-spring-boot-1-3 – Adam Oct 24 '16 at 11:53
  • Which then will also shutdown the cache... This is handled by the appropriate factory that creates ehcache. – M. Deinum Oct 24 '16 at 11:58
  • I was expecting that but unfortunately it is not happening like that. I am not getting any error,but my tomcat is not stopping, when I check it is because of ehcache only. – Adam Oct 24 '16 at 12:45
  • That, afaik, shouldn't happen. What is blocking ? Can you add your configuration and possible pom. Also which EhCache version are you using. – M. Deinum Oct 24 '16 at 13:38
  • updated the configuration, i have not included any dependency for eh cache, it is taking the default dependency. – Adam Oct 24 '16 at 14:06
  • Can you elaborate on how the cache is getting filled/loaded within your `ApplicationStartupService`? Could you also post the error on the tomcat side, (at least I suspect it it telling you something about hanging threads or something like that). – M. Deinum Oct 25 '16 at 05:49
  • Well actually I was under the impression that Spring Boot would be using the `EhCacheManagerFactoryBean` to construct the `EhCacheManager` which on shutdown will also shutdown the cache manager from EhCache. However this doesn't seem to be the case, which will leak the starter threads from EhCache. You could work around it by configuring the `EhCacheManagerFactoryBean` instead of relying on auto-configuration. Or add an application listener, for the time being, to destroy the cache manager on shutdown. See also https://jira.spring.io/browse/SPR-11680?jql=text%20~%20%22CacheManager%22 – M. Deinum Oct 25 '16 at 05:58
  • As mentioned in [SPR-11680](https://jira.spring.io/browse/SPR-11680?jql=text%20~%20%22CacheManager%22) Spring Boot does however expose the plain ehcache `CacheManager` so its shutdown method should be called. – M. Deinum Oct 25 '16 at 06:02
  • The spring cache manager do not have shutdown method. I have tried adding this but it did not help. @Bean public CacheManager cacheManager() { net.sf.ehcache.CacheManager cacheManager = new net.sf.ehcache.CacheManager(); return new EhCacheCacheManager(cacheManager); } – Adam Oct 25 '16 at 10:17
  • That is the same as Spring Boot does so it wil not help. You actually make it worse as you are not exposing the EhCache `CacheManager` which has a `shutdown` method but only the spring `CacheManager` which suffers from the issue as mentioned in the issue. – M. Deinum Oct 25 '16 at 12:05
  • public CacheManager cacheManager() { net.sf.ehcache.CacheManager cacheManager = new net.sf.ehcache.CacheManager(); return new EhCacheCacheManager(cacheManager); I am exposing the net.sf.ehcache.CacheManager() which has the shutdown method. Also I have tried answer below. – Adam Oct 25 '16 at 12:34
  • You are exporting the `EhCacheCacheManager` which is a spring class implementing also `CacheManager` from Spring not the ehcache one. So no you aren't exposing the `net.sf.ehcache.CacheManager` as a plain bean. Which is what Spring Boot does and that still apparently doesn't work. Are you really sure that the EhCache from Spring Boot is the culprit? And not something else? – M. Deinum Oct 25 '16 at 12:38
  • I removed the caching on start up and tried to stop the tomcat and it stopped with out any issues. Not sure whether it is conflicting with anything else. – Adam Oct 25 '16 at 13:13

1 Answers1

0

How about create a spring context listener. Trap the context destroy even and shutdown the ehcache.

public class SpringEhcacheShutdownListenerBean implements ApplicationListener {

@Override
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ContextClosedEvent) {
        // now you can do ehcache shutdown
        // ...
    }
}

}

Don't forget to register the class as a spring bean.

Henry
  • 136
  • 3