Статьи

Отправка сообщений JMS из WildFly 8 в WebLogic 12 с помощью Camel

Системная интеграция — хороший вызов. Особенно, когда вы ищете стандарты связи и надежные решения. В современном мире микросервисов все говорят о сервисах REST и протоколах на основе http. На самом деле этого никогда не будет достаточно для большинства корпоративных проектов, которые обычно имеют гораздо более сложный набор требований. Разумное решение — интеграция на основе службы сообщений Java. И хотя мы больше не рассматриваем централизованные инфраструктуры и ESB, мы хотим использовать интеграцию определенных сервисов по принципу «точка-точка». Давайте посмотрим, сможем ли мы заставить это работать и отправлять сообщения между JBoss WildFly и Oracle WebLogic Server.

Бизнес-кейс — от Java EE к микросервисам

сценарий

Но сначала я хочу сделать шаг назад: зачем кому-то? Я думаю, что одной из основных причин такого сценария является медленный путь миграции. Отходя от монолитных одноплатформенных приложений, мы хотим быть достаточно гибкими, чтобы выделять отдельные сервисы из этих гигантских установок и делать их доступными в качестве сервиса. Предполагая, что это даже возможно, и унаследованное приложение имеет достойный дизайн. Или мы хотим продвигать отдельные услуги, скажем, с технической точки зрения. В этом конкретном примере мы не можем дождаться, чтобы включить функции Java EE 7 в наше приложение, и WebLogic по-прежнему в основном зависает на EE 6. Мы можем сделать это с помощью служб REST или даже WebServices, но нам может потребоваться больше. И именно здесь вступает в силу спецификация JMS .

Клиентские библиотеки Oracle JMS в WildFly

Чтобы отправлять сообщения между двумя разными серверами, вам нужно интегрировать отдельные клиентские библиотеки в отправляющую сторону. Для WebLogic это тонкий клиент WebLogic JMS (wljmsclient.jar). обеспечивает функциональность Java EE и WebLogic JMS, используя гораздо меньшую площадь клиента, чем установка WebLogic или полный клиент, и несколько меньшую площадь клиента, чем клиент Thin T3. На самом деле, он содержит API-интерфейсы JMS Java EE и реализации, которые будут напрямую конфликтовать с теми, которые предоставляет WildFly. Чтобы использовать их, нам нужно будет упаковать их в виде модуля и настроить JMS Bridge в HornetQ, чтобы использовать именно это. Первое, что нужно добавить новый модуль. Измените папку на wildfly-8.2.0.Final \ modules \ system \ layer \ base и создайте новую структуру папок: custom \ oracle \ weblogic \ main под ней. Скопируйте wlthint3client.jar из папки% MW_HOME% \ server \ lib здесь. Теперь вам нужно добавить файл дескриптора модуля module.xml:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<module xmlns="urn:jboss:module:2.0" name="custom.oracle.weblogic">
    <resources>
        <resource-root path="wlthint3client.jar">
            <filter>
                <exclude-set>
                    <path name="javax.ejb"/>
                    <path name="javax.ejb.spi"/>
                    <path name="javax.transaction"/>
                    <path name="javax.jms"/>
                    <path name="javax.xml"/>
                    <path name="javax.xml.stream"/>
                </exclude-set>
            </filter>
        </resource-root>
    </resources>
 
    <dependencies>
        <module name="javax.api"/>
        <module name="sun.jdk" export="false" services="import">
            <exports>
                <include-set>
                    <path name="sun/security/acl"/>
                    <path name="META-INF/services"/>
                </include-set>
            </exports>
        </module>
        <module name="com.sun.xml.bind" />
        <module name="org.omg.api"/>
        <module name="javax.ejb.api" export="false"   />
        <module name="javax.transaction.api"  export="false" />
        <module name="javax.jms.api"  export="false" />
        <module name="javax.xml.stream.api" export="false"  />
        <module name="org.picketbox" optional="true"/>
        <module name="javax.servlet.api" optional="true"/>
        <module name="org.jboss.logging" optional="true"/>
        <module name="org.jboss.as.web" optional="true"/>
        <module name="org.jboss.as.ejb3" optional="true"/>
        <module name="org.hornetq" />
    </dependencies>
</module>

Этот файл определяет все необходимые ресурсы и зависимости вместе с соответствующими исключениями. Если это сделано, нам, наконец, нужен мост сообщений.

Мост сообщений HMS HornetQ

Функция моста JMS состоит в том, чтобы получать сообщения из исходного места назначения JMS и отправлять их в целевое место назначения JMS. Обычно источник или целевое назначение находятся на разных серверах. Мост также можно использовать для объединения сообщений с других серверов JMS, отличных от HornetQ, если они соответствуют JMS 1.1. Откройте standalone-full.xml и добавьте следующую конфигурацию в подсистему обмена сообщениями:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<jms-bridge name="wls-bridge" module="custom.oracle.weblogic">
                <source>
                    <connection-factory name="java:/ConnectionFactory"/>
                    <destination name="java:/jms/sourceQ"/>
                </source>
                <target>
                    <connection-factory name="jms/WFMessagesCF"/>
                    <destination name="jms/WFMessages"/>
                    <context>
                        <property key="java.naming.factory.initial"
                              value="weblogic.jndi.WLInitialContextFactory"/>
                        <property key="java.naming.provider.url" 
                              value="t3://127.0.0.1:7001"/>
                    </context>
                </target>
                <quality-of-service>AT_MOST_ONCE</quality-of-service>
                <failure-retry-interval>2000</failure-retry-interval>
                <max-retries>10</max-retries>
                <max-batch-size>500</max-batch-size>
                <max-batch-time>500</max-batch-time>
                <add-messageID-in-header>true</add-messageID-in-header>
            </jms-bridge>

Как видите, он напрямую ссылается на модуль и имеет определение источника и цели. Источником является локальная очередь сообщений WildFly, которая определена в подсистеме обмена сообщениями:

1
2
3
   <jms-queue name="sourceQ">
       <entry name="java:/jms/sourceQ"/>
   </jms-queue>

И целью является удаленная очередь плюс фабрика соединений, которые определены в WebLogic Server. Я предполагаю, что вы знаете, как это сделать, если нет, пожалуйста, обратитесь к этой документации . Вот и все. Теперь нам нужно отправить сообщение в нашу локальную очередь, и оно будет отправлено через мост через очередь WebLogic.

Тестирование моста — с верблюдом

Разверните bean-компонент, управляемый сообщениями, в WebLogic (да, вам придется упаковать его как ejb jar в ухо и все это). Этот конкретный пример просто выводит текст сообщения в регистратор.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@MessageDriven(mappedName = "jms/WFMessages", activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
 
public class LogMessageBean implements MessageListener {
    private final static Logger LOGGER = Logger.getLogger(LogMessageBean.class.getName());
 
    public LogMessageBean() {
    }
 
    @Override
    public void onMessage(Message message) {
        TextMessage text = (TextMessage) message;
        try {
            LOGGER.log(Level.INFO, text.getText());
        } catch (JMSException jmxe) {
            LOGGER.log(Level.SEVERE, jmxe.getMessage());
        }
    }
}

Теперь нам нужен продюсер на сервере WildFly. Сделайте это, я на самом деле использую интеграцию WildFly-Camel JMS .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Startup
@ApplicationScoped
@ContextName("jms-camel-context")
public class JMSRouteBuilder extends RouteBuilder {
 
    @Override
    public void configure() throws Exception {
        // Initial Context Lookup
        Context ic = new InitialContext();
        ConnectionFactory cf = (ConnectionFactory) ic.lookup("/ConnectionFactory");
        // Create the JMS Component
        JmsComponent component = new JmsComponent();
        component.setConnectionFactory(cf);
        getContext().addComponent("jms", component);
        // Build A JSON Greeting
        JsonObject text = Json.createObjectBuilder()
                 .add("Greeting", "From WildFly 8").build();
        // Send a Message from timer to Queue
        from("timer://sendJMSMessage?fixedRate=true.=10000")
                .transform(constant(text.toString()))
                .to("jms:queue:sourceQ")
                .log("JMS Message sent");
    }
}

Вот и вся магия. Таймер отправляет текстовое сообщение JSON в локальную очередь, которая соединяется с WebLogic.

сообщение-в-WLS

Еще несколько советов

Если вы хотите протестировать очередь WebLogic без моста, вам нужно будет включить wljmsclient в ваш проект. Поскольку это недоступно в репозитории Maven (AFAIK), вы можете просто установить его локально:

1
mvn install:install-file -Dfile=%MW_HOME%/wlserver/server/lib/wlthint3client.jar -DgeneratePom=true -DgroupId=custom.com.oracle -DartifactId=wlthint3client -Dversion=12.1.3 -Dpackaging=jar

Другая важная вещь заключается в том, что вы столкнетесь с проблемами загрузки классов в WildFly, если попытаетесь использовать пользовательский модуль в любой другой области, кроме моста. Итак, обратите пристальное внимание, чтобы вы не использовали его где-то еще.

Мост имеет сравнительно большой интервал повторения отказов и настроен максимум попыток. Это обходной путь. Если WildFly запускается слишком быстро и мост пытается получить доступ к локальному sourceQ до того, как очередь будет настроена, это приведет к исключению.