12

I'm porting 5 years old Spring MVC application with JSPs to Spring Boot. Therefore, according to sample in http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-jsp-limitations I'm using "war" packaging.

Embedded tomcat starts. However logs are full of caching warnings like in the example below

2016-08-25 14:59:01.442  INFO 28884 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-08-25 14:59:01.456  INFO 28884 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2016-08-25 14:59:01.458  INFO 28884 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.4
2016-08-25 14:59:01.531  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/displaytag-1.2.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:01.531  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/decrex-maven-0.1.10-SNAPSHOT.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:01.531  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/spring-boot-actuator-1.4.0.RELEASE.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:01.531  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/validation-api-1.1.0.Final.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:01.532  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/lucene-backward-codecs-5.3.1.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:01.532  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/lucene-queries-5.3.1.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
.....
2016-08-25 14:59:05.121  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/lib/jstl-1.2.jar] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:05.139  WARN 28884 --- [ost-startStop-1] org.apache.catalina.webresources.Cache   : Unable to add the resource at [/WEB-INF/classes/commons-logging.properties] to the cache because there was insufficient free space available after evicting expired cache entries - consider increasing the maximum size of the cache
2016-08-25 14:59:05.139  INFO 28884 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2016-08-25 14:59:05.139  INFO 28884 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 7117 ms
.....
2016-08-25 15:02:03.960  INFO 28884 --- [ndardContext[]]] org.apache.catalina.webresources.Cache   : The background cache eviction process was unable to free [10] percent of the cache for Context [] - consider increasing the maximum size of the cache. After eviction approximately [9,251] KB of data remained in the cache.

I'd be happy to increase tomcat cache, but I'm failing to find a way to control it in Spring Boot. Please, advise!!!


I tried a suggestion from Andy Wilkinson below. Also tried to use it in EmbeddedServletContainerCustomizer
@Component
public class ServletContainerCustomizer implements EmbeddedServletContainerCustomizer {

    private static final Log log = LogFactory.getLog(ServletContainerCustomizer.class);

    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
        if (TomcatEmbeddedServletContainerFactory.class.isAssignableFrom(container.getClass())) {

            int cacheSize = 256 * 1024;
            log.info("Customizing tomcat factory. New cache size (KB) is " + cacheSize);

            TomcatEmbeddedServletContainerFactory tomcatFactory = (TomcatEmbeddedServletContainerFactory) container;
            tomcatFactory.addContextCustomizers((context) -> {
                StandardRoot standardRoot = new StandardRoot(context);
                standardRoot.setCacheMaxSize(cacheSize);
            });

        }
    }

}

Message about changing the cache size is in the logs, but the code above has no influence on the warnings

Viktor
  • 345
  • 1
  • 3
  • 13
  • There is a some info about this error: http://stackoverflow.com/questions/26893297/tomcat-8-throwing-org-apache-catalina-webresources-cache-getresource-unable-to As far I understand to increase the cache size you have to define [`EmbeddedServletContainerCustomizer`](http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/embedded/EmbeddedServletContainerCustomizer.html) – Slava Semushin Aug 25 '16 at 13:54
  • Thank you for the idea. I can get access to an instance of [TomcatEmbeddedServletContainerFactory](http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.html). However there are no methods, which can help to control caching – Viktor Aug 25 '16 at 14:17

4 Answers4

13

I've been having the same problem for a while, but Andy Wilkinson's hint set me on the right track. What worked for me was to set the cache as Andy did, but then also explicitly set the resources in context.

@Bean
public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory() {
        @Override
        protected void postProcessContext(Context context) {
            final int cacheSize = 40 * 1024;
            StandardRoot standardRoot = new StandardRoot(context);
            standardRoot.setCacheMaxSize(cacheSize);
            context.setResources(standardRoot); // This is what made it work in my case.

            logger.info(String.format("New cache size (KB): %d", context.getResources().getCacheMaxSize()));
        }
    };
    return tomcatFactory;
}

Hope this helps!

Alexander H
  • 198
  • 1
  • 8
4

You can configure the cache size using a context customizer to configure the context with a customized StandardRoot:

Java 7:

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
    tomcatFactory.addContextCustomizers(new TomcatContextCustomizer() {

        @Override
        public void customize(Context context) {
            StandardRoot standardRoot = new StandardRoot(context);
            standardRoot.setCacheMaxSize(40 * 1024);
        }

    });
    return tomcatFactory;
}

Java 8:

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
    tomcatFactory.addContextCustomizers((context) -> {
        StandardRoot standardRoot = new StandardRoot(context);
        standardRoot.setCacheMaxSize(40 * 1024);
    });
    return tomcatFactory;
}
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • Thanks a lot! I tried your suggestion (with 1024*1024) both ways: creating the factory and customizing it in EmbeddedServletContainerCustomizer later (code is added to my question). However neither had any influence on the results - the warnings are still there – Viktor Aug 26 '16 at 08:50
  • `standardRoot.setCachingAllowed(false);` does not disable cache either. Seems `StandardRoot` does not influence anything – Viktor Aug 26 '16 at 08:56
  • It sounds like your customizer isn't being used. Are you sure it's in a package that's covered by component scanning? – Andy Wilkinson Aug 26 '16 at 13:10
  • Yes. To insure this I added `log.info("...")` statement to the customizer and I see this statement in the logs – Viktor Aug 26 '16 at 13:39
  • Well, it works for me. Without a _complete_ example that shows it not working I'm stumped. – Andy Wilkinson Aug 26 '16 at 14:29
2

Referring to the answer here, I created src/main/webapp/META-INF/context.xml and added the following.

<?xml version="1.0" encoding="UTF-8"?>
<Context>
  <Resources cachingAllowed="true" cacheMaxSize="204800" />
</Context>
Joseph Hui
  • 573
  • 6
  • 11
0

Andy's solution got me most of the way with the same issue, but did not take effect until I added context.setResources(standardRoot);

Here is my entire working configuration:

@Configuration
public class TomcatConfiguration {

private final Logger log = LoggerFactory.getLogger(TomcatConfiguration.class);

@Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
    log.info("Configuring TomcatEmbeddedServletContainerFactory");
    TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
    tomcatFactory.addContextCustomizers((context) -> {
        StandardRoot standardRoot = new StandardRoot(context);
        standardRoot.setCacheMaxSize(40 * 1024);
        context.setResources(standardRoot);
    });
    return tomcatFactory;
}
}

It may be worth noting that the default cache size is 10240 (10 megabytes)

Procrastinator
  • 2,526
  • 30
  • 27
  • 36
Ben P
  • 1
  • 1