/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cache.ehcache;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.Configuration;
import net.sf.ehcache.config.ConfigurationFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;

FactoryBean that exposes an EhCache CacheManager instance (independent or shared), configured from a specified config location.

If no config location is specified, a CacheManager will be configured from "ehcache.xml" in the root of the class path (that is, default EhCache initialization - as defined in the EhCache docs - will apply).

Setting up a separate EhCacheManagerFactoryBean is also advisable when using EhCacheFactoryBean, as it provides a (by default) independent CacheManager instance and cares for proper shutdown of the CacheManager. EhCacheManagerFactoryBean is also necessary for loading EhCache configuration from a non-default config location.

Note: As of Spring 5.0, Spring's EhCache support requires EhCache 2.10 or higher.

Author:Juergen Hoeller, Dmitriy Kopylenko
See Also:
Since:1.1.1
/** * {@link FactoryBean} that exposes an EhCache {@link net.sf.ehcache.CacheManager} * instance (independent or shared), configured from a specified config location. * * <p>If no config location is specified, a CacheManager will be configured from * "ehcache.xml" in the root of the class path (that is, default EhCache initialization * - as defined in the EhCache docs - will apply). * * <p>Setting up a separate EhCacheManagerFactoryBean is also advisable when using * EhCacheFactoryBean, as it provides a (by default) independent CacheManager instance * and cares for proper shutdown of the CacheManager. EhCacheManagerFactoryBean is * also necessary for loading EhCache configuration from a non-default config location. * * <p>Note: As of Spring 5.0, Spring's EhCache support requires EhCache 2.10 or higher. * * @author Juergen Hoeller * @author Dmitriy Kopylenko * @since 1.1.1 * @see #setConfigLocation * @see #setShared * @see EhCacheFactoryBean * @see net.sf.ehcache.CacheManager */
public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, InitializingBean, DisposableBean { protected final Log logger = LogFactory.getLog(getClass()); @Nullable private Resource configLocation; @Nullable private String cacheManagerName; private boolean acceptExisting = false; private boolean shared = false; @Nullable private CacheManager cacheManager; private boolean locallyManaged = true;
Set the location of the EhCache config file. A typical value is "/WEB-INF/ehcache.xml".

Default is "ehcache.xml" in the root of the class path, or if not found, "ehcache-failsafe.xml" in the EhCache jar (default EhCache initialization).

See Also:
/** * Set the location of the EhCache config file. A typical value is "/WEB-INF/ehcache.xml". * <p>Default is "ehcache.xml" in the root of the class path, or if not found, * "ehcache-failsafe.xml" in the EhCache jar (default EhCache initialization). * @see net.sf.ehcache.CacheManager#create(java.io.InputStream) * @see net.sf.ehcache.CacheManager#CacheManager(java.io.InputStream) */
public void setConfigLocation(Resource configLocation) { this.configLocation = configLocation; }
Set the name of the EhCache CacheManager (if a specific name is desired).
See Also:
  • setName.setName(String)
/** * Set the name of the EhCache CacheManager (if a specific name is desired). * @see net.sf.ehcache.config.Configuration#setName(String) */
public void setCacheManagerName(String cacheManagerName) { this.cacheManagerName = cacheManagerName; }
Set whether an existing EhCache CacheManager of the same name will be accepted for this EhCacheManagerFactoryBean setup. Default is "false".

Typically used in combination with "cacheManagerName" but will simply work with the default CacheManager name if none specified. All references to the same CacheManager name (or the same default) in the same ClassLoader space will share the specified CacheManager then.

See Also:
/** * Set whether an existing EhCache CacheManager of the same name will be accepted * for this EhCacheManagerFactoryBean setup. Default is "false". * <p>Typically used in combination with {@link #setCacheManagerName "cacheManagerName"} * but will simply work with the default CacheManager name if none specified. * All references to the same CacheManager name (or the same default) in the * same ClassLoader space will share the specified CacheManager then. * @see #setCacheManagerName * #see #setShared * @see net.sf.ehcache.CacheManager#getCacheManager(String) * @see net.sf.ehcache.CacheManager#CacheManager() */
public void setAcceptExisting(boolean acceptExisting) { this.acceptExisting = acceptExisting; }
Set whether the EhCache CacheManager should be shared (as a singleton at the ClassLoader level) or independent (typically local within the application). Default is "false", creating an independent local instance.

NOTE: This feature allows for sharing this EhCacheManagerFactoryBean's CacheManager with any code calling CacheManager.create() in the same ClassLoader space, with no need to agree on a specific CacheManager name. However, it only supports a single EhCacheManagerFactoryBean involved which will control the lifecycle of the underlying CacheManager (in particular, its shutdown).

This flag overrides "acceptExisting" if both are set, since it indicates the 'stronger' mode of sharing.

See Also:
/** * Set whether the EhCache CacheManager should be shared (as a singleton at the * ClassLoader level) or independent (typically local within the application). * Default is "false", creating an independent local instance. * <p><b>NOTE:</b> This feature allows for sharing this EhCacheManagerFactoryBean's * CacheManager with any code calling <code>CacheManager.create()</code> in the same * ClassLoader space, with no need to agree on a specific CacheManager name. * However, it only supports a single EhCacheManagerFactoryBean involved which will * control the lifecycle of the underlying CacheManager (in particular, its shutdown). * <p>This flag overrides {@link #setAcceptExisting "acceptExisting"} if both are set, * since it indicates the 'stronger' mode of sharing. * @see #setCacheManagerName * @see #setAcceptExisting * @see net.sf.ehcache.CacheManager#create() * @see net.sf.ehcache.CacheManager#CacheManager() */
public void setShared(boolean shared) { this.shared = shared; } @Override public void afterPropertiesSet() throws CacheException { if (logger.isInfoEnabled()) { logger.info("Initializing EhCache CacheManager" + (this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : "")); } Configuration configuration = (this.configLocation != null ? EhCacheManagerUtils.parseConfiguration(this.configLocation) : ConfigurationFactory.parseConfiguration()); if (this.cacheManagerName != null) { configuration.setName(this.cacheManagerName); } if (this.shared) { // Old-school EhCache singleton sharing... // No way to find out whether we actually created a new CacheManager // or just received an existing singleton reference. this.cacheManager = CacheManager.create(configuration); } else if (this.acceptExisting) { // EhCache 2.5+: Reusing an existing CacheManager of the same name. // Basically the same code as in CacheManager.getInstance(String), // just storing whether we're dealing with an existing instance. synchronized (CacheManager.class) { this.cacheManager = CacheManager.getCacheManager(this.cacheManagerName); if (this.cacheManager == null) { this.cacheManager = new CacheManager(configuration); } else { this.locallyManaged = false; } } } else { // Throwing an exception if a CacheManager of the same name exists already... this.cacheManager = new CacheManager(configuration); } } @Override @Nullable public CacheManager getObject() { return this.cacheManager; } @Override public Class<? extends CacheManager> getObjectType() { return (this.cacheManager != null ? this.cacheManager.getClass() : CacheManager.class); } @Override public boolean isSingleton() { return true; } @Override public void destroy() { if (this.cacheManager != null && this.locallyManaged) { if (logger.isInfoEnabled()) { logger.info("Shutting down EhCache CacheManager" + (this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : "")); } this.cacheManager.shutdown(); } } }