Статьи

Клиентский Мул

Мул   обычно используется на получающем конце запросов на обслуживание. Например, потоки мулов обычно инициируются внешними событиями, такими как отправка JMS-сообщения в очередь, HTTP-запрос POSTed или срабатывание кварцевого триггера. Поскольку Mule обычно развертывается как сервер, такого поведения следует ожидать. Однако, что не так очевидно, так это использование Mule в качестве клиента этих сервисов. В этом сообщении мы увидим, как MuleClient может быть встроен в не-Mule-приложение для отправки и получения сообщений в качестве клиента.

Настройка MuleClient с помощью Spring

Для целей этого поста в блоге я предполагаю, что у нас есть довольно простое приложение Spring MVC, которое работает с данными о продукте. Мы начнем с изменения контроллера Spring MVC для использования MuleClient для асинхронной отправки объекта Product в очередь JMS. Затем мы увидим, как мы можем изменить этот вызов, чтобы вызвать ответ из временной очереди, воспользовавшись поддержкой Mule для синхронного JMS. Наконец, мы увидим, как мы можем выполнить «локальную» интеграцию и вызвать ее из приложения Spring MVC, используя MuleClient.

Однако прежде чем мы сможем сделать что-либо из этого, нам нужно подключить экземпляр MuleClient в нашем приложении Spring MVC. Начнем с создания файла mule-config.xml в каталоге приложения ./src/main/resources/META-INF приложения Spring. Мы создадим каталог с именем «mule» и поместим в него следующий файл mule-config.xml.

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:vm="http://www.mulesoft.org/schema/mule/vm"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:spring="http://www.springframework.org/schema/beans"
      xmlns:jms="http://www.mulesoft.org/schema/mule/jms"
      xmlns:mule-xml="http://www.mulesoft.org/schema/mule/xml"
      xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.2/mule.xsd
http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/3.2/mule-vm.xsd
http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/3.2/mule-jms.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.mulesoft.org/schema/mule/xml http://www.mulesoft.org/schema/mule/xml/3.2/mule-xml.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
">

    <spring:bean name="connectionFactory"
                 class="org.apache.activemq.ActiveMQConnectionFactory">
        <spring:property name="brokerURL" value="vm://activemq01"/>
    </spring:bean>

    <jms:activemq-connector name="jmsConnector" connectionFactory-ref="connectionFactory"/>

</mule>

Эта конфигурация настраивает соединитель JMS, на который мы будем ссылаться из контроллера Spring. Теперь давайте подключим MuleClient весной. Для этого случая я добавлю следующие строки в мой файл applicationContext.xml.

<bean name="muleClient" class="org.mule.module.client.MuleClient" scope="singleton">
    <constructor-arg value="META-INF/mule/mule-config.xml"/>
</bean>

Теперь мы можем внедрить синглтон MuleClient в класс контроллера ProductController, например так:

@RequestMapping("/products")
@Controller
public class ProductController {

    @Autowired
    MuleClient muleClient;

    @RequestMapping(method = RequestMethod.POST)
    public void save(@RequestBody Product product) throws Exception {
      // ToDo implement code to dispatch to JMS
    }
}

Отправка сообщений JMS

MuleClient готов к этому моменту. Давайте изменим метод save () для отправки сообщения JMS, содержащего данные о продукте.

@RequestMapping(method = RequestMethod.POST)
    public void save(@RequestBody Product product) throws Exception {
        muleClient.dispatch("jms://products", product, null);
}

Мы вызываем метод dispatch () MuleClient для асинхронного помещения объекта Product в очередь JMS с именем «products».

Надеюсь, очевидно, насколько это просто. Реализация такого же поведения с нативными библиотеками JMS или даже Spring JmsTemplate, потребовала бы значительно больше работы. Это дополнительно демонстрируется, если мы изменим код для ожидания ответа во временной очереди. Предполагая, что «удаленной» стороной этой очереди является входящая конечная точка JMS Mule с шаблоном обмена запросом-ответом, тогда нам просто нужно сделать следующее.

@ResponseBody
@RequestMapping(method = RequestMethod.POST)
public Product save(@RequestBody Product product) throws Exception {
    MuleMessage response = muleClient.send("jms://products", product, null, 2000);
    if (response == null || response.getPayload() instanceof NullPayload) {
        throw new InvalidProductResponseException();
    } else {
        return (Product) response.getPayload();
    }
}

Изменение «рассылки» на «отправка» заставляет MuleClient ожидать ответа. В этом случае он будет ожидать возврата Продукта во временную очередь, предположительно каким-то образом измененную (т. Е. Его поле идентификатора заполнено идентификатором базы данных). Если ответ не получен в течение 2 секунд или нулевой ответ вернувшись, мы бросаем исключение. В противном случае измененный Продукт возвращается веб-браузеру или потребителю API.

Аудит данных о продукции

Давайте предположим, что нам нужно выполнить аудит данных о продуктах, отправленных в очередь JMS, возможно, отправив их в удаленный API. Это может быть несколько усложнено в коде, особенно в контроллере, но тривиально для реализации с потоком Мула, как показано ниже.

<flow name="submitAndAuditProductDefinitions">
    <vm:inbound-endpoint path="products" exchange-pattern="one-way"/>
    <all>
        <jms:outbound-endpoint queue="products" exchange-pattern="one-way"/>
        <http:outbound-endpoint host="api.acmesoft.com" port="80" path="productAudit"
                   exchange-pattern="one-way"/>
    </all>
</flow>

Assuming the above flow is added to the mule-config.xml configured at the beginning of this post, we just need to modify the MuleClient code in ProductController to dispatch to the VM queue rather then JMS as follows.

@RequestMapping(method = RequestMethod.POST)
public void save(@RequestBody Product product) throws Exception {
    muleClient.dispatch("vm://products", product, null);
}

Wrapping Up

You may have already been aware of MuleClient, particularly in the context of writing functional tests (where it is indispensable.)   This post illustrates that MuleClient has a role in the client side of your applications as well.  We saw how to use MuleClient to dispatch and synchronously consume messages off JMS queues.  We also saw how MuleClient facilitates adhoc integrations while embedded in a non-Mule application.  These techniques will hopefully let you use Mule to simplify not just your server side integrations, but your client side ones as well.