开启了shiro-ehcache缓存的话,在使用jenkins做持续集成并发布项目的时候,如果载入了自己的ehcache缓存配置文件的话,可能会报告如下错误.
ERROR: Publisher hudson.plugins.deploy.DeployPublisher aborted due to exception如果你回头看tomca的话,你会发现他下面的那个shiro-ehcache配置文件时无法删除的.只要tomcat在启动中就一直被占用.那会不会是shiro框架并没有释放配置文件的文件流呢?
org.codehaus.cargo.container.ContainerException: Failed to undeploy [C:\Users\盼庚\.jenkins\jobs\一对一\workspace\target\ifservice.war]
at org.codehaus.cargo.container.tomcat.internal.AbstractTomcatManagerDeployer.undeploy(AbstractTomcatManagerDeployer.java:144)
at org.codehaus.cargo.container.tomcat.internal.AbstractTomcatManagerDeployer.redeploy(AbstractTomcatManagerDeployer.java:180)
at hudson.plugins.deploy.CargoContainerAdapter.deploy(CargoContainerAdapter.java:64)
at hudson.plugins.deploy.CargoContainerAdapter$1.invoke(CargoContainerAdapter.java:90)
at hudson.plugins.deploy.CargoContainerAdapter$1.invoke(CargoContainerAdapter.java:77)
at hudson.FilePath.act(FilePath.java:912)
at hudson.FilePath.act(FilePath.java:885)
at hudson.plugins.deploy.CargoContainerAdapter.redeploy(CargoContainerAdapter.java:77)
at hudson.plugins.deploy.DeployPublisher.perform(DeployPublisher.java:47)
at hudson.tasks.BuildStepMonitor$3.perform(BuildStepMonitor.java:45)
at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:781)
at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:753)
at hudson.maven.MavenModuleSetBuild$MavenModuleSetBuildExecution.post2(MavenModuleSetBuild.java:1020)
at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:706)
at hudson.model.Run.execute(Run.java:1690)
at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:509)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:230)
Caused by: org.codehaus.cargo.container.tomcat.internal.TomcatManagerException: FAIL - Unable to delete [D:\Dropbox\Develop\Java\Expansion\tomcat\webapps\ifservice]. The continued presence of this file may cause problems.
at org.codehaus.cargo.container.tomcat.internal.TomcatManager.invoke(TomcatManager.java:507)
at org.codehaus.cargo.container.tomcat.internal.TomcatManager.invoke(TomcatManager.java:443)
at org.codehaus.cargo.container.tomcat.internal.TomcatManager.undeploy(TomcatManager.java:383)
at org.codehaus.cargo.container.tomcat.Tomcat7xRemoteDeployer.performUndeploy(Tomcat7xRemoteDeployer.java:57)
at org.codehaus.cargo.container.tomcat.internal.AbstractTomcatManagerDeployer.undeploy(AbstractTomcatManagerDeployer.java:134)
... 17 more
org.codehaus.cargo.container.tomcat.internal.TomcatManagerException: FAIL - Unable to delete [D:\Dropbox\Develop\Java\Expansion\tomcat\webapps\ifservice]. The continued presence of this file may cause problems.
at org.codehaus.cargo.container.tomcat.internal.TomcatManager.invoke(TomcatManager.java:507)
at org.codehaus.cargo.container.tomcat.internal.TomcatManager.invoke(TomcatManager.java:443)
at org.codehaus.cargo.container.tomcat.internal.TomcatManager.undeploy(TomcatManager.java:383)
at org.codehaus.cargo.container.tomcat.Tomcat7xRemoteDeployer.performUndeploy(Tomcat7xRemoteDeployer.java:57)
at org.codehaus.cargo.container.tomcat.internal.AbstractTomcatManagerDeployer.undeploy(AbstractTomcatManagerDeployer.java:134)
at org.codehaus.cargo.container.tomcat.internal.AbstractTomcatManagerDeployer.redeploy(AbstractTomcatManagerDeployer.java:180)
at hudson.plugins.deploy.CargoContainerAdapter.deploy(CargoContainerAdapter.java:64)
at hudson.plugins.deploy.CargoContainerAdapter$1.invoke(CargoContainerAdapter.java:90)
at hudson.plugins.deploy.CargoContainerAdapter$1.invoke(CargoContainerAdapter.java:77)
at hudson.FilePath.act(FilePath.java:912)
at hudson.FilePath.act(FilePath.java:885)
at hudson.plugins.deploy.CargoContainerAdapter.redeploy(CargoContainerAdapter.java:77)
at hudson.plugins.deploy.DeployPublisher.perform(DeployPublisher.java:47)
at hudson.tasks.BuildStepMonitor$3.perform(BuildStepMonitor.java:45)
at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:781)
at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:753)
at hudson.maven.MavenModuleSetBuild$MavenModuleSetBuildExecution.post2(MavenModuleSetBuild.java:1020)
at hudson.model.AbstractBuild$AbstractBuildExecution.post(AbstractBuild.java:706)
at hudson.model.Run.execute(Run.java:1690)
at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:509)
at hudson.model.ResourceController.execute(ResourceController.java:88)
at hudson.model.Executor.run(Executor.java:230)
Finished: FAILURE
我们重写EhCacheManager类,在其中有个方法叫做 getCacheManagerConfigFileInputStream(),返回值是一个InputStream流,从字面就可以理解其内容是返回配置文件流的.我们这样修改
String configFile = getCacheManagerConfigFile();
InputStream inputStream = null;
try {
inputStream = ResourceUtils.getInputStreamForPath(configFile); //原始的输入流
byte[] b = IOUtils.toByteArray(inputStream);//使用字节数组保存流,实现将流保存到内存中.
InputStream in = new ByteArrayInputStream(b);//从数组重建输入流
return in;
} catch (IOException e) {
throw new ConfigurationException("Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);
} finally {
IOUtils.closeQuietly(inputStream);关闭打开文件的原始输入流.
}
这样再集成发布的时候就不会再报告那个错误了.
完整代码:
import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import org.apache.commons.io.IOUtils;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.apache.shiro.cache.CacheManager;import org.apache.shiro.cache.ehcache.EhCache;import org.apache.shiro.config.ConfigurationException;import org.apache.shiro.io.ResourceUtils;import org.apache.shiro.util.Destroyable;import org.apache.shiro.util.Initializable;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Shiro {@code CacheManager} implementation utilizing the Ehcache framework for * all cache functionality. * <p/> * This class can {@link #setCacheManager(net.sf.ehcache.CacheManager) accept} a * manually configured {@link net.sf.ehcache.CacheManager * net.sf.ehcache.CacheManager} instance, or an {@code ehcache.xml} path * location can be specified instead and one will be constructed. If neither are * specified, Shiro's failsafe * <code><a href="./ehcache.xml">ehcache.xml</a>} file will be used by default. * <p/> * This implementation requires EhCache 1.2 and above. Make sure EhCache 1.1 or earlier * is not in the classpath or it will not work. * <p/> * Please see the <a href="http://ehcache.sf.net" target="_top">Ehcache website</a> for their documentation. * * @see <a href="http://ehcache.sf.net" target="_top">The Ehcache website</a> * @since 0.2 */public class EhCacheManager implements CacheManager, Initializable, Destroyable { /** * This class's private log instance. */ private static final Logger LOG = LoggerFactory.getLogger(EhCacheManager.class); /** * The EhCache cache manager used by this implementation to create caches. */ protected net.sf.ehcache.CacheManager manager; /** * Indicates if the CacheManager instance was implicitly/automatically * created by this instance, indicating that it should be automatically * cleaned up as well on shutdown. */ private boolean cacheManagerImplicitlyCreated = false; /** * Classpath file location of the ehcache CacheManager config file. */ private String cacheManagerConfigFile = "classpath:org/apache/shiro/cache/ehcache/ehcache.xml"; /** * Default no argument constructor */ public EhCacheManager() { } /** * Returns the wrapped Ehcache {@link net.sf.ehcache.CacheManager * CacheManager} instance. * * @return the wrapped Ehcache {@link net.sf.ehcache.CacheManager * CacheManager} instance. */ public net.sf.ehcache.CacheManager getCacheManager() { return manager; } /** * Sets the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} * instance. * * @param manager * the wrapped Ehcache {@link net.sf.ehcache.CacheManager * CacheManager} instance. */ public void setCacheManager(net.sf.ehcache.CacheManager manager) { this.manager = manager; } /** * Returns the resource location of the config file used to initialize a new * EhCache CacheManager instance. The string can be any resource path * supported by the * {@link org.apache.shiro.io.ResourceUtils#getInputStreamForPath(String)} * call. * <p/> * This property is ignored if the CacheManager instance is injected * directly - that is, it is only used to lazily create a CacheManager if * one is not already provided. * * @return the resource location of the config file used to initialize the * wrapped EhCache CacheManager instance. */ public String getCacheManagerConfigFile() { return this.cacheManagerConfigFile; } /** * Sets the resource location of the config file used to initialize the * wrapped EhCache CacheManager instance. The string can be any resource * path supported by the * {@link org.apache.shiro.io.ResourceUtils#getInputStreamForPath(String)} * call. * <p/> * This property is ignored if the CacheManager instance is injected * directly - that is, it is only used to lazily create a CacheManager if * one is not already provided. * * @param classpathLocation * resource location of the config file used to create the * wrapped EhCache CacheManager instance. */ public void setCacheManagerConfigFile(String classpathLocation) { this.cacheManagerConfigFile = classpathLocation; } /** * Acquires the InputStream for the ehcache configuration file using * {@link ResourceUtils#getInputStreamForPath(String) * ResourceUtils.getInputStreamForPath} with the path returned from * {@link #getCacheManagerConfigFile() getCacheManagerConfigFile()}. * * @return the InputStream for the ehcache configuration file. */ protected InputStream getCacheManagerConfigFileInputStream() { String configFile = getCacheManagerConfigFile(); InputStream inputStream = null; try { inputStream = ResourceUtils.getInputStreamForPath(configFile); byte[] b = IOUtils.toByteArray(inputStream); InputStream in = new ByteArrayInputStream(b); return in; } catch (IOException e) { throw new ConfigurationException("Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e); } finally { IOUtils.closeQuietly(inputStream); } } /** * Loads an existing EhCache from the cache manager, or starts a new cache * if one is not found. * * @param name * the name of the cache to load/create. */ public final <K, V> Cache<K, V> getCache(String name) throws CacheException { if (LOG.isTraceEnabled()) { LOG.trace("Acquiring EhCache instance named [" + name + "]"); } try { net.sf.ehcache.Ehcache cache = ensureCacheManager().getEhcache(name); if (cache == null) { if (LOG.isInfoEnabled()) { LOG.info("Cache with name '{}' does not yet exist. Creating now.", name); } this.manager.addCache(name); cache = manager.getCache(name); if (LOG.isInfoEnabled()) { LOG.info("Added EhCache named [" + name + "]"); } } else { if (LOG.isInfoEnabled()) { LOG.info("Using existing EHCache named [" + cache.getName() + "]"); } } return new EhCache<K, V>(cache); } catch (net.sf.ehcache.CacheException e) { throw new CacheException(e); } } /** * Initializes this instance. * <p/> * If a {@link #setCacheManager CacheManager} has been explicitly set (e.g. * via Dependency Injection or programatically) prior to calling this * method, this method does nothing. * <p/> * However, if no {@code CacheManager} has been set, the default Ehcache * singleton will be initialized, where Ehcache will look for an * {@code ehcache.xml} file at the root of the classpath. If one is not * found, Ehcache will use its own failsafe configuration file. * <p/> * Because Shiro cannot use the failsafe defaults (fail-safe expunges cached * objects after 2 minutes, something not desirable for Shiro sessions), * this class manages an internal default configuration for this case. * * @throws org.apache.shiro.cache.CacheException * if there are any CacheExceptions thrown by EhCache. * @see net.sf.ehcache.CacheManager#create */ public final void init() throws CacheException { ensureCacheManager(); } private net.sf.ehcache.CacheManager ensureCacheManager() { try { if (this.manager == null) { if (LOG.isDebugEnabled()) { LOG.debug("cacheManager property not set. Constructing CacheManager instance... "); } // using the CacheManager constructor, the resulting instance is // _not_ a VM singleton // (as would be the case by calling CacheManager.getInstance(). // We do not use the getInstance here // because we need to know if we need to destroy the // CacheManager instance - using the static call, // we don't know which component is responsible for shutting it // down. By using a single EhCacheManager, // it will always know to shut down the instance if it was // responsible for creating it. this.manager = new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()); if (LOG.isTraceEnabled()) { LOG.trace("instantiated Ehcache CacheManager instance."); } cacheManagerImplicitlyCreated = true; if (LOG.isDebugEnabled()) { LOG.debug("implicit cacheManager created successfully."); } } return this.manager; } catch (Exception e) { throw new CacheException(e); } } /** * Shuts-down the wrapped Ehcache CacheManager <b>only if implicitly * created</b>. * <p/> * If another component injected a non-null CacheManager into this instace * before calling {@link #init() init}, this instance expects that same * component to also destroy the CacheManager instance, and it will not * attempt to do so. */ public void destroy() { if (cacheManagerImplicitlyCreated) { try { net.sf.ehcache.CacheManager cacheMgr = getCacheManager(); cacheMgr.shutdown(); } catch (Exception e) { if (LOG.isWarnEnabled()) { LOG.warn("Unable to cleanly shutdown implicitly created CacheManager instance. " + "Ignoring (shutting down)..."); } } cacheManagerImplicitlyCreated = false; } }}