001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.cache.ehcache; 018 019import net.sf.ehcache.CacheException; 020import net.sf.ehcache.CacheManager; 021import net.sf.ehcache.config.Configuration; 022import net.sf.ehcache.config.ConfigurationFactory; 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.beans.factory.DisposableBean; 027import org.springframework.beans.factory.FactoryBean; 028import org.springframework.beans.factory.InitializingBean; 029import org.springframework.core.io.Resource; 030 031/** 032 * {@link FactoryBean} that exposes an EhCache {@link net.sf.ehcache.CacheManager} 033 * instance (independent or shared), configured from a specified config location. 034 * 035 * <p>If no config location is specified, a CacheManager will be configured from 036 * "ehcache.xml" in the root of the class path (that is, default EhCache initialization 037 * - as defined in the EhCache docs - will apply). 038 * 039 * <p>Setting up a separate EhCacheManagerFactoryBean is also advisable when using 040 * EhCacheFactoryBean, as it provides a (by default) independent CacheManager instance 041 * and cares for proper shutdown of the CacheManager. EhCacheManagerFactoryBean is 042 * also necessary for loading EhCache configuration from a non-default config location. 043 * 044 * <p>Note: As of Spring 4.1, Spring's EhCache support requires EhCache 2.5 or higher. 045 * 046 * @author Juergen Hoeller 047 * @author Dmitriy Kopylenko 048 * @since 1.1.1 049 * @see #setConfigLocation 050 * @see #setShared 051 * @see EhCacheFactoryBean 052 * @see net.sf.ehcache.CacheManager 053 */ 054public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, InitializingBean, DisposableBean { 055 056 protected final Log logger = LogFactory.getLog(getClass()); 057 058 private Resource configLocation; 059 060 private String cacheManagerName; 061 062 private boolean acceptExisting = false; 063 064 private boolean shared = false; 065 066 private CacheManager cacheManager; 067 068 private boolean locallyManaged = true; 069 070 071 /** 072 * Set the location of the EhCache config file. A typical value is "/WEB-INF/ehcache.xml". 073 * <p>Default is "ehcache.xml" in the root of the class path, or if not found, 074 * "ehcache-failsafe.xml" in the EhCache jar (default EhCache initialization). 075 * @see net.sf.ehcache.CacheManager#create(java.io.InputStream) 076 * @see net.sf.ehcache.CacheManager#CacheManager(java.io.InputStream) 077 */ 078 public void setConfigLocation(Resource configLocation) { 079 this.configLocation = configLocation; 080 } 081 082 /** 083 * Set the name of the EhCache CacheManager (if a specific name is desired). 084 * @see net.sf.ehcache.config.Configuration#setName(String) 085 */ 086 public void setCacheManagerName(String cacheManagerName) { 087 this.cacheManagerName = cacheManagerName; 088 } 089 090 /** 091 * Set whether an existing EhCache CacheManager of the same name will be accepted 092 * for this EhCacheManagerFactoryBean setup. Default is "false". 093 * <p>Typically used in combination with {@link #setCacheManagerName "cacheManagerName"} 094 * but will simply work with the default CacheManager name if none specified. 095 * All references to the same CacheManager name (or the same default) in the 096 * same ClassLoader space will share the specified CacheManager then. 097 * @see #setCacheManagerName 098 * #see #setShared 099 * @see net.sf.ehcache.CacheManager#getCacheManager(String) 100 * @see net.sf.ehcache.CacheManager#CacheManager() 101 */ 102 public void setAcceptExisting(boolean acceptExisting) { 103 this.acceptExisting = acceptExisting; 104 } 105 106 /** 107 * Set whether the EhCache CacheManager should be shared (as a singleton at the 108 * ClassLoader level) or independent (typically local within the application). 109 * Default is "false", creating an independent local instance. 110 * <p><b>NOTE:</b> This feature allows for sharing this EhCacheManagerFactoryBean's 111 * CacheManager with any code calling <code>CacheManager.create()</code> in the same 112 * ClassLoader space, with no need to agree on a specific CacheManager name. 113 * However, it only supports a single EhCacheManagerFactoryBean involved which will 114 * control the lifecycle of the underlying CacheManager (in particular, its shutdown). 115 * <p>This flag overrides {@link #setAcceptExisting "acceptExisting"} if both are set, 116 * since it indicates the 'stronger' mode of sharing. 117 * @see #setCacheManagerName 118 * @see #setAcceptExisting 119 * @see net.sf.ehcache.CacheManager#create() 120 * @see net.sf.ehcache.CacheManager#CacheManager() 121 */ 122 public void setShared(boolean shared) { 123 this.shared = shared; 124 } 125 126 127 @Override 128 public void afterPropertiesSet() throws CacheException { 129 if (logger.isInfoEnabled()) { 130 logger.info("Initializing EhCache CacheManager" + 131 (this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : "")); 132 } 133 134 Configuration configuration = (this.configLocation != null ? 135 EhCacheManagerUtils.parseConfiguration(this.configLocation) : ConfigurationFactory.parseConfiguration()); 136 if (this.cacheManagerName != null) { 137 configuration.setName(this.cacheManagerName); 138 } 139 140 if (this.shared) { 141 // Old-school EhCache singleton sharing... 142 // No way to find out whether we actually created a new CacheManager 143 // or just received an existing singleton reference. 144 this.cacheManager = CacheManager.create(configuration); 145 } 146 else if (this.acceptExisting) { 147 // EhCache 2.5+: Reusing an existing CacheManager of the same name. 148 // Basically the same code as in CacheManager.getInstance(String), 149 // just storing whether we're dealing with an existing instance. 150 synchronized (CacheManager.class) { 151 this.cacheManager = CacheManager.getCacheManager(this.cacheManagerName); 152 if (this.cacheManager == null) { 153 this.cacheManager = new CacheManager(configuration); 154 } 155 else { 156 this.locallyManaged = false; 157 } 158 } 159 } 160 else { 161 // Throwing an exception if a CacheManager of the same name exists already... 162 this.cacheManager = new CacheManager(configuration); 163 } 164 } 165 166 167 @Override 168 public CacheManager getObject() { 169 return this.cacheManager; 170 } 171 172 @Override 173 public Class<? extends CacheManager> getObjectType() { 174 return (this.cacheManager != null ? this.cacheManager.getClass() : CacheManager.class); 175 } 176 177 @Override 178 public boolean isSingleton() { 179 return true; 180 } 181 182 183 @Override 184 public void destroy() { 185 if (this.locallyManaged) { 186 if (logger.isInfoEnabled()) { 187 logger.info("Shutting down EhCache CacheManager" + 188 (this.cacheManagerName != null ? " '" + this.cacheManagerName + "'" : "")); 189 } 190 this.cacheManager.shutdown(); 191 } 192 } 193 194}