﻿# 如何將 Spring Boot 應用程式部署到 WildFly 應用程式伺服器

開源的 WildFly 應用程式伺服器 (WildFly Application Server) (WildFly AS) 是商用的 JBoss EAP (Enterprise Application Server) 的上游版本 (upstream project)。意思也就是說，JBoss EAP 是基於 WildFly AS 打造的，你只要學會如何部署應用程式到 WildFly AS，大概就知道如何部署到 JBoss EAP。今天這篇文章我打算來介紹如何將 Spring Boot 應用程式部署到 WildFly 應用程式伺服器。

![WildFly](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/765bd047c411ed5547dd-190064728-cd61c7c4-1322-4bd3-9ea4-2ae5b830254a.png)

### 啟動 WildFly 應用程式伺服器

本文將以目前最新穩定版 WildFly 26.1.2 Final 版本為例。

1.  先到 [WildFly Downloads](https://www.wildfly.org/downloads/) 下載**最新穩定版**並**解壓縮**
    
    假設我們將 `wildfly-26.1.2.Final.zip` 解壓縮到 `G:\wildfly-26.1.2.Final` 目錄下
    
2.  開啟 **Command Prompt** (命令提示字元) 視窗，進入解壓縮的資料夾
    
    ```batch
    cd /d G:\wildfly-26.1.2.Final
    ```
    
3.  建立管裡者帳號
    
    ```batch
    bin\add-user.bat
    ```
    
    假設我們設定帳號為 `wildfly`，密碼為 `wi1df1y!`
    
    ```
    What type of user do you wish to add?
    a) Management User (mgmt-users.properties)
    b) Application User (application-users.properties)
    (a): a
    
    Enter the details of the new user to add.
    Using realm 'ManagementRealm' as discovered from the existing property files.
    Username : wildfly
    Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file.
    - The password should be different from the username
    - The password should not be one of the following restricted values {root, admin, administrator}
    - The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)
    Password : wi1df1y!
    Re-enter Password : wi1df1y!
    What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[  ]:
    About to add user 'wildfly' for realm 'ManagementRealm'
    Is this correct yes/no? yes
    Added user 'wildfly' to file 'G:\wildfly-26.1.2.Final\standalone\configuration\mgmt-users.properties'
    Added user 'wildfly' to file 'G:\wildfly-26.1.2.Final\domain\configuration\mgmt-users.properties'
    Added user 'wildfly' with groups  to file 'G:\wildfly-26.1.2.Final\standalone\configuration\mgmt-groups.properties'
    Added user 'wildfly' with groups  to file 'G:\wildfly-26.1.2.Final\domain\configuration\mgmt-groups.properties'
    Is this new user going to be used for one AS process to connect to another AS process?
    e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server Jakarta Enterprise Beans calls.
    yes/no? no
    Press any key to continue . . .
    ```
    
4.  以 `standalone` 模式啟動 WildFly AS
    
    ```batch
    bin\standalone.bat --debug
    ```
    
    > 加上 `--debug` 會額外 LISTEN Port `8787` 讓 IDE 工具可以透過 Attach 的方式進行應用程式偵錯。
    
5.  開啟 `WildFly AS` 預設首頁: [http://127.0.0.1:8080/](http://127.0.0.1:8080/)
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/ff369ccf670c2073bf0a-189957995-26c9950e-8b18-4722-993a-927887c7ba24.png)
    
6.  開啟 `WildFly AS` 管裡主控台: [http://127.0.0.1:9990/](http://127.0.0.1:9990/) (帳號: `wildfly` , 密碼: `wi1df1y!`)
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/20d01a8ba65ffc4ebe3b-189958095-9814d0b8-fdbd-48da-96b4-14cdca488c51.png)
    

### 使用 Spring Boot Initializr 快速建立一個新專案

1.  請使用以下參數建立專案
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/cc05dbc55a338cb26461-189958939-23e2c80d-78af-4f87-b815-fb37abe8cd8a.png)
    
2.  撰寫一個 `HomeController` 並簡單回應一個 `Hello World` 字串即可
    
    ```java
    package com.duotify.app1.controllers;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * HomeController
    */
    @RestController
    @RequestMapping("/")
    public class HomeController {
        public HomeController() {
        }
    
        @GetMapping
        public String getString() {
            return "Hello World";
        }
    }
    ```
    
3.  調整 `src\main\resources\application.properties` 屬性檔
    
    由於 `WildFly AS` 預設會佔用 Port `8080`，剛好跟 Spring Boot 內建的 Tomcat 應用程式伺服器所用到的 Port `8080` 相衝突。因此建議你調整 `server.port` 屬性為`8081` 即可。
    
    ```ini
    server.port=8081
    ```
    
4.  啟動 Tomcat 應用程式伺服器執行
    
    [http://localhost:8081/](http://localhost:8081/)
    
    此時你應該會在畫面上看到一行很簡單的 `Hello World` 而已，看到就代表 Spring Boot 運作正常！
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/ac3c62d925511ef0320b-189960550-7a48bcc5-dd69-4c09-95d6-6e83eeefb499.png)
    
    > 在 VSCode 裡面可以開啟 `App1Application.java` 檔案之後，按下 `F5` 功能鍵就可以啟動網站。
    
5.  建立 Git 版控
    
    ```bash
    curl -sL https://www.gitignore.io/api/java,maven > .gitignore
    
    git init
    git add .
    git commit -m "Initial commit"
    ```
    

### 初始化 `WildFly AS` 部署相關設定

1.  在專案中建立一個 `src/main/webapp/WEB-INF/jboss-web.xml` 檔案
    
    ```xml
    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-web xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
        <context-root>/</context-root>
    </jboss-web>
    ```
    
2.  從 `spring-boot-starter-web` 相依套件排除 `ch.qos.logback:logback-classic` 這個 `artifact`
    
    ```xml
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <exclusions>
          <exclusion>
              <artifactId>logback-classic</artifactId>
              <groupId>ch.qos.logback</groupId>
          </exclusion>
      </exclusions>
    </dependency>
    ```
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/b82171313ef3b5d9890a-189964482-2708991b-4efd-4d25-a707-6b5d759d5fe0.png)
    
    如果你不排除 `logback-classic` 的話，到時部署就會看到以下錯誤：
    
    ```json
    {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"app1-0.0.1-SNAPSHOT.war\".undertow-deployment" => "java.lang.RuntimeException: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Slf4jLoggerFactory loaded from jar:file:/G:/wildfly-26.1.2.Final/modules/system/layers/base/org/slf4j/impl/main/slf4j-jboss-logmanager-1.1.0.Final.jar!/). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Slf4jLoggerFactory
        Caused by: java.lang.RuntimeException: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Slf4jLoggerFactory loaded from jar:file:/G:/wildfly-26.1.2.Final/modules/system/layers/base/org/slf4j/impl/main/slf4j-jboss-logmanager-1.1.0.Final.jar!/). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Slf4jLoggerFactory
        Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.Slf4jLoggerFactory loaded from jar:file:/G:/wildfly-26.1.2.Final/modules/system/layers/base/org/slf4j/impl/main/slf4j-jboss-logmanager-1.1.0.Final.jar!/). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.Slf4jLoggerFactory"}}
    ```
    
3.  加入 `wildfly-maven-plugin` plugin 到 `<build><plugins>` 區段下
    
    ```xml
    <plugin>
      <groupId>org.wildfly.plugins</groupId>
      <artifactId>wildfly-maven-plugin</artifactId>
      <version>3.0.2.Final</version>
    </plugin>
    ```
    
4.  封裝應用程式
    
    ```bash
    mvn clean package
    ```
    
    此時會產生一個 `g:\app1\target\app1-0.0.1-SNAPSHOT.war` 封裝檔
    
5.  部署應用程式
    
    直接將 `app1-0.0.1-SNAPSHOT.war` 複製到 `G:\wildfly-26.1.2.Final\standalone\deployments` 資料夾，就可以全自動部署完成！
    
6.  測試網站執行
    
    [http://127.0.0.1:8080/](http://127.0.0.1:8080/)
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/e13c0b452b4991970ace-189983680-90627213-2abd-426b-bcad-3e3c5f8c3522.png)
    

### 設定 Maven 的 `install` lifecycle phase 自動部署應用程式到 WildFly 應用程式伺服器

1.  先設定好 WildFly 自動部署所需的屬性(Properties)
    
    ```xml
    <properties>
      <java.version>17</java.version>
      <maven.test.skip>true</maven.test.skip>
    
      <deploy.wildfly.host>127.0.0.1</deploy.wildfly.host>
      <deploy.wildfly.port>9990</deploy.wildfly.port>
      <deploy.wildfly.username>wildfly</deploy.wildfly.username>
      <deploy.wildfly.password>wi1df1y!</deploy.wildfly.password>
    
    </properties>
    ```
    
2.  加入 `wildfly-maven-plugin` plugin 的 `<executions>` 與 `<configuration>` 設定
    
    其中 `<executions>` 主要用來將 `install` 這個 lifecycle phase 與 `wildfly:deploy` goal 綁定(bound)，讓日後在執行 `mvn install` 的時候自動部署應用程式到 WildFly AS 去！
    
    ```xml
    <plugin>
      <groupId>org.wildfly.plugins</groupId>
      <artifactId>wildfly-maven-plugin</artifactId>
      <version>3.0.2.Final</version>
    
      <executions>
        <execution>
          <phase>install</phase>
          <goals>
            <goal>deploy</goal>
          </goals>
        </execution>
      </executions>
    
      <configuration>
        <filename>${project.build.finalName}.war</filename>
        <hostname>${deploy.wildfly.host}</hostname>
        <port>${deploy.wildfly.port}</port>
        <username>${deploy.wildfly.username}</username>
        <password>${deploy.wildfly.password}</password>
      </configuration>
    
    </plugin>
    ```
    
3.  透過 Maven 自動部署應用程式到 WildFly AS
    
    ```bash
    mvn clean install
    ```
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/a972c3404092480ec587-189983815-577c3b51-7f47-40ba-9ba9-af8e1fa29ba9.png)
    
4.  測試網站執行
    
    [http://127.0.0.1:8080/](http://127.0.0.1:8080/)
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/e13c0b452b4991970ace-189983680-90627213-2abd-426b-bcad-3e3c5f8c3522.png)
    

### 相關連結

-   本文範例程式: [https://github.com/doggy8088/spring-boot-wildfly-26/commits/master](https://github.com/doggy8088/spring-boot-wildfly-26/commits/master)
-   [WildFly](https://www.wildfly.org/)
-   [WildFly Maven Plugin (wildfly-maven-plugin)](https://docs.jboss.org/wildfly/plugins/maven/latest/)
-   [WildFly - Wikipedia](https://en.wikipedia.org/wiki/WildFly)
-   [Spring Boot Hello World on WildFly - Mastertheboss](http://www.mastertheboss.com/jboss-frameworks/spring/spring-boot-hello-world-on-wildfly/)
-   [Deploy Spring Boot on WildFly application server - DEV Community](https://dev.to/jakmar17/deploy-spring-boot-on-wildfly-application-server-2029)
-   [How to Change the Default Port in Spring Boot | Baeldung](https://www.baeldung.com/spring-boot-change-port)
-   [Maven Dependency Scopes | Baeldung](https://www.baeldung.com/maven-dependency-scopes)
