应用程序是否可以对通过非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)
答案 0 :(得分:1)
问题归结为Mule BindingInvocationHandler
使用MuleEvent
RequestContext.getEvent()
查找当前ThreadLocal
这一事实。换句话说,由于您正在另一个线程中执行绑定,因此Mule上下文丢失,您将遇到上述故障。
使用Mule的工作管理器(你可以从MuleContext获得),这是一个更好的设计,使用你自己的ExecutorService
,仍然无法解决问题,因为BindingInvocationHandler
的依赖(已弃用!)RequestContext.getEvent()
构造。
我认为你需要重新考虑你的设计,因为当你真正研究它时,IMO并没有多大意义。在另一个线程上执行绑定不会给你带来任何东西,因为entryPoint
是请求 - 响应,所以一个入站线程被移出池。在绑定完成之前,此线程将保持阻塞状态,无论绑定本身是由此线程还是其他线程执行。
如果出于某种原因而逃避我,你真的需要在另一个线程中执行绑定,然后在另一个流程中移动绑定并使用request-reply
message processor调用它。
这里的教训是:Mule已经拥有了丰富的线程模型,最好使用它提供的线程结构(request-reply
,async
,one-way
VM队列)在其中进行游戏。而不是自己编码。