我在使用异步 couchdatabase java驱动程序时,遇到了Play framework默认缓存(EHCache)的问题。在热重新加载时播放崩溃,错误如下:
Error in custom provider, play.api.cache.EhCacheExistsException: An EhCache instance with name 'play' already exists.
我发现这可能不仅适用于couchdatabase驱动程序,而且也适用于其他一些场景,比如EUOCrov7M。
发布于 2017-04-05 15:34:50
我想出了一个解决方案-强制停止钩上的高速缓存关闭。它可以在项目中的一个现有模块中完成,例如:
lifecycle.addStopHook(() -> {
...
CacheManager.getInstance().shutdown();
...
});
还可以创建特殊的“修复”模块:
package fixes;
import java.util.concurrent.CompletableFuture;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.google.inject.AbstractModule;
import net.sf.ehcache.CacheManager;
import play.Logger;
import play.Logger.ALogger;
import play.inject.ApplicationLifecycle;
/**
* Fix for the hot reloading cache issue.
* "Error in custom provider, play.api.cache.EhCacheExistsException: An EhCache instance with name 'play' already exists."
*
*/
public class CacheFix extends AbstractModule{
@Override
protected void configure() {
bind(CacheFixInstance.class).asEagerSingleton();
}
}
/**
* Only stop hook
*/
@Singleton
class CacheFixInstance {
private static ALogger logger = Logger.of(CacheFixInstance.class);
@Inject
public CacheFixInstance(ApplicationLifecycle lifecycle) {
lifecycle.addStopHook(() -> {
// Force cache to stop.
CacheManager.getInstance().shutdown();
logger.debug("Cache has been shutdown");
// Nothing to return.
return CompletableFuture.completedFuture(null);
});
}
}
在application.conf
中:
enabled += fixes.CacheFix
发布于 2017-07-27 06:49:51
如果有些人看了一下快速的复制修复,这里是我从Andriy的答案翻译出来的scala版本。
package utils
import javax.inject.{Inject, Singleton}
import com.google.inject.AbstractModule
import net.sf.ehcache.CacheManager
import play.api.Logger
import play.api.inject.ApplicationLifecycle
import scala.concurrent.{ExecutionContext, Future}
/**
* Fix for the hot reloading cache issue.
* "Error in custom provider, play.api.cache.EhCacheExistsException: An EhCache instance with name 'play' already exists."
*
*/
class CacheHotReloadFix extends AbstractModule {
override protected def configure(): Unit = {
bind(classOf[CacheHotReloadFixInstance]).asEagerSingleton()
}
}
@Singleton
class CacheHotReloadFixInstance @Inject() (lifecycle: ApplicationLifecycle, implicit val executionContext: ExecutionContext) {
private val logger = Logger(this.getClass)
lifecycle.addStopHook { () =>
logger.debug("Forching ehcach to stop before play reloads")
// Force cache to stop.
Future(CacheManager.getInstance().shutdown())
}
}
发布于 2018-01-05 12:08:44
如果在运行测试用例时遇到问题(其中将有多个Applicaiton
),则可以使用SyncCacheApi
和AsyncCacheApi
的虚拟实现,并在通过provideApplication()
创建Application
时覆盖绑定。
@Override
protected Application provideApplication() {
Application application = new GuiceApplicationBuilder().configure(testConfig)
.disable(EhCacheModule.class)
.overrides(bind(SyncCacheApi.class).to(FakeSyncCacheApi.class))
.bindings(new MyModule())
.in(new File(".")).build();
return application;
}
而样本FakeSyncCacheApi
应该类似于
@Singleton
public class FakeSyncCacheApi implements SyncCacheApi {
private LRUMap cache = new LRUMap();
@Override
public <T> T get(String key) {
return (T) cache.get(key);
}
@Override
public <T> T getOrElseUpdate(String key, Callable<T> block, int expiration) {
return getOrElseUpdate(key, block);
}
@Override
public <T> T getOrElseUpdate(String key, Callable<T> block) {
T value = (T) cache.get(key);
if (value == null) {
try {
value = block.call();
} catch (Exception e) {
}
cache.put(key, value);
}
return value;
}
@Override
public void set(String key, Object value, int expiration) {
cache.put(key, value);
}
@Override
public void set(String key, Object value) {
cache.put(key, value);
}
@Override
public void remove(String key) {
cache.remove(key);
}
}
这里的想法是禁用EhCache
模块并拥有我们自己的虚拟实现。
https://stackoverflow.com/questions/43243293
复制