【发布时间】:2015-10-01 15:37:27
【问题描述】:
基础
我有几个项目,它们实现了一个缓存服务——每个都有自己的,每个几乎都和其他的一样。我已将现有的缓存服务压缩并缩短为一个项目,其中包含两种不同的缓存服务——一种用于基本对象,一种用于复杂对象(它扩展了基本服务)。我创建了 2 个项目 - 一个部署为 .war 文件,而 API 项目则用于此部署。
整个应用程序运行在带有最新 JDK 7 的 JBoss AS 7.1 “Thunder”上。
问题
每当删除旧的缓存条目时,特别需要通知一个类。为此,我使用 CleanupListeners 实现了一个通知程序。
CleanupListener.java
public interface CleanupListener extends Remote {
public abstract boolean supports(Class<?> clazz) throws RemoteException;
public abstract void notify(Object removedObject) throws RemoteException;
}
缓存服务中的必要实现
public void registerCleanupListener(CleanupListener listener) {
listeners.add(listener);
}
private void fireCleanupEvent(Object removedObject) {
for (CleanupListener cleanupListener : listeners) {
try {
if (cleanupListener.supports(removedObject.getClass())) {
cleanupListener.notify(removedObject);
}
} catch (RemoteException re) {
LOGGER.error("Remote Listener not available", re);
}
}
}
监听器通过private final HashSet<CleanupListener>进行管理
需要通知的项目使用这个接口的实现:
@Component
public class CleanupEventListener extends UnicastRemoteObject implements CleanupListener {
protected CleanupEventListener() throws RemoteException {
super();
}
@Resource
private ClassRequiresNotification notifyMe;
public boolean supports(Class<?> clazz) {
return SupportedObject.class.isAssignableFrom(clazz);
}
public void notify(Object removedObject) {
notifyMe.someMethod((SupportedObject) removedObject);
}
}
还有一个注册 bean:
@Component
public class CleanupEventListenerRegistrator {
@Resource
private CleanupEventListener cleanupEventListener;
@Resource
private BasicCacheService cacheService;
@PostConstruct
public void init() {
cacheService.registerCleanupListener(cleanupEventListener);
}
}
远程服务通过 SpringBean 导出:
@Bean
public RmiServiceExporter basicCacheServiceExporter(BasicCacheService basicCacheService) {
RmiServiceExporter cacheService = new RmiServiceExporter();
cacheService.setService(basicCacheService);
cacheService.setServiceName(BASIC_CACHE_SERVICE_NAME);
cacheService.setServiceInterface(some.package.BasicCacheService.class);
return cacheService;
}
并通过 XML-Config 注册:
<bean id="basicCacheService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="lookupStubOnStartup" value="false"/>
<property name="serviceUrl" value="basicCacheService" />
<property name="serviceInterface" value="some.package.BasicCacheService" />
<property name="refreshStubOnConnectFailure" value="true"/>
</bean>
异常
所以,每当我尝试调用预期的方法时,我都会遇到两个异常之一:
要么我得到一个NoSuchObjectException(罕见),要么更常见的是一个ClassNotFoundException 包裹在UnmarshalException 中
我做了什么
我已经查阅了 JavaDocs,大量搜索并在这里筛选了几个问题,但无济于事。我发现了一些信息,标准属性rmi.codebase 设置为true,这可能需要重写一些代码,但是我们已经在项目的另一个地方使用 RMI,它在那里工作得很好。添加 SecurityManager 会破坏我们应用程序的其余部分(由于外部先决条件)并调用 NoSuchObjectException。
到目前为止,StackOverflow 中的答案已经产生“这是代码库的问题”、“您需要安装 securityManager”、“类必须具有相同的名称并且在同一个包中”,当然还有“这是代码库” .我提到了两次,因为它确实经常出现,但没有一次提到如何处理代码库问题。
附加信息
我不确定这是否重要,但这里有更多信息:
cacheservice-project用java代码配置,使用服务的project用XML配置。
Listener-Interface 不是通过 Annotations 或 XML-Beans 导出的,因为有几篇文章(这里至少包括一篇文章)暗示这将导出类,但只在服务器端监听,这不是我想要的。
我还尝试将 CleanupListener 设为一个抽象类,它本身扩展了 UnicastRemoteObject ,但也没有成功 - 事实上,它比我现在拥有的更糟糕。
我正在 Eclipse 中编写和测试应用程序。
通过命令行中的 gradle 组装和发布到服务器。
问题
有谁知道这里的问题是什么,以及如何实际解决它?当我所做的一切都遇到异常或“是的,这是一个代码库错误”时,情况变得非常严重,因为两者都没有帮助。
任何帮助将不胜感激。
【问题讨论】:
标签: java eclipse spring rmi event-listener