java - 同一 OSGI 包中的多个类加载器导致类转换异常

标签 java osgi aem apache-felix

有时,在我们部署应用程序并卸载和安装 bundle 后,我们会遇到类转换异常,其中类 A 无法转换为类 A。问题是实例的类加载器已经在一段时间的内存不同于类本身的类加载器。部署不会影响存储实例的包(在此示例中为包 Y)。

伪代码如下:

捆绑X

public class A extends B {
/* ... */
}

...

/* ... */

@Reference
private InMemoryUserTokenStore inMemoryUserTokenStore;

/* ... */

protected UsersTokenStore getTokenStore() {
    return inMemoryUserTokenStore; // <- reference to service from another bundle where tokens are stored
}

/* The token is created and obtained in the same bundle */

A token = new A(...);
getTokenStore().addToken(token)

/* ... */

B token = getTokenStore().getToken(id)
((A) token).doSomething(); // <- this is when class cast exception is thrown*/

使用调试器我发现这里token的类名是A,两者的类加载器返回相同的bundle名称和id(bundle X,相同的 ID)但是它们不相等。

捆绑Y

public class InMemoryUserTokenStore implements UsersTokenStore {
/* ... */
    private ConcurrentMap<String, B> tokens = new ConcurrentHashMap();
    /* ... */
    public B getToken(String id) {
        /* ... */
        return tokens.get(id); // <- instance returned here sometimes has different class loader than class A from bundle **X**
    }
/* ... */
}

我不确定这是 OSGI 的问题还是我们这边的一些设计错误?

最佳答案

如果所讨论的两个类实例具有不同的类加载器,则抛出 ClassCastException。

当更新或卸载 bundle 并导出包时,这些包不会被删除,并且针对旧的已卸载 bundle 解析的 bundle 仍将使用旧的/过时的代码,直到包被刷新。这是 OSGi 规范定义的正确行为。

Sling(AEM 的底层框架)的 bundle installer 实现在安装、更新或删除后调用刷新,因此根本不应该出现此问题。您应该调查为什么在某些情况下刷新失败 - 一个起点是为以下类启用跟踪日志记录并查看发生了什么 -

org/apache/sling/installer/core/impl/tasks/BundleUpdateTask
org/apache/sling/installer/core/impl/tasks/RefreshBundlesTask

关于java - 同一 OSGI 包中的多个类加载器导致类转换异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52272319/

相关文章:

java - 寻找 OSGi 设计模式

html - 在 AEM 的文本 RTE 组件中调整 html 卡片元素的边距

java - 如何部分覆盖 OOTB 组件的 osgi 配置?

java - 在Java中使用正则表达式,如何从未知长度的字符串中捕获数字?

maven - 传递依赖 : Using Elasticsearch Rest High Client problem in AEM

java - IntelliJ Jar 错误 : Invalid signature file digest for Manifest main attributes

osgi - 如何获取 Equinox 3.10 及更高版本中所有已加载的 bundle

javascript - CQ5 ECMA 脚本获取对服务的引用

java - Spring Data MongoDB - 使用嵌套字段投影进行聚合

java - 如何将错误消息添加到 Wicket 中的 ValidationError