Несколько загрузчиков классов в одном пакете OSGI приводят к исключениям приведения классов - PullRequest
0 голосов
/ 11 сентября 2018

Иногда, после развертывания нашего приложения и удаления и установки пакетов, мы получаем исключения приведения класса, когда класс 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 X , тот же идентификатор) они не равны.

Связка 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 или может быть какая-то ошибка в дизайне с нашей стороны?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

ClassCastException генерируется, если два рассматриваемых экземпляра класса имеют разные загрузчики классов.

Когда пакет обновляется или удаляется, и он экспортировал пакеты, эти пакеты не удаляются, и пакеты, разрешенные для старого неустановленного пакета, будутвсе еще используйте старый / устаревший код, пока пакеты не обновятся.Это правильное поведение, определенное спецификацией OSGi.

Реализация Sling (которая является базовой платформой для AEM) вызывает установщик пакета, который вызывает обновление после установки, обновления или удаления, поэтому эта проблема вообще не должна появляться,Вы должны выяснить, почему в некоторых случаях происходит сбой обновления - отправной точкой было бы включить ведение журнала трассировки для следующих классов и посмотреть, что происходит-

org/apache/sling/installer/core/impl/tasks/BundleUpdateTask
org/apache/sling/installer/core/impl/tasks/RefreshBundlesTask
0 голосов
/ 11 сентября 2018

Вы храните объекты типа, созданного более старой ревизией пакета, и ожидаете, что они будут преобразованы в тип, созданный более новой ревизией пакета.Ваш кеш, хранилище токенов, должен сделать недействительными любые объекты, хранящиеся в пакете, когда этот пакет остановлен.

...