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