Architecture 什么';基于EJB3的应用程序的最佳通信模式是什么?

Architecture 什么';基于EJB3的应用程序的最佳通信模式是什么?,architecture,jakarta-ee,ejb-3.0,jms,message-driven-bean,Architecture,Jakarta Ee,Ejb 3.0,Jms,Message Driven Bean,我正在启动一个JavaEE项目,它需要具有很强的可伸缩性。到目前为止,这一概念是: 几个消息驱动bean,负责体系结构的不同部分 每个MDB都注入了一个会话Bean,用于处理业务逻辑 两个实体bean,提供对持久层的访问 通过JMS消息通过请求/应答概念在架构的不同部分之间进行通信: MDB接收包含活动请求的消息 使用其会话bean执行必要的业务逻辑 将消息中的响应对象返回给原始请求者 其思想是,通过消息总线将体系结构的各个部分彼此解耦,对可伸缩性没有限制。只需启动更多组件-只要它们连接

我正在启动一个JavaEE项目,它需要具有很强的可伸缩性。到目前为止,这一概念是:

  • 几个消息驱动bean,负责体系结构的不同部分
  • 每个MDB都注入了一个会话Bean,用于处理业务逻辑
  • 两个实体bean,提供对持久层的访问
  • 通过JMS消息通过请求/应答概念在架构的不同部分之间进行通信:
    • MDB接收包含活动请求的消息
    • 使用其会话bean执行必要的业务逻辑
    • 将消息中的响应对象返回给原始请求者
其思想是,通过消息总线将体系结构的各个部分彼此解耦,对可伸缩性没有限制。只需启动更多组件-只要它们连接到同一总线,我们就可以不断增长

不幸的是,我们在请求-应答概念上遇到了大量问题。交易管理似乎阻碍了我们的发展。会话bean不应该使用消息吗

通过阅读,我感觉到人们实际上反对EJB的请求/回复概念

如果是这样,您如何在EJB之间进行通信?(记住,可伸缩性是我追求的目标)

我当前设置的详细信息:

  • MDB 1“TestController”将(本地)SLSB 1“TestService”用于业务逻辑
  • onMessage()使TestService向队列XYZ发送消息并请求回复
    • TestService使用Bean管理的事务
    • TestService在初始化时通过联合连接工厂建立到JMS代理的连接和会话(@PostConstruct)
    • TestService在发送后提交事务,然后开始另一个事务并等待10秒以等待响应
  • 消息到达MDB 2“LocationController”,它将(本地)SLSB 2“LocationService”用于业务逻辑
  • onMessage()使LocationService将消息发送回请求的JMSReplyTo队列
    • 相同的BMT概念,相同的@PostConstruct概念
  • 所有人都使用相同的连接工厂来访问代理
问题:第一条消息的发送(由SLSB 1)和接收(由MDB 2)正常。发送返回消息(通过SLSB 2)也可以。然而,SLSB 1从未收到任何东西-它只是超时

我在没有messageSelector的情况下尝试了,没有更改,仍然没有收到消息

通过会话bean使用消息不正常吗

SLSB 1-TestService.java

@Resource(name = "jms/mvs.MVSControllerFactory")
private javax.jms.ConnectionFactory connectionFactory;

@PostConstruct
public void initialize() {
    try {
      jmsConnection = connectionFactory.createConnection();
      session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      System.out.println("Connection to JMS Provider established");
    } catch (Exception e) { }
}

public Serializable sendMessageWithResponse(Destination reqDest, Destination respDest, Serializable request) {
    Serializable response = null;

    try {
        utx.begin();
        Random rand = new Random();
        String correlationId = rand.nextLong() + "-" + (new Date()).getTime();

        // prepare the sending message object
        ObjectMessage reqMsg = session.createObjectMessage();
        reqMsg.setObject(request);
        reqMsg.setJMSReplyTo(respDest);
        reqMsg.setJMSCorrelationID(correlationId);

        // prepare the publishers and subscribers
        MessageProducer producer = session.createProducer(reqDest);

        // send the message
        producer.send(reqMsg);
        System.out.println("Request Message has been sent!");
        utx.commit();

        // need to start second transaction, otherwise the first msg never gets sent
        utx.begin();
        MessageConsumer consumer = session.createConsumer(respDest, "JMSCorrelationID = '" + correlationId + "'");
        jmsConnection.start();
        ObjectMessage respMsg = (ObjectMessage) consumer.receive(10000L);
        utx.commit();

        if (respMsg != null) {
            response = respMsg.getObject();
            System.out.println("Response Message has been received!");
        } else {
            // timeout waiting for response
            System.out.println("Timeout waiting for response!");
        }

    } catch (Exception e) { }

    return response;
}
SLSB 2-LocationService.Java(只有reply方法,其余与上面相同)

sun-resources.xml

<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerRequest"  res-type="javax.jms.Queue"  res-adapter="jmsra">
    <property name="Name" value="mvs.LocationControllerRequestQueue"/>
</admin-object-resource>
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerResponse"  res-type="javax.jms.Queue"  res-adapter="jmsra">
    <property name="Name" value="mvs.LocationControllerResponseQueue"/>
</admin-object-resource>

<connector-connection-pool name="jms/mvs.MVSControllerFactoryPool"  connection-definition-name="javax.jms.QueueConnectionFactory"  resource-adapter-name="jmsra"/>
<connector-resource enabled="true" jndi-name="jms/mvs.MVSControllerFactory" pool-name="jms/mvs.MVSControllerFactoryPool"  />

请求/应答模式,即使使用JMS,本质上仍然是同步的。调用者发送一条消息,然后等待回复。这不仅因为分布式事务而变得复杂,还意味着在等待回复时,一个或多个资源(至少在本例中是线程)被分配和浪费。您不能这样扩展:您天生就受到线程数量的限制

要拥有真正可伸缩的JMS体系结构,所有内容都必须是异步的。换句话说,你永远不应该等待。发送和接收的消息应传递必要的信息以触发下一个活动

如果消息的大小太大,则只能存储标识符并将相应的数据存储在数据库中。但是,数据库再次成为一个争论点

如果不同的消息需要知道它们参与了哪个长期运行的进程,您也可以使用相关标识符。当收到消息时,接收方可以使用相关标识符“恢复”长时间运行的活动。这是BPEL的传统模式。同步请求/应答和具有相关标识符的异步消息之间的主要区别在于,可以在每个步骤之间释放资源。可以使用后一个进行缩放,但不能使用第一个

老实说,我对你的长篇大论感到困惑,不明白你的设计是不是相当异步(正确),还是与请求/回复同步(有问题)。但我希望我能提供一些答案


无论如何,去访问这个网站,它是一个有价值的信息来源

您使用的是哪种企业服务总线(ESB)?玻璃鱼?您如何在ESB中配置东西?请不要对您自己的问题发表评论。请用其他事实更新您的问题。然后删除你的评论。请详细描述您的glassfish配置,因为这听起来像是您的瓶颈。@Hank:“问题:第一条消息被发送(由SLSB 1)和接收(由MDB 2)ok。返回消息的发送(由SLSB 2)也可以。但是,SLSB 1从未收到任何消息-它只是超时。”所以这才是真正的问题?也许你应该修改标题,删除初步内容,只关注这个问题,让大家都清楚你的问题是什么。“@Steven:我的问题仍然是标题-大型可扩展JEE应用程序的最佳通信模式是什么。我很高兴删除代码部分(并将其移动到另一个线程),但您询问了详细信息…:)我很高兴听到您的建议。谢谢,明白了。如果是这样,我会让MDB收到响应消息(并确定请求是什么,然后从那里继续),对吗?不是在收到响应之前被阻止的会话bean。。。
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerRequest"  res-type="javax.jms.Queue"  res-adapter="jmsra">
    <property name="Name" value="mvs.LocationControllerRequestQueue"/>
</admin-object-resource>
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerResponse"  res-type="javax.jms.Queue"  res-adapter="jmsra">
    <property name="Name" value="mvs.LocationControllerResponseQueue"/>
</admin-object-resource>

<connector-connection-pool name="jms/mvs.MVSControllerFactoryPool"  connection-definition-name="javax.jms.QueueConnectionFactory"  resource-adapter-name="jmsra"/>
<connector-resource enabled="true" jndi-name="jms/mvs.MVSControllerFactory" pool-name="jms/mvs.MVSControllerFactoryPool"  />