基础
我有几个项目,它们实现了缓存服务 - 每个项目都有自己的,并且每个项目几乎与其他项目相同。我将现有的缓存服务压缩并缩短为一个包含两种不同缓存服务的项目 - 一种用于基本对象,一种用于复杂对象(扩展了基本服务)。我创建了 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>
进行管理
需要通知的项目使用该接口(interface)的实现:
@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代码配置的,使用该服务的项目是用XML配置的。
监听器接口(interface)不会通过注释或 XML-Bean 导出,因为几篇文章(包括此处至少一篇)暗示这将导出该类,但仅在服务器端继续监听,这不是我想要的。
我也尝试过 CleanupListener
一个抽象类,它本身扩展了 UnicastRemoteObject
但这也没有成功——事实上,它比我现在的情况更糟糕。
我正在 eclipse 中编写和测试该应用程序。
组装并发布到服务器是通过命令行中的 gradle 完成的。
问题
有谁知道这里的问题是什么,以及如何实际解决它?当我所做的一切要么遇到异常,要么“是的,这是一个代码库错误”时,事情就变得非常严重,因为两者都没有任何帮助。
如有任何帮助,我们将不胜感激。
最佳答案
实际答案
好吧,这既令人尴尬又令人宽慰。首先...
好消息
上面描述的监听器接口(interface)是有效的。它在服务器端注册,当被调用时,向客户端发出通知,然后客户端可以采取相应的操作。因此,如果您一直在寻找整个“传递监听器”问题的答案,那么您就找到了。
坏消息
然而,我对某些事实相当无知。除此之外,术语代码库实际涵盖的内容。在我的特定情况下,问题是缓存服务本身不依赖于其他项目,它应该保留哪些(自定义)类。因此从技术上讲,代码库实际上是问题 - 由于 build.gradle
中缺乏依赖项。
我希望我不会在这方面浪费任何人的时间,如果是这样,请接受我的道歉,并希望这个问题有时能对其他人有所帮助。
关于java - Spring - 通过 RMI 传递监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31382243/