iT邦幫忙

2025 iThome 鐵人賽

DAY 10
0
Software Development

我們與Maven的距離系列 第 26

Day25 - EAR Packaging and Deploy

  • 分享至 

  • xImage
  •  

前言

在前面的章節中,我們學習了 JAR(Java Archive)和 WAR(Web Application Archive)的打包方式。今天我們要探討企業級應用開發中的另一個重要打包格式:EAR (Enterprise Application Archive)

EAR 是 Java EE(現在稱為 Jakarta EE)規範中定義的企業應用打包格式,專門用於將多個模組(JAR、WAR、RAR)打包成一個可部署的單元,簡化部署流程

什麼是 EAR?

EAR (Enterprise Application Archive) 同JAR檔他也是一個ZIP格式的檔案式,它可以同時將WAR、JAR、RAR檔集於一身包裝成EAR,它需要部署於有實作JavaEE規格的Application Server中,像是常見的Tomcat是無法部署該類型檔案的,需要部署像是TomEE、Jboss EAP、WebSphere這樣類型的Application Server中,EAR相關內容請參考以下圖片
https://ithelp.ithome.com.tw/upload/images/20251010/20128084fanubGDERD.png
註:圖片來自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檔相關資訊存放的地方
https://ithelp.ithome.com.tw/upload/images/20251010/20128084OIXhXc78Zd.png
3. Web Module: 與前一日介紹的相近,不同的是當有使用到Enterprise Bean則會需要新增部署描述檔ejb-jar.xml
https://ithelp.ithome.com.tw/upload/images/20251010/20128084x0vf0vDZNN.png
4. Application Client Module: 專門用於其他應用程式或其他 Java 應用程式存取到EAR中提供的企業級服務模組。
4. Resource Application Module: 資源配接器模組針對特定 EIS(企業資訊系統,Enterprise Information System)的 連接器架構封裝為副檔名為 .rar(Resource Adapter Archive)的 JAR 檔案。

範例演示 - EAR打包與部署

1.準備TomEE
要執行JavaEE專案我們需要有support的Application Server,我們選用TomEE作為示範,下載並解壓縮
https://ithelp.ithome.com.tw/upload/images/20251010/20128084nXuhqPMHjs.png

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執行
https://ithelp.ithome.com.tw/upload/images/20251010/20128084fH3M1SxzM4.png

client執行
https://ithelp.ithome.com.tw/upload/images/20251010/20128084LQSujz1s44.png

小結

因為對Jarkata EE不熟這一天寫來真不易,透過Web註解的方式就可調用EJB,EJB本身也透過註解進行設定相當方便,大幅簡化過去需要設定ejb-jar.xml的流程,回歸今天的主題,我們演示了JarktaEE的專案,通常會是以多模組的形式出現,會有一個額外的模組進行ear檔打包,另外在打包Web模組時有遇到因為EJB的JAR我們有打包進EAR檔,所以pom.xml只需要設定provided就可以了

Reference


上一篇
Day24 - WAR Packaging and Deploy
系列文
我們與Maven的距離26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言