Package structure of JEE application
Typically a Java EE application is designed to have multiple modules or layers. Nowadays we often divide a general web application into 3 tiers, presentation, business logic, and persistence. Most of the time we directly split whole application into 3 modules according to this 3-tiers architecture thought.
From Java EE technology perspective presentation tier is a web module, and business tier (ejb3) and persistence tier (jpa) are both ejb modules. The whole application is the assembly of these web and ejb modules.
From deployment perspective a Java EE application is a .ear package (Enterprise Application aRchive), web module is .war package (Web Application aRchive), and ejb module is .jar package. .war and .jar are all packaged inside .ear.
Java EE module types
Package types |
Structure |
Description |
EAR(.ear) |
META-INF/application.xml
lib/*.jar
<web-module>.war
<ejb-module>.jar
... |
An enterprise application. It may contains several web and ejb modules.
application.xml is Java EE standard deployment descriptor of EAR.
Sometimes Java EE container specific application deployment descriptor is also in META-INF, for example, weblogic-application.xml is weblogic-specific deployment descriptor.
lib contains shared libraries. |
EJB(.jar) |
META-INF/ejb-jar.xml
*.class |
An EJB module. ejb-jar.xml is EJB standard deployment descriptor. It has been optional since JEE5 introduced equivalent annotations. There may be also container-specific deployment descriptor under META-INF folder. |
WAR(.war) |
WEB-INF/web.xml
WEB-INF/classes/*.class
WEB-INF/lib/*.jar
*.jsp
*.js
*.css
*.html |
An WEB module. web.xml is WEB application standard deployment descriptor. It has been optional since JEE5 introduced equivalent annotations. There may be also container-specific deployment descriptor under WEB-INF folder, for example, weblogic.xml for weblogic. |
Maven projects of JEE application
Now I create a complete maven project skeleton for a JEE application, a simplest project, helloworld. The whole application includes 2 modules, one web module and one ejb module. We still need one more project which is to package and assembly these 2 modules into one EAR, one complete JEE application.
Creating these 3 maven projects are sufficient to illustrate a complete JEE application structure.
We also hope this application complies with JEE 7 specification, is able to deploy on weblogic12c, and support JDK 8 runtime environment.
EJB module
1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<packaging>ejb</packaging>
...
<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<ejbVersion>3.1</ejbVersion>
</configuration>
</plugin>
</build>
...
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Key points:
- ejb packaging
- maven-ejb-plugin maven plugin
- javaee-api dependency
2. src/main/resources/META-INF/ejb-jar.xml
<ejb-jar version="3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
<module-name>helloworld-ejb</module-name>
</ejb-jar>
This module name is used by container and is very useful to looks up resource within container.
WEB module
1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<packaging>war</packaging>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
</project>
Key points:
- war packaging
- maven-war-plugin plugin
- javaee-web-api dependency
2. src/main/webapp/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<!--<module-name>helloworld-web</module-name>-->
...
</web-app>
web.xml is optional, if no this file application still works because nowadays servlet can be declared with annotation.
And please notice the module-name declared here. It would overwrite the context-root in container specific descriptor WEB-INF/weblogic.xml if you set and <module>/<context-root> in META-INF/application.xml. For example, if you set module-name helloworld-web the URL to access the application would become http://hostname:port/helloworld-web, the context-root is replaced by module-name. For context-root declaration priority sequence is web.xml > application.xml > weblogic.xml.
EAR (Assembly) module
1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
...
<packaging>ear</packaging>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<configuration>
<version>7</version>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<skinnyWars>true</skinnyWars>
<modules>
<ejbModule>
<groupId>org.example</groupId>
<artifactId>helloworld-ejb</artifactId>
<bundleFileName>helloworld-ejb.jar</bundleFileName>
</ejbModule>
<webModule>
<groupId>org.example</groupId>
<artifactId>helloworld-web</artifactId>
<bundleFileName>helloworld-web.war</bundleFileName>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>helloworld-jar</artifactId>
<version>1.0-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>helloworld-ejb</artifactId>
<version>1.0-SNAPSHOT</version>
<type>ejb</type>
</dependency>
</dependencies>
</project>
Key point:
- ear packaging
- maven-ear-plugin plugin
- Declare the modules you want to package inside maven-ear-plugin configuration
- Add sub-modules as dependencies
2. application.xml
<?xml version="1.0" encoding="UTF-8"?>
<application version="7" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd">
<display-name>helloworld</display-name>
<!-- application name inside container -->
<application-name>helloworld-app</application-name>
<module>
<ejb>helloworld-ejb.jar</ejb>
</module>
<module>
<web>
<web-uri>helloworld-web.war</web-uri>
<!-- Higher priority than context-root of weblogic.xml. The highest is module-name of web.xml -->
<context-root>/helloworld</context-root>
</web>
</module>
</application>
Some other maven settings you may consider
- Create parent pom to put sharing settings within modules
- Config maven-compiler-plugin plugin. Specify source code java version and target version.
- Config maven-dependency-plugin plugin