在前面的章節中,我們學習了 JAR(Java Archive)和 WAR(Web Application Archive)的打包方式。今天我們要探討企業級應用開發中的另一個重要打包格式:EAR (Enterprise Application Archive)。
EAR 是 Java EE(現在稱為 Jakarta EE)規範中定義的企業應用打包格式,專門用於將多個模組(JAR、WAR、RAR)打包成一個可部署的單元,簡化部署流程
EAR (Enterprise Application Archive) 同JAR檔他也是一個ZIP格式的檔案式,它可以同時將WAR、JAR、RAR檔集於一身包裝成EAR,它需要部署於有實作JavaEE規格的Application Server中,像是常見的Tomcat是無法部署該類型檔案的,需要部署像是TomEE、Jboss EAP、WebSphere這樣類型的Application Server中,EAR相關內容請參考以下圖片
註:圖片來自Jarkata官網
1. META-INF: 通常會有Jarkata EE規格的部署描述檔(Deployment descriptors,簡稱DD檔)與實作Jarkata EE的AppServer的部署描述檔,例如glassfish-application.xml、ibm-ejb-jar-bnd.xmi、 jboss-deployment-structure.xml等等
2. EJB Module: 當開發出企業級元件Enterprise Bean時,就需要透過部署描述檔ejb-jar.xml來與AppServer進行溝通,MAINFEST.MF作為JAR檔相關資訊存放的地方
3. Web Module: 與前一日介紹的相近,不同的是當有使用到Enterprise Bean則會需要新增部署描述檔ejb-jar.xml
4. Application Client Module: 專門用於其他應用程式或其他 Java 應用程式存取到EAR中提供的企業級服務模組。
4. Resource Application Module: 資源配接器模組針對特定 EIS(企業資訊系統,Enterprise Information System)的 連接器架構封裝為副檔名為 .rar(Resource Adapter Archive)的 JAR 檔案。
1.準備TomEE
要執行JavaEE專案我們需要有support的Application Server,我們選用TomEE作為示範,下載並解壓縮
2.創建專案
請參考Day 15 - Project Inheritance 建置專案結構
demoejb
  +---demoear-ear   (作為打包使用module)     
  |
  +---demoear-ejb   (ejb module)
  |       
  +---demoear-web   (引用ejb的web module)
  |                   
  \---demoejb-client  (client呼叫ejb的app)
3.父層pom
  <groupId>com.mycompany.demoear</groupId>
  <artifactId>demoear</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>demoear</name>
  <description>demo ear project</description>
  <packaging>pom</packaging>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 加入以下編碼設定 -->
    <file.encoding>UTF-8</file.encoding>
    <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <tomee.version>10.1.2</tomee.version>
  </properties>
  <modules>
    <module>demoear-ejb</module>
    <module>demoear-web</module>
    <module>demoear-client</module>
    <module>demoear-ear</module>
  </modules>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.platform</groupId>
      <artifactId>jakarta.jakartaee-api</artifactId>
      <version>10.0.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
4.demoear-ejb模組
pom.xml
  <parent>
    <artifactId>demoear</artifactId>
    <groupId>com.mycompany.demoear</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>demoear-ejb</artifactId>
  <name>demoear-ejb</name>
  <packaging>ejb</packaging>
HelloLocal.java
@Local
public interface HelloLocal {
    String sayHello(String name);
}
HelloLocalBean.java
@Stateless
public class HelloLocalBean implements HelloLocal {
    @Override
    public String sayHello(String name) {
        return "HelloLocal, " + name + "!";
    }
}
HelloRemote.java
@Remote
public interface HelloRemote {
    String sayHello(String name);
}
HelloRemoteBean.java
@Stateless
public class HelloRemoteBean implements HelloRemote {
    @Override
    public String sayHello(String name) {
        return "HelloRemote, " + name + "!";
    }
}
5.demoear-web 模組
  <parent>
    <artifactId>demoear</artifactId>
    <groupId>com.mycompany.demoear</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>demoear-web</artifactId>
  <packaging>war</packaging>
  <name>demoear-web Maven Webapp</name>
  <dependencies>
    <dependency>
      <groupId>com.mycompany.demoear</groupId>
      <artifactId>demoear-ejb</artifactId>
      <version>${project.version}</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
HelloServlet.java
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @EJB
    private HelloLocal helloLocal;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        String message = helloLocal.sayHello("Hi Demoear Webmodule");
        response.setContentType("text/plain");
        try {
            response.getWriter().write(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
6.demoear-client 模組
  <parent>
    <artifactId>demoear</artifactId>
    <groupId>com.mycompany.demoear</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>demoear-client</artifactId>
  <name>demoejb-client</name>
  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>demoear-ejb</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomee</groupId>
        <artifactId>openejb-core</artifactId>
        <version>${tomee.version}</version>
        <scope>provided</scope>
    </dependency>
  </dependencies>
public class App {
    public static void main(String[] args) throws Exception {
         Properties p = new Properties();
            p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.core.LocalInitialContextFactory");
            p.put(Context.PROVIDER_URL, "http://localhost:8080/tomee/ejb");
            final Context ctx = new InitialContext(p);
            HelloRemote helloBean = (HelloRemote) ctx.lookup("HelloRemoteBeanRemote");
            String message = helloBean.sayHello("EJB Client");
            System.out.println("Result: " + message);
    }
}
7.demoear-ear 模組
  <parent>
    <groupId>com.mycompany.demoear</groupId>
    <artifactId>demoear</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>demoear-ear</artifactId>
  <packaging>ear</packaging>
  <name>ear assembly</name>
  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>demoear-ejb</artifactId>
      <version>${project.version}</version>
      <type>ejb</type>
    </dependency>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>demoear-web</artifactId>
      <version>${project.version}</version>
      <type>war</type>
    </dependency>
  </dependencies>
  <build>
    <plugins>
    <!-- Cargo Plugin for TomEE -->
    <plugin>
      <groupId>org.codehaus.cargo</groupId>
      <artifactId>cargo-maven3-plugin</artifactId>
      <configuration>
        <container>
          <containerId>tomee9x</containerId>
          <home>H:\Java\apache-tomee-plus-10.1.2</home>
        </container>
        <configuration>
          <type>standalone</type>
        </configuration>
        <deployables>
          <deployable>
            <groupId>com.mycompany.demoear</groupId>
            <artifactId>demoear-ear</artifactId>
            <type>ear</type>
          </deployable>
        </deployables>
      </configuration>
    </plugin>
  </plugins>
  </build>
web執行
client執行
因為對Jarkata EE不熟這一天寫來真不易,透過Web註解的方式就可調用EJB,EJB本身也透過註解進行設定相當方便,大幅簡化過去需要設定ejb-jar.xml的流程,回歸今天的主題,我們演示了JarktaEE的專案,通常會是以多模組的形式出現,會有一個額外的模組進行ear檔打包,另外在打包Web模組時有遇到因為EJB的JAR我們有打包進EAR檔,所以pom.xml只需要設定provided就可以了