Проблемы OSGI CXF с загрузкой одиночных классов - PullRequest
1 голос
/ 14 февраля 2012

Этот вопрос теперь для Bounty!Первый ответ, который решает эту проблему, выигрывает.

Итак, я недавно обнаружил, что пакеты в OSGI не на 100% изолированы друг от друга, особенно когда ваши пакеты имеют общий пакет, в котором есть синглтон, что можетрезультат в двух несвязанных пакетах, перезаписывающих синглтон.Эта проблема проявилась в библиотеках CXF.Позвольте мне привести подробный пример того, что происходит:

У нас есть пакет A, B и общий пакет CXF в FuseESB ServiceMix (платформа osgi).Класс Bus в CXF является одноэлементным, и из-за того, что OSGI имеет один загрузчик классов для каждого пакета, он будет использовать этот единственный пакет для каждого другого пакета, который использует CXF.Поэтому я, похоже, не могу создать разные шины для комплекта A и комплекта B, что важно для меня, потому что комплектация A должна использовать SSL, а комплектация B не должна использовать SSL.Это еще более расстраивает, учитывая, что пакет A и пакет B не имеют ничего общего друг с другом, кроме того, что они должны быть развернуты вместе в одном ServiceMix.

Теперь я был на этой проблеме дляв то время как сейчас (1-2 месяца) и я прочитал много разных решений.Проблема, однако, заключается в том, что многие решения требуют от меня полного контроля над исходным кодом, а в этом случае у меня нет.Пакет A, который я создаю, использует какую-то проприетарную стороннюю библиотеку non-osgi под названием Xenara, которая использует CXF.По причинам, не зависящим от меня, я ДОЛЖЕН использовать эту стороннюю библиотеку.К счастью, у меня есть доступ к файлу пружинного компонента CXF, который используется этой библиотекой.

Я думаю, что для решения этой проблемы мне нужно кое-что, как сделать так, чтобы комплект A мог использовать свой собственный личный экземпляр CXF илипо крайней мере, заставьте его создать свою шину CXF, которая не используется другими пакетами.Вот методы, которые я пробовал или рассматривал:

  1. Я встроил CXF в комплект A, но, к сожалению, загрузчик классов продолжал получать CXF из-за пределов комплекта A вместо того, чтобы смотреть на путь к классам.Никогда не выяснял, как заставить его искать CXF в пакете А, прежде чем искать вне пакета А.

  2. Были сделаны предложения сделать пакет А в сервисе.Я думаю, что были некоторые недоразумения, и люди думали, что синглтон был в A, а не в CXF.Несмотря на это я попробовал это, и это не решило проблему.Шина CXF по-прежнему распределялась между пакетом A и B.

  3. Переопределите загрузку классов, чтобы в пакете A для загрузки классов CXF использовался другой загрузчик классов.Я не совсем понимаю логику этого, но я уверен, что это будет очень сложно, учитывая, что пружинный компонент используется для создания шины CXF и http-проводника.См. (4) ниже, чтобы получить лучшее представление.

  4. В CXF есть способ установить шину CXF и http-канал для данного контекста потока.Я действительно хочу использовать это решение, но я не могу понять, как преобразовать файл компонента CXF в эквивалентный код Java.Файл CXF Spring Bean представлен ниже.Примечание. У меня нет доступа к исходному коду через этот http-проводник, поэтому я не использовал примеры, показывающие в эту ссылку здесь в разделе «Использование кода Java», потому что у меня нет доступаSOAPS-сервису, wsdl и т. д. ...

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
        <property name="searchSystemEnvironment" value="true" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
    </bean>
    
    <cxf:bus>
        <cxf:outInterceptors>           
            <bean class="com.xenara.messaging.security.IdentityAssertingOutInterceptor"
                  scope="singleton" />
        </cxf:outInterceptors>
    
        <cxf:features>
            <wsa:addressing xmlns:wsa="http://cxf.apache.org/ws/addressing"/>
        </cxf:features>
    </cxf:bus>
    
    <http-conf:conduit name="*.http-conduit">
        <http-conf:client AllowChunking="false" Connection="Keep-Alive" />
        <http-conf:tlsClientParameters disableCNCheck="true" secureSocketProtocol="TLS">
            <sec:keyManagers keyPassword="${javax.net.ssl.keyStorePassword}">
                <sec:keyStore type="JKS" password="${javax.net.ssl.keyStorePassword}"
                                         file="${javax.net.ssl.keyStore}" />
            </sec:keyManagers>
            <sec:trustManagers>
                <sec:keyStore type="JKS" password="${javax.net.ssl.trustStorePassword}" file="${javax.net.ssl.trustStore}" />
            </sec:trustManagers>
            <sec:cipherSuitesFilter>
                <sec:include>SSL_RSA_WITH_3DES_EDE_CBC_SHA</sec:include>
                ...
            </sec:cipherSuitesFilter>
        </http-conf:tlsClientParameters>
    </http-conf:conduit>
    

Ответы [ 2 ]

2 голосов
/ 27 марта 2012

Проблема, с которой вы сталкиваетесь, довольно существенная и основная. У вас есть статическое состояние в поддерживающей библиотеке CXF, но вы все еще хотите использовать совместно используемые экземпляры библиотек, использующих CXF. Вы не можете изменять общие библиотеки (из-за огромного размера), а также не можете изменять CXF (с закрытым исходным кодом?). Давайте назовем эти общие библиотеки Foo и Bar.

Предположим, у вас есть следующие классы:

CXF#1
Foo#1, using CXF#1
Bar#1, using CXF#1
WebApp#1, using Foo#1 and Bar#1

Если я правильно понимаю, теперь вы хотите, чтобы другое приложение использовало те же экземпляры Foo и Bar, без использования той же базовой библиотеки CXF # 1. Это соответствует следующей ситуации.

CXF#2
CXF#1
Foo#1, using CXF#1 when called by App#1, using CXF#2 when called by App#2
Bar#1, using CXF#1 when called by App#1, using CXF#2 when called by App#2
WebApp#1, using Foo#1 and Bar#1
WebApp#2, using Foo#1 and Bar#1

Это просто невозможно; не в OSGi и не в любой среде Java. Существующий класс не может динамически привязываться к другому классу, делая выбор на основе вызывающего пакета. Единственный способ сделать это без изменения библиотек - это дублировать вспомогательные библиотеки:

CXF#2
CXF#1
Foo#1, using CXF#1
Bar#1, using CXF#1
Foo#2, using CXF#2
Bar#2, using CXF#2
WebApp#1, using Foo#1 and Bar#1
WebApp#2, using Foo#2 and Bar#2

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

Хакерский / рискованный способ решения этой проблемы заключается в следующем. Вы должны быть в состоянии декомпилировать класс CXF. Это позволит вам изменить класс следующим образом:

class CXF {
    [...]
    public static CXF getInstance() {
        // based on the current Stack frame, determine which instance to return. Remember, the instance should be based on the WebApp bundle (while you still have shared libraries in between!)
    }
}

Это не надежно. Предположим, что ваше WebApp запускает поток обратного вызова, происходящий из библиотеки A. Этот поток вызывает CXF.getInstance() -> Метод getInstance() не может определить, какой WebApp запустил поток обратного вызова.

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

- РЕДАКТИРОВАТЬ - После прочтения на CXF, кажется очень странным, что CXF представляет класс Singleton. Это сделано для OSGi! Возможно, вам лучше задать вопрос в списке рассылки CXF; они будут знать все о специальном сахаре и причинах создания одиночного экземпляра, и, возможно, уже подумали об этом сценарии использования.

2 голосов
/ 15 февраля 2012

Это звучит как основная предпосылка OSGi для меня: изоляция обеспечена, но вы можете сделать многое из того, что вы можете в обычной OSGi;например, изменять статические члены класса, и, поскольку вы все совместно используете этот класс (предположительно, A экспортирует его, B и C импортирует его), другие заметят.

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

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

Для справки: эта ситуация не имеет ничего общего сServicemix, это базовая Java: если мы говорим об одном и том же классе, и кто-то меняет статическое свойство, другие заметят.Если эта ситуация вас смущает, вы можете немного прочитать о механизмах загрузки и разделения классов в OSGi.

...