我有一个关于JavaEE应用程序中EAR打包的优缺点的一般架构问题。我有一个JavaEE业务应用程序部署在多个服务器环境中。该应用程序由以下主要模块组成:
不考虑不同模块的进一步细节,目前我将这些模块打包成一个EAR,部署在GlassFish或WildFly等应用服务器上:
my.ear
/
+- META-INF/
| |- application.xml
|- my_ejb_module.jar
|- my_web_module.war
|- my_restservice.war
随着如今WebService和微服务架构被越来越多地讨论,我想知道这种打包是否有点过时了?
当我开始这个项目几年时,这个打包似乎是最好的解决方案,因为包含业务逻辑的EJB模块在两个Web模块之间共享。
但是当我今天查看自包含的微服务时,我想知道将应用程序拆分为两个可部署的Web模块,其中每个模块都包含EJB模块是否会更好:
web-ui.war
/
+- WEB-INF/lib
| |- my_ejb_module.jar
|- my_web_module.war
restservice.war
/
+- WEB-INF/lib
| |- my_ejb_module.jar
|- my_restservice.war
在此设置中,我将能够在单独的机器上部署RESTAPI。因此,看起来该方法与EAR打包相比没有劣势。
这是真的吗?我的问题是关于事务的。如果两个Web模块在EAR打包中共享相同的EJB模块,有什么好处吗?或者第二种方法,两个Web模块都包含相同的EJB模块,在事务处理和并发方面提供了相同的功能吗?尤其是当两个Web模块都部署在同一个应用程序服务器上时。
到目前为止,我看到的唯一缺点是,我的EJB模块不能包含JavaEETimerServices或MessageDriven EJB,因为在war模块中部署时不支持这些类型的EJB。但这在我的情况下是可以接受的。
我试着自己回答我的问题:在进行了一些测试部署后,我得出结论,在我的情况下,拆分是不可能的。原因是,我的ejb-module包含JPA实体bean。如果我部署两个包含相同实体bean的Web模块,这将破坏任何JPA缓存概念。只有当两个Web模块使用相同的REST服务访问JPA实体bean时,分离才有可能。
所以我的示例部署应该是这样的
web-ui.war
/
|- my_web_module.war
restservice.war
/
+- WEB-INF/lib
| |- my_ejb_module.jar
|- my_restservice.war
其中restservice. war是包含业务逻辑和数据库层(JPA实体bean)以及发布开放RESTAPI的主要模块。web-ui.war只包含一个Web应用程序,该应用程序通过来自restservice.war的RESTAPI进行交互。但是将ejb模块捆绑在两个Web模块中是一种不好的做法。EAR打包在将所有模块捆绑在一起的情况下是有意义的,并提供了所有客户端模块(war模块)可以透明且以事务保存方式访问相同EJB模块的优势。
因此,包含JPA实体bean的EJB模块应该只部署一次,而不是捆绑到多个部署单元中。
我看到的耳朵打包的唯一缺点是有时耳朵是某种单体。为了简化您的架构,您可以摆脱耳朵打包并分解这些单体,如果您使用完整的配置文件应用程序服务器,那么您可以将ejb-jar单独部署为jar文件,并从Web模块调用EJB。
您可以使用JNDI查找创建松散耦合的架构:
ExampleEJB exampleEJB;
...
private ExampleEJB getExampleEJB() {
if (this.exampleEJB == null) {
InitialContext ic = new InitialContext();
this.exampleEJB = (ExampleEJB)ic.lookup("ExampleEJB#com.example.ExampleEJB");
}
return this.exampleEJB
}
或者通过注释使用CDI的紧密耦合:
...
@EJB(mappedName="ExampleEJB")
ExampleEJB exampleEJB;
...
JNDI查找没有限制,您可以在任何类中使用它。在javaee 6中,注释仅适用于容器管理的组件(使用@WebService、@Statless、@Stateful等注释的类)。