在Mule线程以外的线程上调用通过组件绑定创建的代理

时间:2012-11-19 21:37:46

标签: mule

应用程序是否可以对通过非Mule线程(即应用​​程序创建的线程)上的组件绑定创建的代理进行调用?我试图这样做,我在org.mule.DefaultMuleEvent上得到一个NullPointerException:268。

关于Mule EE 3.3.0的内容

感谢。

更新:

骡子代码

<mule ...>
    <vm:endpoint path="entryPoint" name="entryPoint" />

    <flow name="entryPoint.Flow">
        <inbound-endpoint ref="entryPoint" exchange-pattern="request-response" />
        <component class="foo.Component">
            <binding interface="foo.Interface" method="echo">
            <vm:outbound-endpoint path="foo.Interface.echo" exchange-pattern="request-response" />
        </binding>
        </component>
    </flow>

    <flow name="foo.Interface.echo">
        <vm:inbound-endpoint path="foo.Interface.echo" exchange-pattern="request-response" />
        <logger level="INFO" />
    </flow>

</mule>

Java组件

package foo;

import static java.util.concurrent.Executors.newSingleThreadExecutor;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Component {

    private Interface i;

    public String foo(final String input) {
        return callInterfaceOnAWorkerThreadWith(input);
    }

    public void setInterface(final Interface i) {
        this.i = i;
    }

    private String callInterfaceOnAWorkerThreadWith(final String input) {
        ExecutorService executorService = newSingleThreadExecutor();
        Future<String> future = executorService.submit(new Callable<String>() {

            @Override
            public String call() throws Exception {
                return i.echo(input);
            }

        });
        executorService.shutdown();
        try {
            executorService.awaitTermination(60, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        try {
            return future.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

    }

}

Java界面

package foo;

public interface Interface {

    String echo(String input);

}

执行骡子应用程序的测试夹具

package foo;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.client.MuleClient;
import org.mule.tck.junit4.FunctionalTestCase;

@RunWith(MockitoJUnitRunner.class)
public class ATest extends FunctionalTestCase {

    @Test
    public void echo() {
        final MuleClient client = muleContext.getClient();
        MuleMessage reply = send(client, "entryPoint", "a string");
        assertEquals("a string", reply.getPayload());
    }

    @Override
    protected String getConfigResources() {
        return "app/componentbindingonanotherthread.xml";
    }

    private MuleMessage send(final MuleClient client, final String url, final Object payload) {
        try {
            return client.send(url, payload, null, RECEIVE_TIMEOUT);
        } catch (final MuleException e) {
            throw new RuntimeException(e);
        }
    }

}

执行上面的代码会在日志中显示以下异常:

Root Exception stack trace:
java.lang.NullPointerException
    at org.mule.DefaultMuleEvent.<init>(DefaultMuleEvent.java:268)
    at org.mule.component.BindingInvocationHandler.invoke(BindingInvocationHandler.java:96)
    at $Proxy14.echo(Unknown Source)

1 个答案:

答案 0 :(得分:1)

问题归结为Mule BindingInvocationHandler使用MuleEvent RequestContext.getEvent()查找当前ThreadLocal这一事实。换句话说,由于您正在另一个线程中执行绑定,因此Mule上下文丢失,您将遇到上述故障。

使用Mule的工作管理器(你可以从MuleContext获得),这是一个更好的设计,使用你自己的ExecutorService,仍然无法解决问题,因为BindingInvocationHandler的依赖(已弃用!)RequestContext.getEvent()构造。

我认为你需要重新考虑你的设计,因为当你真正研究它时,IMO并没有多大意义。在另一个线程上执行绑定不会给你带来任何东西,因为entryPoint是请求 - 响应,所以一个入站线程被移出池。在绑定完成之前,此线程将保持阻塞状态,无论绑定本身是由此线程还是其他线程执行。

如果出于某种原因而逃避我,你真的需要在另一个线程中执行绑定,然后在另一个流程中移动绑定并使用request-reply message processor调用它。

这里的教训是:Mule已经拥有了丰富的线程模型,最好使用它提供的线程结构(request-replyasyncone-way VM队列)在其中进行游戏。而不是自己编码。