如何实例化ehcache.CacheEventListener?解决clone方法隐藏冲突问题
这个问题我之前在使用Ehcache 2.x版本时也碰到过,本质是Java接口方法访问权限的冲突导致的编译错误,我来给你拆解一下解决思路和可行方案:
错误原因解析
Ehcache 2.x的CacheEventListener接口中定义了public abstract Object clone() throws CloneNotSupportedException方法,而Java原生Object类的clone()方法是protected权限的。根据Java的方法重写规则:子类实现接口方法时,访问权限不能比接口中定义的更严格。如果你没有显式实现这个public的clone()方法,编译器就会报错,提示你“无法隐藏父接口中的public抽象方法”。
直接解决办法:显式实现public的clone()方法
你只需要在自定义的监听器类中,显式重写clone()方法并将其设为public即可。根据你的监听器是否需要支持克隆,有两种实现方式:
1. 监听器无需克隆(常见场景)
如果你的监听器是无状态的单例,或者不需要被克隆,直接抛出CloneNotSupportedException即可:
import net.sf.ehcache.CacheException; import net.sf.ehcache.Element; import net.sf.ehcache.event.CacheEventListener; public class ConnectionClosingCacheListener implements CacheEventListener { // 处理元素驱逐/超时的核心逻辑 private void closeConnection(Element element) { // 从缓存元素中获取需要关闭的连接对象 Object connection = element.getObjectValue(); if (connection instanceof AutoCloseable) { try { ((AutoCloseable) connection).close(); } catch (Exception e) { // 根据业务需求处理关闭异常,比如日志记录 e.printStackTrace(); } } } // 重写需要关注的事件方法 @Override public void notifyElementEvicted(String cacheName, Element element) { closeConnection(element); } @Override public void notifyElementExpired(String cacheName, Element element) { closeConnection(element); } @Override public void notifyElementRemoved(String cacheName, Element element) throws CacheException { closeConnection(element); } // 实现其他不需要自定义逻辑的接口方法 @Override public void notifyElementPut(String cacheName, Element element) throws CacheException {} @Override public void notifyElementUpdated(String cacheName, Element element) throws CacheException {} @Override public void notifyRemoveAll(String cacheName) {} @Override public void dispose() {} // 关键:显式实现public的clone方法 @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException("This listener does not support cloning"); } }
2. 监听器需要支持克隆
如果你的监听器有状态,需要支持克隆,就实现对应的克隆逻辑:
@Override public Object clone() throws CloneNotSupportedException { // 创建新的监听器实例,复制必要的状态 ConnectionClosingCacheListener clone = new ConnectionClosingCacheListener(); // 复制你的监听器中的状态字段(如果有) // clone.someField = this.someField; return clone; }
更简洁的替代方案:继承CacheEventListenerAdapter
如果你觉得实现所有接口方法太繁琐,可以直接继承Ehcache提供的CacheEventListenerAdapter抽象类。这个类已经默认实现了CacheEventListener的所有方法(包括clone()方法,默认抛出CloneNotSupportedException),你只需要重写你关心的事件方法即可:
import net.sf.ehcache.Element; import net.sf.ehcache.event.CacheEventListenerAdapter; public class ConnectionClosingListenerAdapter extends CacheEventListenerAdapter { @Override public void notifyElementEvicted(String cacheName, Element element) { closeConnection(element); } @Override public void notifyElementExpired(String cacheName, Element element) { closeConnection(element); } @Override public void notifyElementRemoved(String cacheName, Element element) throws CacheException { closeConnection(element); } private void closeConnection(Element element) { // 同样的连接关闭逻辑 Object connection = element.getObjectValue(); if (connection instanceof AutoCloseable) { try { ((AutoCloseable) connection).close(); } catch (Exception e) { e.printStackTrace(); } } } }
配置监听器到缓存
最后,记得在你的ehcache.xml中配置这个监听器:
<cache name="yourTargetCache" maxEntriesLocalHeap="1000" timeToLiveSeconds="300"> <cacheEventListenerFactory class="net.sf.ehcache.event.RegisteredEventListeners$CacheEventListenerFactory" properties="listenerClass=com.yourpackage.ConnectionClosingCacheListener"/> </cache>
内容的提问来源于stack exchange,提问作者markthegrea

