Documentation Home

Caching Configuration

Configuring cache settings follows the same pattern as other configuration in Broadleaf.

You will want to define a bean in your applicationContext.xml file that specifies additional config locations for Broadleaf to merge. This bean will look similar to this:

<bean id="blMergedCacheConfigLocations" class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list>
            <value>classpath:bl-override-ehcache.xml</value>
        </list>
    </property>
</bean>

Broadleaf will then pick up this definition and merge it with the default configuration, overriding any regions that Broadleaf has defined while creating new ones.

Note: if you have started using Broadleaf with the DemoSite "Heat Clinic" project then this is already configured for you

Caching with Enterprise

With the Broadleaf Enterprise license caches are expired whenever you make edits in the admin panel. This allows you to set caches extremely

Default Cache Configurations

Broadleaf provides a number of ehcache regions out of the box with sensible defaults. These are defined in the following locations:

These default settings were determined empirically using load testing results from our scalability white paper.

Additional Cache Regions with Enterprise

Beyond the above default cache configurations, various modules that are included with the Enterprise license define new regions. These are notated below.

Enterprise:

<!-- 1 day cache -->
<cache
    name="defaultSandboxableCollectionQueryCache"
    maxElementsInMemory="50000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="86400"/>

This is a special cache that acts as the default cache for queries executed as a result of intercepting a collection fetch on an entity class and converting it from many individual select queries to a single select query. This isn't stored in the original cache region as query caches behave differently than entities using the @Cache annotation.

Since a significant number of collections will be cached in this region, it must be sized properly for your application. The best way to determine how large this cache should be is proper profiling and load testing. However, as a rule of thumb you should start with setting it to 5 times the number of products in the catalog. For example, the default setting of 50k assumes a catalog containing 10k products.

The cache region converter, blCollectionQueryCacheRegionConverter, can be customized to provide different enterprise collection query caches other than the default for different original cache regions by merging into the blEnterpriseCollectionCacheRegionConversion bean map. For example:

<bean class="org.broadleafcommerce.common.extensibility.context.merge.LateStageMergeBeanPostProcessor">
    <property name="collectionRef" value="myCollectionCacheRegions" />
    <property name="targetRef" value="blEnterpriseCollectionCacheRegionConversion" />
</bean>

<bean id="myCollectionCacheRegions" class="org.springframework.beans.factory.config.MapFactoryBean">
    <property name="sourceMap">
        <map>
            <entry key="blCategories" value="myCategoriesCache"/>
        </map>
    </property>
</bean>

Theme:

<!-- 1 hour cache -->
<cache
    name="blThemeConfigurationUpdated"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="3600"/>

<!-- 1 hour cache -->
<cache
    name="blThemeFiles"
    maxElementsInMemory="10000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="3600"/>

<cache name="blThemeFileNullCheckCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="3600"/>

Account Credit

<cache
    name="blCreditAccountElements"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="1"
    timeToIdleSeconds="10"/>

i18nEnterprise

<cache
    name="blInternationalMessageElements"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="600"/>

<cache name="blInternationalMessageNullCheckCache"
   maxElementsInMemory="1000"
   eternal="false"
   overflowToDisk="false"
   timeToLiveSeconds="600"/>

Price Lists

<diskStore path="java.io.tmpdir"/>

<!-- 1 hour cache -->
<cache
    name="blPriceListCache"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="3600"/>

Subscription

<!-- 1 hour cache -->
<cache
    name="blSubscriptionCache"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="3600"/>

Manually Expiring Caches in a Running Application

The below methodology exposes the EHCache regions over JMX as MBeans for control. You can then connect to the Java process via a JMX console like VisualVM.

One drawback with this is that you will get duplicate MBean exceptions if you are running the site and admin on the same JVM (deploying to the same Tomcat instance).

  1. Add the following to an applicationContext (either site or admin):

    <bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
        <!-- indicate to first look for a server -->
        <property name="locateExistingServerIfPossible" value="true"/>
    </bean>
    
    <bean id="managementService"
        class="net.sf.ehcache.management.ManagementService"
        init-method="init"
        destroy-method="dispose">
        <constructor-arg ref="blCacheManager"/>
        <constructor-arg ref="mbeanServer"/>
        <constructor-arg index="2" value="true"/>
        <constructor-arg index="3" value="true"/>
        <constructor-arg index="4" value="true"/>
        <constructor-arg index="5" value="true"/>
    </bean>
    

    or in Java Config:

    @Bean
    public MBeanServerFactoryBean mbeanServer() {
        MBeanServerFactoryBean mBeanServerFactoryBean = new MBeanServerFactoryBean();
        mBeanServerFactoryBean.setLocateExistingServerIfPossible(true);
        return mBeanServerFactoryBean;
    }

    @Bean(initMethod = "init", destroyMethod = "dispose")
    public ManagementService managementService(@Qualifier("blCacheManager") CacheManager cacheManager, @Qualifier("mbeanServer") MBeanServerFactoryBean mbeanServer) {
        ManagementService managementService = new ManagementService(cacheManager, mbeanServer.getObject(), true, true, true, true);
        return managementService;
    }
  1. Start up the server, and connect to it via a JMX listener like VisualVM. If you are running locally, VisualVM will display all local Java processes on the lefthand side that you can easily attach to. In this screenshot, I have attached to my locally running Broadleaf instance that I started via Ant/Maven on the command line:

    visualvm-local

    If you go over to the MBeans tab, you will see the exports from the server. We are interested in the net.sf.ehcache folder and the Cache -> DEFAULT MBean:

    visual-vm-ehcache

    If you click on a specific MBean you can hit the removeAll button to clear the cache:

    visual-vm-cmscache

Simple Remote JMX Connections

Add the following arguments to your JVM (if you are using Tomcat, this is CATALINA_OPTS):

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=4446 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 

This opens port 4446 for remote connection

Remote JMX Connections Securely behind a Firewall

The above configuration assigns a random external port for RMI which makes it impossible to securely connect to the running application and only whitelist a specific port. The below instructions assume Tomcat, but there are likely equivalents on other application servers.

  1. In server.xml, add this line anywhere in the <Server> tag, replacing the placeholder ports. The rmiRegistryPortPlatfor is the JMX remote port to connect to while the rmiServerPortPlatform is internally used by Tomcat.

    <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener" rmiRegistryPortPlatform="30000" rmiServerPortPlatform="30001"/>
    
  2. Create a jmxremote.access if one does not already exist

    controlRole   readwrite \
                  create javax.management.monitor.*,javax.management.timer.* \
                  unregister
    
  3. Create a jmxremote.access if one does not already exist with a chmod of 0600

    controlRole  somepassword
    
  4. Change the system properties above to authenticate and specify the password and access file.

    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=true
    -Dcom.sun.management.jmxremote.password.file=/etc/java-7-openjdk/management/jmxremote.password
    -Dcom.sun.management.jmxremote.access.file=/etc/java-7-openjdk/management/jmxremote.access
    -Djava.rmi.server.hostname=1.2.3.4
    

    Note: you could also use com.sun.management.jmxremote.ssl=true and use the domain name for the hostname if you have a valid SSL certificate

  5. In VisualVM right click on "Remote" and hit "Add Remote Host..."

    remote host

  6. Select the host that you just added and go to "Add JMX Connection"

    add JMX remote

Disabling the Cache

You can also add configuration to completely disable all caching in Broadleaf. If you started from the DemoSite Heat Clinic starter project you should have a bl-override-ehcache.xml file in the site project (in the admin, this is bl-override-ehcache-admin.xml). If not, the below changes should be in the file that you configured at the top of this document.

This sets all of the caches in Broadleaf to expire after 10 seconds. This might be useful in a development environment but should not be checked into version control.

<cache
    name="blTranslationElements"
    maxElementsInMemory="10000000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache
    name="blConfigurationModuleElements"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>      

<cache
    name="blSystemPropertyElements"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache name="blSystemPropertyNullCheckCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="blBundleElements"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<diskStore path="java.io.tmpdir"/>

<defaultCache
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"
    timeToIdleSeconds="30"/>

<cache
    name="blStandardElements"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10">
    <cacheEventListenerFactory class="org.broadleafcommerce.common.cache.engine.HydratedCacheEventListenerFactory"/>
</cache>

<cache
    name="blProducts"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10">
    <cacheEventListenerFactory class="org.broadleafcommerce.common.cache.engine.HydratedCacheEventListenerFactory"/>
</cache>

<cache name="blProductUrlCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="blCategories"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10">
    <cacheEventListenerFactory class="org.broadleafcommerce.common.cache.engine.HydratedCacheEventListenerFactory"/>
</cache>

<cache name="blCategoryUrlCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="blOffers"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10">
    <cacheEventListenerFactory class="org.broadleafcommerce.common.cache.engine.HydratedCacheEventListenerFactory"/>
</cache>

<cache
    name="blInventoryElements"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache
    name="org.hibernate.cache.internal.StandardQueryCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="query.Catalog"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="query.Cms"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="query.Offer"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="blOrderElements"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

 <cache
    name="blCustomerElements"
    maxElementsInMemory="100000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache
    name="query.Order"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

 <cache
    name="generatedResourceCache"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

 <!-- This is required by Hibernate to ensure that query caches return 
      corrrect results. It must contain at least as many entries as there are 
      DB tables. -->
 <cache name="org.hibernate.cache.spi.UpdateTimestampsCache" 
    maxElementsInMemory="5000" 
    eternal="true" 
    overflowToDisk="true"/>

<cache name="blTemplateElements"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache
    name="blCMSElements"
    maxElementsInMemory="10000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache name="cmsPageCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache name="cmsStructuredContentCache"
    maxElementsInMemory="5000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<!--  URLHandlerCache -->
<cache name="cmsUrlHandlerCache"
    maxElementsInMemory="5000"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>


<cache
    name="blThemeConfigurationUpdated"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

    <!-- 1 hour cache -->
<cache
    name="blThemeFiles"
    maxElementsInMemory="10000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache name="blThemeFileNullCheckCache"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache
    name="blCreditAccountElements"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"
    timeToIdleSeconds="10"/>

<cache
    name="blInternationalMessageElements"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="false"
    timeToLiveSeconds="10"/>

<cache name="blInternationalMessageNullCheckCache"
   maxElementsInMemory="1000"
   eternal="false"
   overflowToDisk="false"
   timeToLiveSeconds="10"/>

<cache
    name="blPriceListCache"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

<cache
    name="blSubscriptionCache"
    maxElementsInMemory="100"
    eternal="false"
    overflowToDisk="true"
    timeToLiveSeconds="10"/>

Other cache settings

Broadleaf also uses various other caching configured by system properties. Add this to your environment-specific properties files to change the behavior.

cache.page.templates
cache.page.templates.ttl