주:

OKE의 Spring Boot를 사용하여 Oracle GraalVM 기반 Java 애플리케이션을 생성하여 ATP에 SOAP 메시지를 저장하고 OCI Queue로 전송

소개

대부분의 고객은 기존 SOAP(Simple Object Access Protocol) 메시징을 사용하여 애플리케이션 간 통신을 활성화합니다. 트랜잭션 데이터를 저장하고, 서비스 분리(decoupling)를 보장하고, 수신 요청 로드 밸런싱을 달성하고, 이러한 메시지의 비동기 통신을 활성화해야 하는 경우가 많습니다.

이 사용지침서에서는 Oracle Autonomous Transaction Processing(ATP) 및 OCI Queue와 같은 다양한 OCI(Oracle Cloud Infrastructure) 서비스와의 트랜잭션 통합자로 사용될 Oracle Cloud Infrastructure Kubernetes Engine(OKE) 인프라에 배포된 Spring Boot를 사용하여 Oracle GraalVM 기반 Java 애플리케이션을 구축하는 방법을 알아봅니다. 이 설정을 통해 시스템은 직접 연결 없이 상호 작용할 수 있으므로 처리 속도가 다른 응용 프로그램 간의 통신을 용이하게 할 수 있습니다. 또한 정보가 데이터베이스에 저장되면 이를 참조하거나 분석할 수 있습니다.

다음 기술을 사용합니다.

Oracle Cloud Infrastructure Services(OCI): OCI는 150여 개의 클라우드 서비스를 제공하는 안전한 고성능 클라우드 플랫폼입니다. 확장성, 보안 및 성능을 위해 설계되었습니다.

Oracle 기술:

기타 기술:

OCI 상위 아키텍처:

OCI 아키텍처

사용 사례 구조

참고:

목표

필요 조건

작업 1: OKE 클러스터 프로비전 및 구성

이 작업에서는 Kubernetes 플랫폼을 프로비저닝합니다. 이 플랫폼에서는 애플리케이션이 ATP에 저장할 모든 SOAP 높은 트랜잭션 메시지를 지원하고 각각을 OCI 대기열에 실시간으로 전송할 수 있습니다.

  1. OCI 콘솔에 로그인하여 개발자 서비스, OKE(Kubernetes 클러스터)로 이동한 다음 원하는 구획을 선택합니다.

    OKE 클러스터를 만드는 방법에는 다음 두 가지가 있습니다.

    • 빠른 생성.
    • 사용자정의 생성.
  2. 빠른 생성을 선택합니다. 이 방법은 다음과 같이 OKE의 작업에 필요한 모든 요소를 더 쉽고 빠르게 자동으로 배치합니다.

    • VCN(가상 클라우드 네트워크).
    • 인터넷 게이트웨이.
    • NAT(Network Address Translation) 게이트웨이입니다.
    • 서비스 게이트웨이.
    • Kubernetes 클러스터.
    • Kubernetes 워커 노드 및 노드 풀.

    주: 이미 고객에게 서비스, 네트워크, 기반구조가 있는 엔터프라이즈 환경의 경우 OKE 배치를 준수하도록 사용자 정의하고 클라이언트 구조, 리소스 및 모범 사례에 맞게 조정하는 것이 중요합니다.

    빠른 생성

  3. 클러스터 생성을 누르고 다음 정보를 입력합니다.

    • 이름: OKE 클러스터의 이름을 입력합니다.
    • 구획: 이 프로젝트에 대해 생성된 컴파트먼트를 선택합니다.
    • Kubernetes 버전: 사용 가능한 최신 Kubernetes 버전을 선택합니다.
    • Kubernetes API 끝점: 이 자습서에서는 공용 끝점을 선택하지만, 전용 끝점을 선택할 수도 있습니다.
    • 노드 유형: 관리됨 노드를 선택합니다.
    • Kubernetes 워커 노드: 비공개 워커를 선택합니다.
    • 구성 및 이미지: VM.Standard.E5를 선택합니다. 유연하게 OCPU 수(2) 및 메모리(16GB)를 사용자 정의하고 기본 Oracle Linux 8 이미지를 보존합니다.
    • 노드 수: OKE 노드 풀과 함께 배치할 워커 노드 2개를 입력합니다.

    OKE 클러스터 생성

    OKE 클러스터가 작동 중인지 검토합니다.

    OKE 실행 중

작업 2: OCI 컨테이너 레지스트리 클래식 프로비전, 구성 및 액세스

저장소에서 프로젝트 이미지를 관리해야 합니다. 이를 위해 OCI Container Registry Classic을 프로비저닝합니다. 이미지가 OCI Container Registry Classic에 저장되면 OKE에 배포할 수 있습니다.

  1. OCI 콘솔로 이동하여 개발자 서비스, 컨테이너 및 아티팩트, 컨테이너 레지스트리로 이동하고 저장소 생성을 누릅니다.

  2. 다음 정보를 입력하고 Create(만들기)를 누릅니다.

    • 컴파트먼트에 생성: 이 프로젝트에 대해 생성된 컴파트먼트를 선택합니다.
    • 액세스: 공용을 선택합니다.
    • 저장소 이름: springboot/tutorialapp을 입력합니다.

    저장소 생성

  3. 저장소가 생성되면 Oracle 관리 호스트에서 다음 명령을 사용하여 저장소에 액세스합니다.

    docker login -u 'tenancy_namespace/domain/username' regionID.ocir.io
    
    Password: xxxxxx
    

    Oracle 레지스트리 인증

    OK

작업 3: ATP(Oracle Autonomous Transaction Processing) 서버리스 데이터베이스 프로비전 및 구성

ATP 데이터베이스에서는 트랜잭션당 수신된 각 SOAP 메시지의 데이터를 저장하며, 대략 각각 밀리초 순서로 병렬 및 순차적 삽입에 참석합니다.

  1. OCI 콘솔로 이동하여 Oracle Database로 이동하고 Autonomous Transaction Processing을 누릅니다.

  2. Autonomous Database 생성을 누르고 다음 정보를 입력합니다.

    • 구획 선택: 이 프로젝트에 대해 생성된 구획을 선택합니다.
    • 표시명: 표시명을 입력합니다.
    • 데이터베이스 이름 표시: 데이터베이스 이름을 입력합니다.
    • 작업 로드 유형 선택: 트랜잭션 처리를 선택합니다.
    • 배포 유형 선택: 서버리스를 선택합니다.
    • 데이터베이스 구성:
      • 개발자: 선택을 해제합니다.
      • 데이터베이스 버전 선택: 23ai를 선택합니다.
      • ECPU 개수: 2를 입력합니다.
      • 컴퓨트 자동 스케일링: 선택합니다.
      • 스토리지: 1024GB를 입력합니다.
    • 자동 백업 보존 기간(일): 기본 옵션을 60일로 둡니다.
    • 관리자 인증서 생성:
      • 사용자 이름: 기본적으로 ADMIN이며 편집할 수 없습니다.
      • 비밀번호: 선호 비밀번호를 입력합니다.
      • 비밀번호 확인: 비밀번호를 다시 입력합니다.
    • 네트워크 액세스 선택: 프라이빗 끝점 액세스만을 선택한 다음 이 프로젝트에 대해 생성된 VCN 및 서브넷을 선택합니다. 이 설정은 지정된 VCN(전용 네트워크)으로만 연결을 제한합니다. 그러나 회사의 필요에 따라 다른 옵션을 선택할 수 있습니다.

    Oracle ATP 데이터베이스 생성

    Oracle ATP 데이터베이스 생성

    Oracle ATP 데이터베이스 생성

    ATP 데이터베이스가 실행 중인지 검토합니다.

    ATP 실행중

작업 4: Oracle Autonomous Transaction Processing(ATP)에서 프로젝트 테이블 연결 및 생성

이제 태스크 3에서 생성된 ATP 데이터베이스에서 프로젝트 테이블을 구성, 연결 및 생성해야 합니다.

  1. OCI 콘솔로 이동하여 Oracle Database, Autonomous Transaction Processing으로 이동하고 Database Connection을 누릅니다. TLS 인증, TLS를 선택하고 전자 지갑 다운로드를 누릅니다.

    데이터베이스 접속

  2. 전자 지갑 .zip 파일의 압축을 풀고 tnsnames.ora에서 데이터 소스 URL을 가져와서 이 데이터베이스에 접속할 수 있습니다. 이 데이터 소스 URL을 저장합니다.

    예:

    tutorialoracleatp_medium = (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=xxxxxxxx.adb.sa-saopaulo-1.oraclecloud.com))(connect_data=(service_name=xxxxxxxxxxxxxxx_tutorialoracleatp_medium.adb.oraclecloud.com))(security=(ssl_server_dn_match=no)))
    
  3. 이제 데이터베이스에 액세스해야 합니다. ATP가 프로비저닝되면 ORDS(Oracle REST Data Services) 액세스가 사용으로 설정되었습니다. 자세한 내용은 Oracle REST Data Services를 참조하십시오.

    Autonomous Database 세부정보 페이지로 이동하여 데이터베이스 작업을 누릅니다. 동일한 VCN(가상 클라우드 네트워크)에서 실행되는 컴퓨트 인스턴스에서만 액세스할 수 있습니다.

    데이터베이스 작업

  4. 브라우저에 URL을 붙여넣고 이전에 ATP 데이터베이스에 입력한 사용자 및 비밀번호를 사용하여 ORDS에 액세스한 다음 Oracle SQL Developer Web 모듈에 액세스합니다.

    ORDS

  5. 다음 질의를 사용하여 수신할 SOAP 메시지와 관련된 USERS, CARSHOUSES 테이블을 생성합니다.

    CREATE TABLE USERS (
    username varchar(50) NOT NULL,
    userlastname varchar(50) NOT NULL,
    id int NOT NULL,
    email varchar(50) NOT NULL,
    dateuser varchar(50) NOT NULL,
    attributeuser varchar(50) NOT NULL  
    );
    
    CREATE TABLE CARS (
    userid int NOT NULL,
    brand varchar(50) NOT NULL,
    color varchar(50) NOT NULL,
    plate varchar(50) NOT NULL  
    );
    
    CREATE TABLE HOUSES (
    userid int NOT NULL,
    floors int NOT NULL,
    locationhouse varchar(50) NOT NULL,
    rooms int NOT NULL,
    bathrooms int NOT NULL
    );
    

    데이터베이스에 생성된 테이블

작업 5: OCI 대기열 프로비전 및 구성

OCI 대기열에서는 특정 기간 동안 RESTful HTTP API를 통해 높은 트랜잭션 메시지를 저장합니다. 그런 다음 소비자는 메시지를 즉시 또는 편리하게 읽고 삭제할 수 있으므로 분리 및 데이터 손실을 방지할 수 있습니다.

  1. OCI 콘솔로 이동하여 개발자 서비스, 애플리케이션 통합으로 이동하고 대기열을 누릅니다.

  2. 대기열 생성을 누르고 다음 정보를 입력하고 대기열 생성을 누릅니다.

    • 이름: 대기열에 적합한 이름을 입력합니다.
    • 구획: 작업 컴파트먼트를 선택합니다.
    • 대기열 설정: 이 자습서에서는 기본 구성을 선택하지만, 원하는 경우 가시성 시간 초과, 최대 보존 기간, 최대 채널 소비사용 불능 문자 대기열 설정과 같은 비즈니스 요구에 따라 여러 옵션을 사용자정의할 수 있습니다.
    • 암호화 설정 구성: Oracle 관리 키를 선택합니다. 단, 고객 관리 키도 옵션입니다.

    대기열 생성

    OCI 대기열이 실행 중인지 검토합니다.

    실행 중인 OCI 대기열

작업 6: Spring Boot를 사용하여 Oracle GraalVM 기반 Java 애플리케이션을 구축하고 OKE에 배포

이제 Spring Boot에서 다음 작업을 수행하는 Oracle GraalVM 기반 Java 애플리케이션을 개발하고 배포할 예정입니다.

주: 시작하기 전에 필요 조건 - 관리 호스트필요 조건 - 개발 환경 섹션에 표시된 대로 관리 호스트 및 개발 환경을 생성해야 합니다.

관리 호스트 및 개발 환경이 구성되고 준비되면 Spring Boot 프로젝트 개발을 시작할 수 있습니다.

  1. Spring initializr로 이동하고 Spring Boot 프로젝트의 폴더 구조 및 기본 파일을 제공하는 첫번째 프로젝트를 생성하여 나중에 요구사항에 따라 수정합니다. 다음 정보를 입력하고 생성을 누릅니다. 그러면 Spring Boot 프로젝트가 자동으로 다운로드되어 개발 호스트에 저장되고 압축이 해제됩니다.

    • 프로젝트: Maven을 선택합니다.
    • 언어: Java를 선택합니다.
    • 스프링 부트: 3.3.6을 선택합니다.
    • 프로젝트 메타데이터:
      • 그룹: com.tutorial_springboot를 입력합니다.
      • 아티팩트: 자습서를 입력합니다.
      • 이름: 자습서를 입력합니다.
      • 설명: Spring Boot Application(SOAP 읽기, JSON으로 변환, ATP 삽입 및 OCI 대기열에 넣기)을 입력합니다.
    • 패키징: Jar를 선택합니다.
    • Java: 17을 선택합니다.
    • 종속성: Oracle 드라이버, 웹 서비스 봄웹 봄을 선택합니다.

    주: 필요에 따라 프로젝트에 일부 종속성을 추가하고 나중에 pom.xml 파일에 직접 추가할 수 있습니다.

    Springboot 프로젝트

  2. 이제 스프링 부트 구조 프로젝트가 있습니다.

    구조 스프링 부팅 프로젝트

    pom.xml 파일을 검토하면 작업을 시작합니다.

    원본 POM 파일

    이 자습서에서 제안된 범위에 따라 pom.xml 파일을 업데이트합니다.

    • oci sdk 버전 및 다음 종속성을 추가합니다.

      • oci-java-sdk-common.
      • oci-java-sdk-queue.
      • oci-java-sdk-addons-oke-workload-identity.
      • oci-java-sdk-common-httpclient-jersey3.

      애플리케이션은 OCI로 인증하고 OCI Queue와 같은 OCI 서비스를 연결 및 관리해야 합니다.

    • 이미 pom.xml 파일은 spring-boot-starter-web-services 종속성을 가지며 wsdl4j 종속성을 추가해야 합니다. 주요 목적은 SOAP 메시지에서 수신된 데이터를 가져와서 Java 객체에 배치하고, XML 페이로드를 조작하는 스프링 웹 서비스를 생성하고, 계약 우선 SOAP 서비스 개발을 용이하게 하는 것입니다. 또한 포트, URI를 구성하고 XSD(XML Schema Definition) 파일에서 로드된 XML 스키마를 설정할 수 있습니다.

    • JSON 종속성을 추가합니다. 이 라이브러리는 SOAP 메시지에서 추출된 데이터로 JSON 형식을 생성하는 데 사용됩니다.

    • Build 섹션에 spring-boot-maven-plugin 플러그인을 추가합니다. 이 플러그인을 사용하면 jar 실행 가능 Spring Boot 프로젝트 파일을 생성할 수 있습니다.

    • Build 섹션에 jaxb2-maven-plugin 플러그인을 추가합니다. 이 플러그인은 JAXB(Java API for XML binding)를 사용하여 XML 스키마에서 Java 클래스를 생성하며, 이러한 방식으로 SOAP 메시지의 데이터를 우리가 생성한 Java 클래스 객체로 전달할 수 있습니다.

      이 플러그인 섹션에서는 XSD 파일이 Spring Boot 프로젝트에 포함된 경로를 나타내는 구성을 배치하는 것이 중요합니다.

      <configuration>
         <sources>
         <source>${project.basedir}/src/main/resources/messages.xsd<source>
         </sources>
      </configuration>
      
    • 종속성 섹션에 jasypt-spring-boot-starter 종속성을 추가하고 application.properties 파일에서 중요한 매개변수를 암호화하여 애플리케이션 내에서 안전하게 사용할 수 있도록 하는 jasypt-maven-plugin 플러그인을 빌드 섹션에 추가합니다.

    pom.xml 파일에 추가된 다음 종속성을 검토합니다.

    POM 파일 수정됨

    POM 파일 수정됨

  3. 라이브러리를 다운로드하고 다음 명령을 실행합니다.

    1. 개발 환경에서 다음 명령을 실행하여 프로젝트에 액세스합니다.

      cd tutorial
      

      Spring 부트 프로젝트 폴더

    2. 프로젝트를 정리하고 이전 빌드에서 생성한 모든 파일을 제거합니다.

      mvn clean
      

      Maven 클린

    3. 로컬 maven 저장소에서 아티팩트를 비우기(삭제 및 선택적으로 재분석)합니다.

      mvn dependency:purge-local-repository
      

    Maven 비우기 종속성

  4. 이미 프로젝트에 종속성과 pom.xml 파일이 구성되어 있습니다. SOAP XML 파일은 클라이언트측의 요청을 나타내므로 SOAP XML 파일과 Spring Boot 프로젝트측의 요청을 해석하는 XSD 파일을 검사합니다.

    1. 이 SOAP XML 파일에는 다음 이미지와 같이 요청당 전송할 두 개의 서로 다른 클라이언트에서 가져온 개인 정보 및 기타 속성과 함께 두 개의 메시지가 있습니다.

      SOAP 파일

    2. 이제 Spring Boot 프로젝트 측에서 Spring 웹 서비스가 자동으로 WSDL로 익스포트하는 웹 서비스 도메인을 정의하기 위해 XML 스키마가 필요합니다. 다음 이미지는 이 자습서에 대해 정의된 messages.xsd 파일을 보여줍니다.

      messages.xsd:

      XSD 파일

    3. Spring Boot 프로젝트의 resources 폴더에 messages.xsd 파일을 저장합니다.

      폴더에 XSD 파일

  5. jar 파일에 프로젝트 파일을 빌드하고 설치합니다. 다음 명령을 실행하고 Spring Boot 프로젝트 폴더에 있는지 확인합니다.

    mvn install
    

    주: maven 설치 명령이 실행되면 대상 폴더가 자동으로 생성되고, 동일한 방식으로 이전에 생성된 XSD 파일 및 프로젝트의 실행 파일 .jar 파일에 따라 Java 클래스가 생성됩니다.

    대상 폴더

  6. 이제 Spring Boot 프로젝트에 필요한 Java 클래스를 추가할 수 있습니다.

    WebServiceConfig.java Class: 이 Java 클래스는 SOAP 웹 서비스를 생성하기 위해 개발되었습니다.

    • SOAP 요청을 처리하도록 서블릿을 설정합니다.
    • XML 스키마를 기반으로 WSDL 정의를 생성합니다.
    • SOAP 웹 서비스의 액세스 끝점을 정의합니다.
    • classpath의 messages.xsd 스키마 파일을 사용합니다.
    //Imports
    import org.springframework.boot.web.servlet.ServletRegistrationBean; //import the ServletRegistrationBean class
    import org.springframework.context.ApplicationContext; //import the ApplicationContext class
    import org.springframework.context.annotation.Bean; //import the Bean class
    import org.springframework.context.annotation.Configuration; //import the Configuration class
    import org.springframework.core.io.ClassPathResource; //import the ClassPathResource class
    import org.springframework.ws.config.annotation.EnableWs; //import the EnableWs class
    import org.springframework.ws.config.annotation.WsConfigurerAdapter; //import the WsConfigurerAdapter class
    import org.springframework.ws.transport.http.MessageDispatcherServlet; //import the MessageDispatcherServlet class
    import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; //import the DefaultWsdl11Definition class
    import org.springframework.xml.xsd.SimpleXsdSchema; //import the SimpleXsdSchema class
    import org.springframework.xml.xsd.XsdSchema; //import the XsdSchema class
    
    //Configuration class for the Web Service configuration
    @EnableWs //Enable the Web Service
    @Configuration //Define the class as a Configuration class 
    
    public class WebServiceConfig extends WsConfigurerAdapter {
    
       //Create a ServletRegistrationBean object to register the MessageDispatcherServlet object with the application context
       @Bean
       public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
          MessageDispatcherServlet servlet = new MessageDispatcherServlet(); //Create a MessageDispatcherServlet object
          servlet.setApplicationContext(applicationContext); //Set the application context for the MessageDispatcherServlet object
          servlet.setTransformWsdlLocations(true); //Set the transformWsdlLocations property to true
          return new ServletRegistrationBean<>(servlet, "/ws/*"); //Return a new ServletRegistrationBean object with the MessageDispatcherServlet object and the URL pattern
       }
    
       //Create a DefaultWsdl11Definition object to define the WSDL
       @Bean(name = "messages")
       public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema messagesSchema) {
          DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); //Create a DefaultWsdl11Definition object
          wsdl11Definition.setPortTypeName("MessagesPort"); //Set the port type name
          wsdl11Definition.setLocationUri("/ws"); //Set the location URI
          wsdl11Definition.setTargetNamespace("http://tutorial_example.com/ns0"); //Set the target namespace
          wsdl11Definition.setSchema(messagesSchema); //Set the schema
          return wsdl11Definition; //Return the DefaultWsdl11Definition object
       }
    
       //Create a XsdSchema object to define the schema
       @Bean
       public XsdSchema messagesSchema() {
          return new SimpleXsdSchema(new ClassPathResource("messages.xsd")); //Return a new SimpleXsdSchema object with the messages.xsd file
       }
    }
    

    주: 웹 서비스를 테스트하려면 다음과 같이 동일한 로컬 개발 환경 데스크톱에서 Spring Boot 프로젝트를 실행하고 curl를 사용하여 HTTP 요청을 전송할 수 있습니다.

    mvn spring-boot:run
    

    Spring 부트 프로젝트 실행

    Spring 부트 프로젝트 실행

    프로젝트가 실행 중이고 웹 서비스가 작동되면 다음과 같이 curl를 사용하여 로컬 SOAP HTTP 요청을 실행합니다.

    curl --location 'http://localhost:8080/ws/'
    

    그리고 당신은 우리의 봄 부팅 프로젝트에 노출 된 웹 서비스에서 응답을 얻을 것이다.

    SOAP 웹 서비스

  7. model이라는 폴더를 생성합니다. 이 폴더에는 다음 Java 클래스가 추가됩니다.

    모델 폴더

    주: 이러한 Java 클래스 Car, HouseUser는 HTTP SOAP 요청에서 추출된 각 SOAP 메시지의 데이터를 기반으로 정보를 검색합니다.

    • Car.java class: 이 Java 클래스는 각 사용자에 링크된 속성을 가진 Car 객체를 나타냅니다.

      ```
      //Imports
      import org.springframework.stereotype.Component; // For component scanning
      import org.springframework.context.annotation.Scope; // For defining bean scope
      
      @Component // Marks a class as a Spring-managed component
      @Scope("prototype") //A new instance is created every time the bean is requested
      
      public class Car {
      
         //Attributes
      
         private String brand; 
         private String color; 
         private String plate; 
      
         //"getter" and "setter" methods to get and set the information in each object
      
         public String getBrand(){
         return brand;
         }
      
         public void setBrand(String brand){
         this.brand = brand;
         }
      
         public String getColor(){
         return color;
         }
      
         public void setColor(String color){
         this.color = color;
         }
      
         public String getPlate(){
         return plate;
         }
      
         public void setPlate(String plate){
         this.plate = plate;
         }
      
      }
      ```
      
      • House.java class: 이 Java 클래스는 각 유저에 연결된 속성을 가진 House 객체를 나타냅니다.

        //Imports
        import org.springframework.stereotype.Component; // For component scanning
        import org.springframework.context.annotation.Scope; // For defining bean scope
        
        @Component // Marks a class as a Spring-managed component
        @Scope("prototype") //A new instance is created every time the bean is requested
        
        public class House {
        
           //Attributes
        
           private int floors;
           private String location;
           private int rooms;
           private int bathrooms;
        
        
           //"getter" and "setter" methods to get and set the information in each object
        
           public int getFloors(){
              return floors;
           }
        
           public void setFloors(int floors){
              this.floors = floors;
           }
        
           public String getLocation(){
              return location;
           }
        
           public void setLocation(String location){
              this.location = location;
           }
        
           public int getRooms(){
              return rooms;
           }
        
           public void setRooms(int rooms){
              this.rooms = rooms;
           }
        
           public int getBathRooms(){
              return bathrooms;
           }
        
           public void setBathRooms(int bathrooms){
              this.bathrooms = bathrooms;
           }
        
        }
        
      • User.java class: 이 Java 클래스는 CarHouse 객체를 포함하는 해당 속성을 가진 User 객체를 나타냅니다.

        //Imports
        import org.springframework.stereotype.Component; // For component scanning
        import org.springframework.context.annotation.Scope; // For defining bean scope
        
        @Component // Marks a class as a Spring-managed component
        @Scope("prototype") //A new instance is created every time the bean is requested
        
        
        public class User {
        
           //Attributes
        
           private String username; 
           private String userlastname;
           private int id;
           private String email;
           private String date;
           private String attribute;
           private Car car;
           private House house;
        
        
           //"getter" and "setter" methods to get and set the information in each object
        
           public String getUserName(){
           return username;
           }
        
           public void setUserName(String username){
           this.username = username;
           }
        
           public String getUserLastName(){
           return userlastname;
           }
        
           public void setUserLastName(String userlastname){
           this.userlastname = userlastname;
           }    
        
           public int getID(){
           return id;
           }
        
           public void setID(int id){
           this.id = id;
           }        
        
           public String getEmail(){
           return email;
           }
        
           public void setEmail(String email){
           this.email = email;
           }
        
           public String getDate(){
           return date;
           }
        
           public void setDate(String date){
           this.date = date;
           }
        
           public String getAttribute(){
           return attribute;
           }
        
           public void setAttribute(String attribute){
           this.attribute = attribute;
           }
        
           public Car getCar(){
           return car;
           }
        
           public void setCar(Car car){
           this.car = car;
           }
        
           public House getHouse(){
           return house;
           }
        
           public void setHouse(House house){
           this.house = house;
           }
        }
        
  8. 이제 획득한 데이터를 OCI ATP 데이터베이스에 저장하기 위해 Spring Boot 프로젝트에서 필요한 매개변수를 구성합니다. resources 폴더에서 애플리케이션에 필요한 매개변수를 추가하는 데 사용되는 application.properties 파일을 찾아야 합니다. 응용 프로그램이 시작되면 자동으로 생성되고 Spring Boot에 의해 로드됩니다.

    참고: 암호 또는 관련 데이터와 같은 중요한 정보를 해커가 추출하거나 볼 수 없도록 암호화 및 보안 방법을 관리하는 것이 중요합니다. 이 자습서에서는 pom.xml 파일에 구성된 jasypt 라이브러리를 사용합니다. 자세한 내용은 Jasypt를 사용하여 Spring Boot 프로젝트에서 암호를 암호화하는 방법을 참조하십시오. 또한 Spring Boot의 Java 클래스에서는 이 라이브러리와 관련된 주석 및 소스 코드를 추가하여 application.properties 매개변수를 해독할 수 있는 위치에 대해 설명합니다.

    다음 이미지와 같이 ATP 데이터베이스에 필요한 적절한 매개변수를 application.properties 파일에 추가합니다.

    애플리케이션 속성 파일

    Spring Boot Java 클래스를 생성하여 데이터베이스에 각 메시지를 저장합니다. 이 클래스는 다음 이미지와 같이 database 폴더에 저장됩니다.

    Database Folder

    • SoapObjectRepository.java: 이 Spring Boot Java 클래스는 JDBC 드라이버를 사용하여 ATP의 각 메시지를 실시간으로 트랜잭션 형식으로 삽입할 수 있습니다.

      //Java Classes USER, CAR, HOUSE Imports
      import com.oracle_springboot_tutorial.tutorial.model.*;
      
      //Spring Boot Imports
      import org.springframework.stereotype.Repository;
      import org.springframework.jdbc.core.JdbcTemplate;
      import org.springframework.beans.factory.annotation.Autowired;
      
      //Repository Class to save SOAP Messages in the Database
      @Repository
      public class SoapObjectRepository {
         private JdbcTemplate template;
         private User user;
      
         //Getters and Setters for JdbcTemplate template object
         public JdbcTemplate getTemplate(){
            return template;
         }
      
         //Autowired annotation to inject JdbcTemplate object into the template object
         @Autowired
         public void setTemplate(JdbcTemplate template){
            this.template = template;
         }
      
         //Method to save User SOAP Message in the Database
         public void saveUserSOAPMessage(User user){
            this.user = user;
            String sql = "INSERT INTO USERS (username, userlastname, id, email, dateuser, attributeuser) VALUES(?, ?, ?, ?, ?, ?)";
            template.update(sql, user.getUserName(), user.getUserLastName(), user.getID(), user.getEmail(), user.getDate(), user.getAttribute());
         }
      
         //Method to save Car SOAP Message in the Database
         public void saveCarSOAPMessage(Car car){
            String sql = "INSERT INTO CARS (userid, brand, color, plate) VALUES(?, ?, ?, ?)";
            template.update(sql, user.getID(), car.getBrand(), car.getColor(), car.getPlate());
         }
      
         //Method to save House SOAP Message in the Database
         public void saveHouseSOAPMessage(House house){
            String sql = "INSERT INTO HOUSES (userid, floors, locationhouse, rooms, bathrooms) VALUES(?, ?, ?, ?, ?)";
            template.update(sql, user.getID(), house.getFloors(), house.getLocation(), house.getRooms(), house.getBathRooms());
         }
      
      
      }
      

      이제 다음 이미지와 같이 먼저 json_message 폴더와 해당 Java Spring Boot 클래스를 생성하는 JSON 소프트웨어 코드를 추가합니다.

      JSON 폴더

    • JsonBuilder.java: 이 Spring Boot Java 클래스는 SOAP XML 형식에서 JSON 형식으로 변환됩니다.

      //Imports to be used for JSON
      import org.json.JSONArray;
      import org.json.JSONObject;
      
      //Imports to be used for the User class
      import com.oracle_springboot_tutorial.tutorial.model.*;
      
      
      //Imports to be used for the ArrayList class
      import java.util.ArrayList;
      
      
      public class JsonBuilder {
      
         //The buildJsonMessage method creates a JSON object from the ArrayList of User objects
         public JSONObject buildJsonMessage(ArrayList<User> usersMessageArray) {
      
            JSONObject rootJson = new JSONObject(); //Create a new JSON object called rootJson
            JSONObject messagesJson = new JSONObject(); //Create a new JSON object called messagesJson
            JSONArray messageArray = new JSONArray(); //Create a new JSON array called messageArray
      
      
            //Iterate through the ArrayList of User objects and create a JSON object for each User object in the ArrayList
            for (User user : usersMessageArray) {
                  JSONObject messageJson = new JSONObject();
                  messageJson.put("username", user.getUserName()); //Add the username of the user to the messageJson object
                  messageJson.put("userlastname", user.getUserLastName()); //Add the userlastname of the user to the messageJson object
                  messageJson.put("id", user.getID()); //Add the id of the user to the messageJson object
                  messageJson.put("email", user.getEmail()); //Add the email of the user to the messageJson object
                  messageJson.put("date", user.getDate()); //Add the date of the user to the messageJson object
                  messageJson.put("attribute", user.getAttribute()); //Add the attribute of the user to the messageJson object
      
      
                  //
                  JSONObject bodyJson = new JSONObject(); //Create a new JSON object called bodyJson
                  JSONObject envelopeJson = new JSONObject(); //Create a new JSON object called envelopeJson
      
                  //Switch statement to check the attribute of the User object
                  switch (user.getAttribute()) {
                     case "CAR":
                              Car car = user.getCar();
                              envelopeJson.put("brand", car.getBrand()); //Add the brand of the car to the envelopeJson object
                              envelopeJson.put("color", car.getColor()); //Add the color of the car to the envelopeJson object
                              envelopeJson.put("plate", car.getPlate()); //Add the plate of the car to the envelopeJson object                       
                        break;
                     case "HOUSE":
                              House house = user.getHouse();
                              envelopeJson.put("floors", house.getFloors()); //Add the floors of the house to the envelopeJson object
                              envelopeJson.put("location", house.getLocation()); //Add the location of the house to the envelopeJson object
                              envelopeJson.put("rooms", house.getRooms()); //Add the rooms of the house to the envelopeJson object
                              envelopeJson.put("bathrooms", house.getBathRooms()); //Add the bathrooms of the house to the envelopeJson object                     
                        break;
                     default:
                        System.out.println("Unknown subject: " + user.getAttribute());
                  }
      
      
                  bodyJson.put("envelope", envelopeJson); //Add the envelopeJson object to the bodyJson object
      
                  messageJson.put("body", bodyJson); //Add the bodyJson object to the messageJson object
      
               messageArray.put(messageJson); //Add the messageJson object to the messageArray array
            }
      
            messagesJson.put("message", messageArray); //Add the messageArray array to the messagesJson object
            rootJson.put("messages", messagesJson); //Add the messagesJson object to the rootJson object
      
            return rootJson;
         }
      }
      
  9. 이제 JSON 형식의 메시지를 OCI Queue로 전송할 수 있습니다. 다음 이미지와 같이 oci_queue 폴더 및 해당 Java Spring Boot 클래스를 생성합니다.

    대기열 폴더

    주: OCIQueue.java 클래스에서는 OKE에서 OCI 대기열로의 액세스를 정의해야 합니다. 이 사용지침서에서는 워크로드 액세스를 사용하여 테넌시와 연관된 사용자, 비밀번호, OCID와 같은 민감한 정보를 처리할 필요 없이 OCI 리소스에 대한 액세스 권한을 부여합니다. 자세한 내용은 OCI 리소스에 워크로드 액세스 권한 부여를 참고하세요.

    OCIQueue.java 클래스 개발을 시작하기 전에 테넌시에서 워크로드 액세스를 구성합니다. 먼저 Oracle GraalVM 기반 Java 애플리케이션과 연결할 네임스페이스를 생성해야 합니다. admin 호스트에 있는지 확인합니다.

    kubectl create ns-tutorial
    

    그런 다음 애플리케이션에 대한 Kubernetes 서비스 계정을 생성합니다.

    kubectl create serviceaccount tutorialserviceaccount --namespace ns-tutorial
    

    이제 워크로드가 필요한 OCI 리소스에 액세스할 수 있도록 OCI IAM 정책을 정의합니다. 이 자습서에서는 OCI 대기열입니다.

    OCI 콘솔로 이동하여 ID 및 보안, 정책으로 이동하고 정책 생성을 누릅니다. 다음 정보를 입력하고 Create(만들기)를 누릅니다.

    • 이름: 선호 정책 이름을 입력합니다.
    • 설명: Access from oke to oci queue를 입력합니다.
    • 정책 작성기:

      Allow any-user to use queues in compartment id ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx where all {request.principal.type = 'workload', request.principal.namespace = 'ns-tutorial', request.principal.service_account = 'tutorialserviceaccount', request.principal.cluster_id = 'ocid1.cluster.oc1.sa-saopaulo-1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}
      

    작업 로드 액세스 정책

    작업 로드 액세스 정책, 네임스페이스 및 서비스 계정을 구성한 후에는 계속할 수 있습니다.

    application.properties 파일에서 작업 5에서 생성된 특정 OCI 대기열을 접속하고 관리하는 데 필요한 대기열 매개변수를 추가합니다.

    OCIID 설정

    • OCIQueue.java: 이 Spring Boot Java 클래스는 OCI Queue에 액세스하여 메시지를 저장할 수 있게 해줍니다.

      //Imports
      import com.oracle.bmc.auth.okeworkloadidentity.OkeWorkloadIdentityAuthenticationDetailsProvider; //Import OkeWorkloadIdentityAuthenticationDetailsProvider to enable access and use OCI Workload Identity
      import com.oracle.bmc.queue.QueueClient; //Import QueueClient to have access and manage of OCI Queue
      import com.oracle.bmc.queue.model.PutMessagesDetails; //Import PutMessagesDetails to send messages to the OCI Queue
      import com.oracle.bmc.queue.model.PutMessagesDetailsEntry; //Import PutMessagesDetailsEntry to send messages to the OCI Queue
      import com.oracle.bmc.queue.requests.PutMessagesRequest; //Import PutMessagesRequest to send messages to the OCI Queue
      
      //Imports for the ArrayList and List
      import java.util.ArrayList;
      import java.util.List;
      
      public class OCIQueue {
         //Set the required parameters to access to OCI and the Queue
      
         //Variables
         private String queueId; 
         private String endPoint;
         private String region;
      
         //Constructor to initialize the OCI Queue object with the required parameters
         public OCIQueue(String queueId, String endPoint, String region){
            this.queueId = queueId;
            this.endPoint = endPoint;
            this.region = region;   
         }
      
      
         //The sendMessages method sends a message to the OCI Queue
         public void sendMessages(String jsonMessage){
            try{    
      
                  //Create an OkeWorkloadIdentityAuthenticationDetailsProvider object to authenticate the OCI Queue
                  OkeWorkloadIdentityAuthenticationDetailsProvider provider = new OkeWorkloadIdentityAuthenticationDetailsProvider.OkeWorkloadIdentityAuthenticationDetailsProviderBuilder().build();
      
                  //Create a QueueClient object to send the message to the OCI Queue
                  QueueClient queueClient = QueueClient.builder().build(provider);
                  queueClient.setRegion(region);
                  queueClient.setEndpoint(endPoint);
      
      
      
                  //Create a PutMessagesDetailsEntry object to send the message
                  PutMessagesDetailsEntry message = PutMessagesDetailsEntry.builder()
                     .content(jsonMessage)
                     .build();
      
                  //Create a List of PutMessagesDetailsEntry objects to send the message
                  List<PutMessagesDetailsEntry> messages = new ArrayList<>();
                  messages.add(message);
      
                  //Create a PutMessagesDetails object to send the message
                  PutMessagesDetails putMessagesDetails = PutMessagesDetails.builder()
                     .messages(messages)
                     .build();
      
      
                  //  Create a PutMessagesRequest object to send the message
                  PutMessagesRequest putMessagesRequest = PutMessagesRequest.builder()
                     .queueId(queueId)
                     .putMessagesDetails(putMessagesDetails)
                     .build();
      
                  // Send the request and get the response
                  queueClient.putMessages(putMessagesRequest);
      
            }catch(Exception e){
                  System.out.println("Exception sending message to OCI Queue: "+e);
            }
         }
      }
      
  10. 데이터베이스, JSON 및 OCI 대기열에 대한 Spring Boot Java 클래스가 있으면 MessagesEndpoint.java 클래스를 진행할 수 있습니다.

    이를 위해 endpoint 및 해당 Spring Boot Java 클래스라는 폴더를 생성합니다.

    끝점 폴더

    주: MessagesEndpoint.java에서는 자동 생성된 일부 클래스를 임포트해야 합니다. 이렇게 하려면 pom.xml 파일의 Configuration 섹션에서 다음 소스를 추가합니다.

    <configuration>
       <sources>
       <source>${project.build.directory}/generated-sources</source>
       </sources>
    </configuration>
    

    pom.xml 파일은 다음과 같아야 합니다.

    생성된 소스 경로

    • MessagesEndpoint.java: 이 Spring Boot Java 클래스의 목적은 SOAP HTTP 요청을 추출하고 해당 값을 각 메시지의 User, Car 및 House Java 객체에 매핑하는 것입니다. 그런 다음 추출된 데이터를 각 SOAP XML 트랜잭션에 대한 ATP 데이터베이스에 저장하고, XML에서 JSON 형식으로 데이터를 변환하고, OCI 대기열에 메시지를 배치합니다. 이러한 메시지는 나중에 소비자가 대기열에서 검색하고 삭제할 수 있습니다.

      //Imports
      import com.oracle_springboot_tutorial.tutorial.model.*; //Import all the classes from the model package
      import com.oracle_springboot_tutorial.tutorial.oci_queue.OCIQueue; //Import the OCIQueue class from the oci_queue package
      
      
      import com.tutorial_example.ns0.Messages;//Import the Messages class from the tutorial_example.ns0 package (Auto generated Java Classes from the WSDL)
      import com.tutorial_example.ns0.MessageType; //Import the MessageType class from the tutorial_example.ns0 package (Auto generated Java Classes from the WSDL)
      
      //Import the ArrayList class from the java.util package
      import java.util.ArrayList;
      
      //Spring Boot imports to be used for the SOAP Web Service
      import org.springframework.beans.factory.annotation.Autowired; //Import the @Autowired annotation to inject the SoapObjectRepository object
      import org.springframework.beans.factory.annotation.Value; //Import the @Value annotation to inject the values from the application.properties file
      import org.springframework.stereotype.Component; //Import the @Component annotation to register the class with Spring
      
      //Spring Boot imports 
      import org.springframework.ws.server.endpoint.annotation.Endpoint; //Import the @Endpoint annotation to register the class with Spring WS
      import org.springframework.ws.server.endpoint.annotation.PayloadRoot; //Import the @PayloadRoot annotation to specify the namespace URI and local part of the request payload
      import org.springframework.ws.server.endpoint.annotation.RequestPayload; //Import the @RequestPayload annotation to map the request payload to the method parameter
      import org.springframework.ws.server.endpoint.annotation.ResponsePayload; //Import the @ResponsePayload annotation to map the returned value to the response payload
      
      //Imports to be used storing SOAP information in the database 
      import com.oracle_springboot_tutorial.tutorial.database.SoapObjectRepository; //Import the SoapObjectRepository class from the database package
      
      //Imports to be used for JSON
      import com.oracle_springboot_tutorial.tutorial.json_message.JsonBuilder; //Import the JsonBuilder class from the json_message package 
      import org.json.JSONObject; //Import the JSONObject class from the org.json package
      
      
      //The @Endpoint annotation registers the class with Spring WS.
      //The @Component annotation registers the class with Spring to be used as a Spring Bean.
      @Endpoint
      @Component
      public class MessagesEndpoint {
      
         //Inject not encrypted and decrypted values using jasypt library from the application.properties file
         @Value("${oci.queue.queueId}")
         private String queueId;
         @Value("${oci.queue.endPoint}")
         private String endPoint;
         @Value("${oci.queue.region}")   
         private String region;
         @Value("${spring.datasource.password}")
         private String datasourcePassword;
      
         //The @Autowired loads JDBC template in SoapObjectRepository.
         @Autowired
         private SoapObjectRepository soapObjectRepository = new SoapObjectRepository();
         //Create a new instance of the JsonBuilder class
         JsonBuilder jsonBuilder = new JsonBuilder();
      
      
         //The namespace URI
         private static final String NAMESPACE_URI = "http://tutorial_example.com/ns0";
      
         //The handleMessagesRequest method is annotated with @PayloadRoot, which means that it is invoked when a request with the specified namespace URI and local part is received.
         @PayloadRoot(namespace = NAMESPACE_URI, localPart = "messages")
         //The @ResponsePayload annotation makes Spring WS map the returned value to the response payload.
         @ResponsePayload
         //The handleMessagesRequest method processes the request and sends the message to the OCI Queue.
         public void handleMessagesRequest(@RequestPayload Messages request) {
            OCIQueue ociQueue = new OCIQueue(queueId, endPoint, region);
      
            //Create an ArrayList to store the users
            ArrayList<User> usersMessageArray = new ArrayList<User>();
      
            //Iterate over the messages, extracting the SOAP Messages and storing in the Java Objects (Car, House, User) 
            for (MessageType message : request.getMessage()) {
      
                  User user = new User();
                  user.setUserName(message.getUsername());
                  user.setUserLastName(message.getUserlastname());
                  user.setID(message.getId());
                  user.setEmail(message.getEmail());
                  user.setDate(message.getDate());
                  user.setAttribute(message.getAttribute());
      
                  //Insert User in Oracle ATP
                  soapObjectRepository.saveUserSOAPMessage(user);
      
                  //Process the attributes Car or House depending of the kind of User
                  processMessage(user, message);
                  //Add the user to the ArrayList
                  usersMessageArray.add(user);
            }
      
      
            //Convert to JSON format
            JSONObject jsonObject = jsonBuilder.buildJsonMessage(usersMessageArray);
      
            //Send the JSON message to OCI Queue
            ociQueue.sendMessages(jsonObject.toString());
      
         }
      
         //The processMessage method processes the message based on the user's attribute.
         private void processMessage(User user, MessageType message) {
            String subject = user.getAttribute();
            switch (subject) {
                  case "CAR":
                     handleCAR(user, message);
                     break;
                  case "HOUSE":
                     handleHouse(user, message);
                     break;
                  default:
                     System.out.println("Unknown subject: " + subject);
            }
         }
      
         //The handleCAR method processes the CAR message.
         private void handleCAR(User user, MessageType message) {
            Car car = new Car();
            car.setBrand(message.getBody().getEnvelope().getBrand());
            car.setColor(message.getBody().getEnvelope().getColor());
            car.setPlate(message.getBody().getEnvelope().getPlate());
      
            user.setCar(car);
            //Insert Car in Oracle ATP
            soapObjectRepository.saveCarSOAPMessage(user.getCar());
      
         }
      
         //The handleHouse method processes the HOUSE message.
         private void handleHouse(User user, MessageType message) {
            House house = new House();
            house.setFloors(message.getBody().getEnvelope().getFloors());
            house.setLocation(message.getBody().getEnvelope().getLocation());
            house.setRooms(message.getBody().getEnvelope().getRooms());
            house.setBathRooms(message.getBody().getEnvelope().getBathrooms());
      
            user.setHouse(house);
      
            //Insert Houses in Oracle ATP
            soapObjectRepository.saveHouseSOAPMessage(user.getHouse());
      
         }
      }
      
  11. 이제 Spring Boot 프로젝트의 전체 구성을 완료했으므로 프로젝트 폴더에 Dockerfile를 만듭니다.

  1. 다음 명령을 실행하여 로컬 Docker 저장소에서 프로젝트 이미지를 빌드하고 푸시합니다.

    docker build . -t springbootapp:latest
    

    Docker 이미지 빌드

  2. 다음 명령을 실행하여 로컬 Docker 저장소의 이미지를 확인합니다.

    docker images
    

    Docker 이미지 로컬 저장소

  3. OCI Container Registry Classic 저장소의 전체 경로로 Spring Boot 애플리케이션 이미지에 태그를 지정할 수 있습니다.

    docker tag springbootapp:latest gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    
  4. 다음 명령을 실행하여 로컬 Docker 저장소에서 확인합니다.

    docker images
    

    OKE 애플리케이션 태그 지정

  5. 다음 명령을 실행하여 OCI Container Registry Classic에 이미지를 푸시합니다.

    docker push gru.ocir.io/xxxxxxxxxx/springboot/tutorialapp:latest
    

    OKE 애플리케이션 푸시

  6. OCI Container Registry Classic에서 OKE 이미지 애플리케이션을 검토하려면 개발자 서비스, 컨테이너 및 아티팩트로 이동하고 컨테이너 레지스트리를 누릅니다.

    OKE Containe 레지스트리의 이미지

    이미지가 OCI Container Registry Classic에 있으면 개발 환경으로 이동하여 OKE에 이 이미지를 배치할 수 있습니다. 이 자습서에서는 다음 명령을 실행하여 필요한 구성을 만듭니다.

    주: 네임스페이스 및 서비스 계정이 이전에 구성되었으므로 암호가 필요합니다.

    1. 다음 명령을 실행하여 프로젝트 폴더에 액세스합니다.

      cd tutorial/
      
    2. 다음 명령을 실행하여 OKE에 대한 암호를 만듭니다.

      kubectl create secret -n ns-tutorial generic ocir --from-file=.dockerconfigjson=../.docker/config.json --type=kubernetes.io/dockerconfigjson
      

      단속 작업 생성

  7. OKE 환경이 이미 준비되어 있으므로 OCI Container Registry Classic에서 OKE로 애플리케이션 이미지를 배포하십시오.

    주: 응용 프로그램 이미지를 배치하려면 매니페스트 파일이 있어야 합니다. 이 사용지침서에서는 다음 yaml 파일이 매니페스트 파일입니다. 이 파일은 애플리케이션을 배치하고 80 포트를 사용하여 수신 중인 OCI 로드 밸런서에 표시되는 수신 서비스를 생성하는 데 사용됩니다.

    • springboot_application.yaml:

      apiVersion: apps/v1
      kind: Deployment
      metadata:
      name: soap-oci-queue-app
      namespace: ns-tutorial 
      labels:
         app: soap-oci-queue-app
      spec:
      replicas: 6
      selector:
         matchLabels:
            app: soap-oci-queue-app
      template:
         metadata:
            labels:
            app: soap-oci-queue-app
         spec:
            serviceAccountName: tutorialserviceaccount
            automountServiceAccountToken: true      
            containers:
            - name: soap-oci-queue-app
            image: gru.ocir.io/xxxxxxxxxxxx/springboot/tutorialapp:latest
            ports:
            - containerPort: 8080
            imagePullSecrets:
            - name: ocir-docker-config
      ---
      
      apiVersion: v1
      kind: Service
      metadata:
      name: svc-dev-app 
      namespace: ns-tutorial 
      spec:
      selector:
         app: soap-oci-queue-app
      ports:
         - port: 80
            targetPort: 8080
      type: LoadBalancer
      
  8. 매니페스트 파일을 저장한 폴더에서 kubectl 명령을 실행합니다.

    kubectl apply -f springboot_application.yaml
    

    이제 애플리케이션이 배포되고 수신 로드 밸런서 서비스가 OKE에 생성됩니다.

    OKE의 매니페스트 적용

  9. OKE에서 생성된 Pod 및 서비스를 검증하려면 다음 명령을 실행합니다.

    kubectl get pods -A
    

    OKE POD

    kubectl get svc -A
    

    OKE 서비스

    주: tutorial.zip에서 Spring Boot Oracle GraalVM 기반 Java 애플리케이션 프로젝트를 다운로드하십시오.

작업 7: JMeter를 사용하여 Spring Boot Oracle Graal VM 애플리케이션 테스트

JMeter 설치에 대한 자세한 내용은 Getting Started with JMeter를 참조하십시오.

JMeter가 설치되고 구성되면 HTTP POST SOAP 요청을 전송할 수 있습니다. 예를 들어, 스레드 수를 2로 설정하여 동시 사용자 또는 응용 프로그램 2개를 나타내고, Loop Count를 3000으로 설정하면 각 사용자 또는 응용 프로그램이 총 6000개의 SOAP 요청에 대해 3000개의 요청을 보냅니다.

SOAP 메시지

JMeter에서 OCI 로드 밸런서 IP, Spring Boot 프로젝트에 구성된 경로 및 본문의 SOAP XML을 설정합니다.

HTTP SOAP 요청

6000개의 SOAP 트랜잭션을 사용하여 JMeter를 실행하고 확인합니다.

주: 클라이언트 응용 프로그램의 SOAP 메시징을 시뮬레이트할 때 각 SOAP HTTP 요청에 대해 정보는 위에 표시된 SOAP XML 파일에 표시된 것과 동일하며 변경되지는 않지만 실제 고객 환경에서는 정보가 확실히 다를 수 있습니다.

다음 명령문을 실행합니다.

  1. ATP에 저장된 총 데이터를 확인합니다.

    Oracle ATP

  2. ATP의 각 테이블에 저장된 데이터의 상세내역을 조회합니다.

    • 자동차:

      자동차

    • 주택들:

      주택

    • USERS:

      USERS

  3. OCI 대기열에 저장된 총 OCI 대기열 요청을 봅니다.

    총 OCI 대기열 요청

  4. OCI 대기열의 메시지 세부정보를 JSON 형식으로 보려면 다음을 수행합니다.

    OCI 대기열 메시지 세부정보

확인

추가 학습 자원

docs.oracle.com/learn에서 다른 실습을 탐색하거나 Oracle Learning YouTube 채널에서 더 많은 무료 학습 콘텐츠에 액세스하세요. 또한 Oracle Learning Explorer가 되려면 education.oracle.com/learning-explorer을 방문하십시오.

제품 설명서는 Oracle Help Center를 참조하십시오.