简体   繁体   中英

Are there any disadvantages in WAR packaging over EAR packaging?

I have a general architectural question about the advantage and disadvantage of EAR packaging in a Java EE application. I have a Java EE business application deployed in multiple server environments. The application consists of the following main modules:

  • EJBs with business logic
  • Web-UI
  • REST API

Without consideration of the further details of the different modules currently I package these modules into an EAR to be deployed on a Application Server like GlassFish or WildFly:

  my.ear
  /
  +- META-INF/
  |  |- application.xml
  |- my_ejb_module.jar
  |- my_web_module.war
  |- my_restservice.war

As in these days WebService and Microservice architecture is discussed more and more often, I wonder if this kind of packaging is a little bit outdated?

As I started the project for several years, this packaging seems to be the best solution, because the EJB module containing the business logic is shared across both web modules.

But when I today look at self-contained microservices I wonder if it would't be better to split the application into two deployable web modules where each of them contains the EJB module:

  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

In this setup I would be able to deploy the REST API on a separate machine. So it looks like the approach has no disadvantage against the EAR packaging.

It this true? My question goes in the direction of transactions. Is there any advantage if two web modules sharing the same EJB module in an EAR packaging? Or did the second approach where both web modules contain the same EJB module provide the same functionality concerning transaction handling and concurrency? Especially when both Web modules are deployed on the same application server.

The only disadvantage I can see so far is, that my EJB module can not contain Java EE TimerServices or MessageDriven EJBs as these kinds of EJBs are not supported when deployed in a war module. But this would be acceptable in my case.

I try to answer my question by myself: After making some test deployments I came to the conclusion, that in my case a split is not possible. The reason is, that my ejb-module contains JPA entity beans. If I deploy two web modules containing the same entity beans that will break any JPA caching concepts. A separation would only be possible if both web modules using the same REST service to access the JPA entity beans.

So my example deployment should look like this

web-ui.war
  /
  |- my_web_module.war

restservice.war
  /
  +- WEB-INF/lib
  |  |- my_ejb_module.jar
  |- my_restservice.war

where the restservice.war is the main module containging business logic and the database layer (JPA entity beans) and also publishing a open REST API. The web-ui.war only contains a web application which interacts via the REST API from the restservice.war. But bundling the ejb module in both web modules is a bad practice. EAR packaging make sense in case to bundle all modules together and provides the advantage that all client modules (war modules) can access the same EJB module transparent and in a transaction save way.

So a EJB module containing JPA entity beans should only be deployed once and not bundled into multiple deployment units.

The only disadvantage I see in ear packaging is that sometimes ears are some kind of monoliths. To simplify your architecture you can get rid of ear packaging and decompose those monoliths, if you are using full profile app server, then you can deploy ejb-jar alone as a jar file, and call EJBs from the web modules.

You can create a loosely coupled architecture using JNDI lookup:

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
}

Or a tight coupled one using CDI via annotations:

...
@EJB(mappedName="ExampleEJB")
ExampleEJB exampleEJB;
...

JNDI lookup has no restrictions, you can use it in any class. In javaee 6 annotations only works in container managed components (classes annotated with @WebService, @Stateless, @Statefull, etc).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM