使用容器進行 Java 開發

先決條件

按照步驟操作,將您的應用程式容器化,如 容器化您的應用程式 中所述。

概述

在本節中,您將逐步瞭解如何為上一節中容器化的應用程式設定本地開發環境。這包括:

  • 新增本地資料庫並持久化資料
  • 建立用於連線偵錯程式的開發容器
  • 配置 Compose 以在您編輯和儲存程式碼時自動更新正在執行的 Compose 服務

新增本地資料庫並持久化資料

您可以使用容器來設定本地服務,例如資料庫。在本節中,您將更新 docker-compose.yaml 檔案以定義資料庫服務和用於持久化資料的卷。此外,此特定應用程式使用系統屬性來定義資料庫型別,因此您需要更新 Dockerfile 以在啟動應用程式時傳入系統屬性。

在克隆的儲存庫目錄中,在 IDE 或文字編輯器中開啟 docker-compose.yaml 檔案。您的 Compose 檔案包含一個示例資料庫服務,但它需要進行一些更改才能適應您的獨特應用程式。

docker-compose.yaml 檔案中,您需要執行以下操作:

  • 取消註釋所有資料庫指令。您現在將使用資料庫服務而不是本地儲存來儲存資料。
  • 刪除頂層 secrets 元素以及 db 服務中的元素。此示例使用環境變數作為密碼,而不是秘密。
  • db 服務中刪除 user 元素。此示例在環境變數中指定了使用者。
  • 更新資料庫環境變數。這些由 Postgres 映象定義。有關更多詳細資訊,請參閱 Postgres 官方 Docker 映象
  • 更新 db 服務的健康檢查測試並指定使用者。預設情況下,健康檢查使用 root 使用者而不是您定義的 petclinic 使用者。
  • server 服務中新增資料庫 URL 作為環境變數。這將覆蓋 spring-petclinic/src/main/resources/application-postgres.properties 中定義的預設值。

以下是更新後的 docker-compose.yaml 檔案。所有註釋都已刪除。

services:
  server:
    build:
      context: .
    ports:
      - 8080:8080
    depends_on:
      db:
        condition: service_healthy
    environment:
      - POSTGRES_URL=jdbc:postgresql://db:5432/petclinic
  db:
    image: postgres
    restart: always
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=petclinic
      - POSTGRES_USER=petclinic
      - POSTGRES_PASSWORD=petclinic
    ports:
      - 5432:5432
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "petclinic" ]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-data:

在 IDE 或文字編輯器中開啟 Dockerfile。在 ENTRYPOINT 指令中,更新指令以傳入系統屬性,如 spring-petclinic/src/resources/db/postgres/petclinic_db_setup_postgres.txt 檔案中所述。

- ENTRYPOINT [ "java", "org.springframework.boot.loader.launch.JarLauncher" ]
+ ENTRYPOINT [ "java", "-Dspring.profiles.active=postgres", "org.springframework.boot.loader.launch.JarLauncher" ]

儲存並關閉所有檔案。

現在,執行以下 docker compose up 命令以啟動您的應用程式。

$ docker compose up --build

開啟瀏覽器並檢視位於 https://:8080 的應用程式。您應該看到一個簡單的寵物診所應用程式。瀏覽應用程式。導航到 **獸醫** 並驗證應用程式是否已連線到資料庫,方法是檢視是否能夠列出獸醫。

在終端中,按 ctrl+c 停止應用程式。

用於開發的 Dockerfile

您現在擁有的 Dockerfile 非常適合小型、安全的生產映象,其中只包含執行應用程式所需的元件。在開發過程中,您可能希望使用具有不同環境的不同映象。

例如,在開發映象中,您可能希望設定映象以啟動應用程式,以便您可以將偵錯程式連線到正在執行的 Java 程序。

與其管理多個 Dockerfile,您可以新增一個新的階段。然後,您的 Dockerfile 可以生成一個適合生產環境的最終映象,以及一個開發映象。

將您的 Dockerfile 的內容替換為以下內容。

# syntax=docker/dockerfile:1

FROM eclipse-temurin:17-jdk-jammy as deps
WORKDIR /build
COPY --chmod=0755 mvnw mvnw
COPY .mvn/ .mvn/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
    --mount=type=cache,target=/root/.m2 ./mvnw dependency:go-offline -DskipTests

FROM deps as package
WORKDIR /build
COPY ./src src/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw package -DskipTests && \
    mv target/$(./mvnw help:evaluate -Dexpression=project.artifactId -q -DforceStdout)-$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout).jar target/app.jar

FROM package as extract
WORKDIR /build
RUN java -Djarmode=layertools -jar target/app.jar extract --destination target/extracted

FROM extract as development
WORKDIR /build
RUN cp -r /build/target/extracted/dependencies/. ./
RUN cp -r /build/target/extracted/spring-boot-loader/. ./
RUN cp -r /build/target/extracted/snapshot-dependencies/. ./
RUN cp -r /build/target/extracted/application/. ./
ENV JAVA_TOOL_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000
CMD [ "java", "-Dspring.profiles.active=postgres", "org.springframework.boot.loader.launch.JarLauncher" ]

FROM eclipse-temurin:17-jre-jammy AS final
ARG UID=10001
RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "/nonexistent" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    appuser
USER appuser
COPY --from=extract build/target/extracted/dependencies/ ./
COPY --from=extract build/target/extracted/spring-boot-loader/ ./
COPY --from=extract build/target/extracted/snapshot-dependencies/ ./
COPY --from=extract build/target/extracted/application/ ./
EXPOSE 8080
ENTRYPOINT [ "java", "-Dspring.profiles.active=postgres", "org.springframework.boot.loader.launch.JarLauncher" ]

儲存並關閉 Dockerfile

Dockerfile 中,您添加了一個新的階段,名為 development,它基於 extract 階段。在此階段,您將提取的檔案複製到一個公共目錄,然後執行一個命令以啟動應用程式。在命令中,您公開埠 8000 並宣告 JVM 的除錯配置,以便您可以連線偵錯程式。

使用 Compose 在本地進行開發

當前 Compose 檔案不會啟動您的開發容器。為此,您必須更新 Compose 檔案以定位開發階段。此外,更新伺服器服務的埠對映以提供偵錯程式訪問許可權。

開啟 docker-compose.yaml 並將以下指令新增到檔案中。

services:
  server:
    build:
      context: .
      target: development
    ports:
      - 8080:8080
      - 8000:8000
    depends_on:
      db:
        condition: service_healthy
    environment:
      - POSTGRES_URL=jdbc:postgresql://db:5432/petclinic
  db:
    image: postgres
    restart: always
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=petclinic
      - POSTGRES_USER=petclinic
      - POSTGRES_PASSWORD=petclinic
    ports:
      - 5432:5432
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "petclinic" ]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-data:

現在,啟動您的應用程式並確認它正在執行。

$ docker compose up --build

最後,測試您的 API 端點。執行以下 curl 命令:

$ curl  --request GET \
  --url https://:8080/vets \
  --header 'content-type: application/json'

您應該收到以下響應:

{"vetList":[{"id":1,"firstName":"James","lastName":"Carter","specialties":[],"nrOfSpecialties":0,"new":false},{"id":2,"firstName":"Helen","lastName":"Leary","specialties":[{"id":1,"name":"radiology","new":false}],"nrOfSpecialties":1,"new":false},{"id":3,"firstName":"Linda","lastName":"Douglas","specialties":[{"id":3,"name":"dentistry","new":false},{"id":2,"name":"surgery","new":false}],"nrOfSpecialties":2,"new":false},{"id":4,"firstName":"Rafael","lastName":"Ortega","specialties":[{"id":2,"name":"surgery","new":false}],"nrOfSpecialties":1,"new":false},{"id":5,"firstName":"Henry","lastName":"Stevens","specialties":[{"id":1,"name":"radiology","new":false}],"nrOfSpecialties":1,"new":false},{"id":6,"firstName":"Sharon","lastName":"Jenkins","specialties":[],"nrOfSpecialties":0,"new":false}]}

連線偵錯程式

您將使用 IntelliJ IDEA 自帶的偵錯程式。您可以使用此 IDE 的社群版。在 IntelliJ IDEA 中開啟您的專案,轉到 **執行** 選單,然後選擇 **編輯配置**。新增一個新的遠端 JVM 除錯配置,類似於以下配置:

Java Connect a Debugger

設定斷點。

開啟 src/main/java/org/springframework/samples/petclinic/vet/VetController.java 並新增一個斷點,位於 showResourcesVetList 函式內。

要啟動除錯會話,請選擇 **執行** 選單,然後選擇 **除錯 您的配置名稱**。

Debug menu

您現在應該在 Compose 應用程式的日誌中看到連線。

Compose log file

您現在可以呼叫伺服器端點。

$ curl --request GET --url https://:8080/vets

您應該看到程式碼在標記的行上斷開,現在您可以像往常一樣使用偵錯程式。您還可以檢查和觀察變數、設定條件斷點、檢視堆疊跟蹤並執行許多其他操作。

Debugger code breakpoint

在終端中,按 ctrl+c 停止應用程式。

自動更新服務

使用 Compose Watch 自動更新正在執行的 Compose 服務,當您編輯和儲存程式碼時。有關 Compose Watch 的更多詳細資訊,請參閱 使用 Compose Watch

在 IDE 或文字編輯器中開啟 docker-compose.yaml 檔案,然後新增 Compose Watch 指令。以下是更新後的 docker-compose.yaml 檔案。

services:
  server:
    build:
      context: .
      target: development
    ports:
      - 8080:8080
      - 8000:8000
    depends_on:
      db:
        condition: service_healthy
    environment:
      - POSTGRES_URL=jdbc:postgresql://db:5432/petclinic
    develop:
      watch:
        - action: rebuild
          path: .
  db:
    image: postgres
    restart: always
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=petclinic
      - POSTGRES_USER=petclinic
      - POSTGRES_PASSWORD=petclinic
    ports:
      - 5432:5432
    healthcheck:
      test: [ "CMD", "pg_isready", "-U", "petclinic" ]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-data:

執行以下命令以使用 Compose Watch 執行您的應用程式。

$ docker compose watch

開啟 Web 瀏覽器並檢視位於 https://:8080 的應用程式。您應該看到 Spring Pet Clinic 主頁。

對本地機器上的應用程式原始檔的任何更改現在都會自動反映到正在執行的容器中。

在 IDE 或文字編輯器中開啟 spring-petclinic/src/main/resources/templates/fragments/layout.html,然後透過新增一個感嘆號更新 主頁 導航字串。

-   <li th:replace="~{::menuItem ('/','home','home page','home','Home')}">
+   <li th:replace="~{::menuItem ('/','home','home page','home','Home!')}">

儲存對 layout.html 的更改,然後您可以在容器自動重建時繼續進行開發。

在容器重建並執行後,重新整理 https://:8080,然後驗證 **主頁!** 是否已顯示在選單中。

在終端中,按 ctrl+c 停止 Compose Watch。

總結

在本節中,您瞭解瞭如何在本地執行資料庫並持久化資料。您還建立了一個包含 JDK 並允許您連線偵錯程式的開發映象。最後,您設定了 Compose 檔案以公開除錯埠,並配置了 Compose Watch 以即時重新載入您的更改。

相關資訊

下一步

在下一節中,您將瞭解如何在 Docker 中執行單元測試。