Spring - 通过RMI传递监听器

时间:2015-07-13 11:32:09

标签: java eclipse spring rmi event-listener

我有几个实现缓存服务的项目 - 每个项目都有自己的,每个项目几乎与其他项目相同。我已经将现有的缓存服务压缩并缩短为包含两个不同缓存服务的单个项目 - 一个用于基本对象,另一个用于复杂对象(扩展基本服务)。我创建了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 {/ 1}}

我做了什么

我已经咨询了JavaDocs,大量搜索并在此处筛选了几个问题,但无济于事。我发现了一些信息,标准属性rmi.codebase设置为true,这可能需要对代码进行一些重写,但是我们已经在项目的其他地方使用了RMI,它确实有效很好。添加SecurityManager会破坏我们应用程序的其余部分(由于外部先决条件)并调用NoSuchObjectException。 到目前为止StackOverflow中的答案已经产生“这是代码库的问题”,“你需要安装一个安全管理器”,“类必须具有相同的名称并且在同一个包中”,当然“它是代码库” 。我两次提到这个,因为它似乎经常出现如何处理代码库问题所带来的。

其他信息

我不确定这是否重要,但这里有更多信息: cacheservice-project使用java代码配置,使用该服务的项目以XML格式配置 监听器接口不会通过Annotations或XML-Beans导出,因为几个帖子(至少包括一个)暗示这将导出类,但只能在服务器端监听,这不是我想要的。 /> 我还试图让CleanupListener成为一个抽象类,它在itselt中扩展UnicastRemoteObject,但这也没有成功 - 实际上,它比我现在的情况更糟糕。
我在eclipse中编写和测试应用程序 组装和发布到服务器是通过命令行中的gradle完成的。

问题

有谁知道这里的问题是什么,以及如何实际解决它?当我所做的一切都是遇到异常或“是的,这是一个代码库错误”时,它变得非常恶化,因为两者都没有帮助。

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:0)

实际答案

好的,这同时令人尴尬和缓解。首先......

好消息

如上所述的Listener-Interface工作。它在服务器端注册,并在被调用时向客户端发出通知,然后客户端可以采取相应的行动。所以,如果你一直在寻找整个“通过听众”问题的答案,那么你就有了它。

坏消息

然而,我对某些事实一无所知。除此之外,术语 codebase 实际涵盖的内容。在我的特定情况下,问题是缓存服务本身没有依赖于其他项目,它应该保留哪些(自定义)类。从技术上讲,代码库实际上问题 - 由于build.gradle缺乏依赖性。

我希望我不会浪费任何人的时间,如果是这样的话,请接受我的道歉,希望这个问题能在某个时候帮助别人。