shiro-ehcache在持續集成無法發佈問題

開啓了shiro-ehcache緩存的話,在使用jenkins做持續集成併發布項目的時候,如果載入了自己的ehcache緩存配置文件的話,可能會報告如下錯誤.

ERROR: Publisher hudson.plugins.deploy.DeployPublisher aborted due to exception
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
如果你回頭看tomca的話,你會發現他下面的那個shiro-ehcache配置文件時無法刪除的.只要tomcat在啓動中就一直被佔用.那會不會是shiro框架並沒有釋放配置文件的文件流呢?

我們重寫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;
        }
    }
}


發佈了23 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章