Jakarta Enterprise Beans 애플리케이션 개발

Red Hat JBoss Enterprise Application Platform 7.4

Red Hat JBoss Enterprise Application Platform용 Jakarta Enterprise Beans 애플리케이션을 개발 및 배포하려는 개발자와 관리자를 위한 지침 및 정보.

Red Hat Customer Content Services

초록

이 문서에서는 Red Hat JBoss Enterprise Application Platform을 사용하여 Jakarta Enterprise Beans 애플리케이션을 개발 및 배포하려는 개발자와 관리자를 위한 정보를 제공합니다.

JBoss EAP 문서에 대한 피드백 제공

오류를 보고하거나 문서를 개선하기 위해 Red Hat Jira 계정에 로그인하여 문제를 제출하십시오. Red Hat Jira 계정이 없는 경우 계정을 생성하라는 메시지가 표시됩니다.

절차

  1. 티켓을 생성하려면 다음 링크를 클릭하십시오.
  2. 문서 URL, 섹션 번호 를 포함하고 문제를 설명하십시오.
  3. 요약 에 문제에 대한 간략한 설명을 입력합니다.
  4. 설명에서 문제 또는 개선 사항에 대한 자세한 설명을 제공합니다. 문서에서 문제가 발생한 위치에 URL을 포함합니다.
  5. Submit 을 클릭하고 문제를 적절한 문서 팀으로 라우팅합니다.

보다 포괄적 수용을 위한 오픈 소스 용어 교체

Red Hat은 코드, 문서, 웹 속성에서 문제가 있는 용어를 교체하기 위해 최선을 다하고 있습니다. 먼저 마스터(master), 슬레이브(slave), 블랙리스트(blacklist), 화이트리스트(whitelist) 등 네 가지 용어를 교체하고 있습니다. 이러한 변경 작업은 작업 범위가 크므로 향후 여러 릴리스에 걸쳐 점차 구현할 예정입니다. 자세한 내용은 CTO Chris Wright의 메시지를 참조하십시오.

1장. 소개

1.1. Jakarta Enterprise Bean 개요

Jakarta Enterprise Beans는 Enterprise Beans라는 서버 측 구성 요소를 사용하여 분산, 트랜잭션, 보안 및 이식 가능한 자카르타 EE 애플리케이션을 개발하기 위한 API입니다. Enterprise Beans는 애플리케이션의 비즈니스 로직을 분리된 방식으로 구현하여 재사용을 촉진합니다. Jakarta Enterprise Beans은 Jakarta Enterprise Beans 3.2 사양에 설명되어 있습니다.

1.2. Jakarta Enterprise Beans 3.2 기능 세트

JBoss EAP 7.3 이상 버전은 다음과 같은 Jakarta Enterprise Beans 3.2 기능을 지원합니다.

  • 세션 빈
  • 메시지 기반 빈
  • Jakarta Enterprise Beans API 그룹
  • no-interface 뷰
  • 로컬 인터페이스
  • 원격 인터페이스
  • 자동 종료 가능 인터페이스
  • 타이머 서비스
  • 비동기 호출
  • 자카르타 인터셉터
  • RMI/IIOP 상호 운용성
  • 트랜잭션 지원
  • 보안
  • 임베드 가능한 API

다음 기능은 JBoss EAP 7에서 더 이상 지원하지 않습니다.

  • EJB 2.1 엔터티 빈 클라이언트 보기
  • 빈 관리 지속성이 있는 엔터티 빈
  • 컨테이너 관리 지속성이 있는 엔터티 빈
  • EJB 쿼리 언어(EJB QL)
  • JAX-RPC 기반 웹 서비스: 끝점 및 클라이언트 보기

1.3. Enterprise Beans

엔터프라이즈 빈은 Java 클래스로 작성되며 적절한 Jakarta Enterprise Beans 주석을 사용하여 주석을 달 수 있습니다. 자체 아카이브( JAR 파일)에서 애플리케이션 서버에 배포하거나 Jakarta EE 애플리케이션의 일부로 배포할 수 있습니다. 애플리케이션 서버는 각 엔터프라이즈 빈의 라이프사이클을 관리하고 보안, 트랜잭션, 동시성 관리 등의 서비스를 제공합니다.

엔터프라이즈 빈은 다양한 비즈니스 인터페이스를 정의할 수도 있습니다. 비즈니스 인터페이스는 클라이언트가 사용할 수 있는 빈 메서드 중 어떤 것을 보다 잘 제어할 수 있으며 원격 JVM에서 실행되는 클라이언트에 대한 액세스를 허용할 수도 있습니다.

엔터프라이즈 빈에는 세션 빈,메시지 기반 빈, 엔터티 빈의 세 가지 유형이 있습니다.

참고

JBoss EAP는 엔터티 빈을 지원하지 않습니다.

1.3.1. 엔터프라이즈 빈 작성

엔터프라이즈 빈은 Java 아카이브(JAR) 파일에 패키징 및 배포됩니다. 엔터프라이즈 빈 JAR 파일을 애플리케이션 서버에 배포하거나 EAR(엔터프라이즈 아카이브) 파일에 포함시키고 해당 애플리케이션과 함께 배포할 수 있습니다. 또한 웹 애플리케이션과 함께 WS(웹 아카이브) 파일에 엔터프라이즈 빈을 배포할 수 있습니다.

1.4. Enterprise Bean Business Interfaces

Jakarta Enterprise Beans 비즈니스 인터페이스는 클라이언트가 사용할 수 있는 세션 빈의 공용 메서드를 선언하는 빈 개발자가 작성한 Java 인터페이스입니다. 세션 빈은 none( 인터페이스 빈 없음 )을 포함하여 원하는 수의 인터페이스를 구현할 수 있습니다.

비즈니스 인터페이스는 로컬 또는 원격 인터페이스로 선언할 수 있지만 둘 다 사용할 수는 없습니다.

자카르타 엔터프라이즈 빈 로컬 비즈니스 인터페이스

Jakarta Enterprise Beans 로컬 비즈니스 인터페이스는 빈과 클라이언트가 동일한 JVM에 있을 때 사용 가능한 메서드를 선언합니다. 세션 빈에서 로컬 비즈니스 인터페이스를 구현하는 경우 해당 인터페이스에 선언된 메서드만 클라이언트에 사용할 수 있습니다.

자카르타 엔터프라이즈 빈 원격 비즈니스 인터페이스

Jakarta Enterprise Beans 원격 비즈니스 인터페이스는 원격 클라이언트에서 사용할 수 있는 방법을 선언합니다. 원격 인터페이스를 구현하는 세션 빈에 대한 원격 액세스는 Jakarta Enterprise Beans 컨테이너에서 자동으로 제공합니다.

원격 클라이언트는 다른 JVM에서 실행되는 모든 클라이언트이며 데스크탑 애플리케이션과 다른 애플리케이션, 서비스 및 엔터프라이즈 빈을 다른 애플리케이션 서버에 배포할 수 있습니다.

로컬 클라이언트는 원격 비즈니스 인터페이스에서 노출하는 메서드에 액세스할 수 있습니다.

Jakarta Enterprise Bean No-interface Bean

비즈니스 인터페이스를 구현하지 않는 세션 빈을 no-interface 빈이라고 합니다. 인터페이스 없는 빈의 모든 공용 메서드는 로컬 클라이언트가 액세스할 수 있습니다.

비즈니스 인터페이스를 구현하는 세션 빈도 비인터페이스 보기를 노출하도록 작성할 수 있습니다.

1.5. 레거시 EJB 클라이언트 호환성

JBoss EAP는 원격 Jakarta Enterprise Beans 구성 요소를 호출하는 기본 API로 Jakarta Enterprise Beans 클라이언트 라이브러리를 제공합니다.

JBoss EAP 7.1부터 Enterprise Beans 클라이언트 두 개가 제공됩니다.

  • Enterprise Beans 클라이언트: 정규 Enterprise Beans 클라이언트는 이전 버전과 완벽하게 호환되지 않습니다.
  • 레거시 EJB 클라이언트: 레거시 EJB 클라이언트는 바이너리 이전 버전과의 호환성을 제공합니다. 이 레거시 EJB 클라이언트는 JBoss EAP 7.0에서 EJB 클라이언트를 사용하여 처음 컴파일된 클라이언트 애플리케이션과 함께 실행할 수 있습니다. JBoss EAP 7.0용 EJB 클라이언트에 있는 모든 API는 JBoss EAP 7.4용 레거시 EJB 클라이언트에 있습니다.

구성에 다음 Maven 종속성을 포함하여 레거시 EJB 클라이언트 호환성을 사용할 수 있습니다.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.eap</groupId>
            <artifactId>wildfly-ejb-client-legacy-bom</artifactId>
            <version>EAP_BOM_VERSION</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.jboss</groupId>
        <artifactId>jboss-ejb-client-legacy</artifactId>
    </dependency>
</dependencies>

JBoss EAP Maven 리포지토리에서 사용할 수 있는 EAP_BOM_VERSION 을 사용해야 합니다.

2장. Enterprise Bean 프로젝트 생성

2.1. Red Hat CodeReady Studio를 사용하여 Jakarta Enterprise Beans Archive 프로젝트 만들기

이 작업은 Red Hat CodeReady Studio에서 Jakarta Enterprise Beans 프로젝트를 생성하는 방법을 설명합니다.

사전 요구 사항

  • JBoss EAP용 서버 및 서버 런타임은 Red Hat CodeReady Studio에 구성되어 있습니다.

    참고

    Red Hat CodeReady Studio에서 Target 런타임7.4 또는 이후 런타임 버전으로 설정하면 프로젝트가 Jakarta EE 8 사양과 호환됩니다.

Red Hat CodeReady Studio에서 Jakarta Enterprise Beans Project 만들기

  1. New EJB Project 마법사를 엽니다.

    1. File (파일) 메뉴로 이동하여 New (새로 만들기)를 선택한 다음 Project(프로젝트 )를 선택합니다.
    2. New Project(새 프로젝트) 마법사가 나타나면 EJB/EJB Project 를 선택하고 Next (다음)를 클릭합니다.

      그림 2.1. 새 EJB 프로젝트 마법사

      새 EJB 프로젝트 마법사
  2. 다음 세부 정보를 입력합니다.

    • 프로젝트 이름: Red Hat CodeReady Studio에 표시되는 프로젝트의 이름과 배포된 JAR 파일의 기본 파일 이름.
    • 프로젝트 위치: 프로젝트 파일이 저장될 디렉터리입니다. 기본값은 현재 작업 영역의 디렉터리입니다.
    • 대상 런타임: 프로젝트에 사용되는 서버 런타임입니다. 배포할 서버에서 사용하는 것과 동일한 JBoss EAP 런타임으로 설정해야 합니다.
    • EJB 모듈 버전: 이 버전은 엔터프라이즈 빈이 준수하는 Jakarta Enterprise Beans 사양의 버전입니다. 3.2 사용을 권장합니다.
    • 설정: 이를 통해 프로젝트에서 지원되는 기능을 조정할 수 있습니다. 선택한 런타임에 기본 구성을 사용합니다.

      Next (다음)를 클릭하여 계속합니다.

  3. Java 프로젝트 구성 화면을 사용하면 Java 소스 파일이 포함된 디렉터리를 추가하고 빌드 출력의 디렉터리를 지정할 수 있습니다.

    이 구성을 변경하지 않고 그대로 두고 Next (다음)를 클릭합니다.

  4. EJB 모듈 설정 화면에서 배포 설명자가 필요한 경우 Generate ejb-jar.xml deployment descriptor 를 선택합니다. 배포 설명자는 Jakarta Enterprise Beans 3.2에서 선택 사항이며 필요한 경우 나중에 추가할 수 있습니다.

    Finish (완료)를 클릭하면 프로젝트가 생성되고 Project Explorer에 표시됩니다.

    그림 2.2. Project Explorer에서 새로 생성된 Jakarta Enterprise Beans Project

    Project Explorer에서 새로 생성된 EJB 프로젝트
  5. 배포를 위해 서버에 프로젝트를 추가하려면 Servers(서버 ) 탭에서 대상 서버를 마우스 오른쪽 버튼으로 클릭하고 Add and Remove (추가 및 제거)를 선택합니다.

    Add and Remove (추가 및 제거) 대화 상자의 Available (사용 가능) 열에서 배포할 리소스를 선택하고 Add (추가) 버튼을 클릭합니다. 리소스는 Configured 열로 이동합니다. Finish( 완료 )를 클릭하여 대화 상자를 닫습니다.

    그림 2.3. 대화 상자 추가 및 제거

    대화 상자 추가 및 제거

이제 지정된 서버에 빌드 및 배포할 수 있는 Red Hat CodeReady Studio에 Jakarta Enterprise Beans 프로젝트가 있습니다.

주의

프로젝트에 엔터프라이즈 빈을 추가하지 않으면 Red Hat CodeReady Studio에 EJB 모듈에 하나 이상의 엔터프라이즈 빈이 포함되어야 함을 알리는 경고 메시지가 표시됩니다. 하나 이상의 엔터프라이즈 빈이 프로젝트에 추가되면 이 경고가 사라집니다.

2.2. Maven에서 Jakarta Enterprise Beans Archive Project 만들기

이 작업은 JAR 파일에 패키징된 하나 이상의 엔터프라이즈 빈을 포함하는 Maven을 사용하여 프로젝트를 생성하는 방법을 보여줍니다.

사전 요구 사항

  • Maven이 이미 설치되어 있습니다.
  • Maven의 기본 사용법을 이해합니다.

Maven에서 Jakarta Enterprise Beans Archive Project 만들기

  1. Maven 프로젝트를 생성합니다. Jakarta Enterprise Beans 프로젝트는 Maven의 전형 시스템과 ejb-javaee7 전형을 사용하여 생성할 수 있습니다. 이렇게 하려면 다음과 같이 매개 변수를 사용하여 mvn 명령을 실행합니다.

    $ mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee7

    Maven은 프로젝트에 대한 groupId,artifactId,버전패키지를 요청합니다.

    $ mvn archetype:generate -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=ejb-javaee7
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building Maven Stub Project (No POM) 1
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
    [INFO]
    [INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
    [INFO]
    [INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom ---
    [INFO] Generating project in Interactive mode
    [INFO] Archetype [org.codehaus.mojo.archetypes:ejb-javaee7:1.5] found in catalog remote
    Define value for property 'groupId': : com.shinysparkly
    Define value for property 'artifactId': : payment-arrangements
    Define value for property 'version':  1.0-SNAPSHOT: :
    Define value for property 'package':  com.shinysparkly: :
    Confirm properties configuration:
    groupId: com.company
    artifactId: payment-arrangements
    version: 1.0-SNAPSHOT
    package: com.company.collections
    Y: :
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 32.440s
    [INFO] Finished at: Mon Oct 31 10:11:12 EST 2011
    [INFO] Final Memory: 7M/81M
    [INFO] ------------------------------------------------------------------------
    [localhost]$
  2. 엔터프라이즈 빈 추가: 엔터프라이즈 빈을 작성하고 빈 패키지의 적절한 하위 디렉터리에 있는 src/main/java 디렉터리의 프로젝트에 추가합니다.
  3. 프로젝트를 빌드합니다. 프로젝트를 빌드하려면 pom.xml 파일과 동일한 디렉터리에서 mvn package 명령을 실행합니다. Java 클래스를 컴파일하고 JAR 파일을 패키징합니다. 빌드된 JAR 파일의 이름은 -.jar 로 지정되며 target/ 디렉토리에 배치됩니다.

이제 JAR 파일을 빌드하고 패키징하는 Maven 프로젝트가 있습니다. 이 프로젝트에는 엔터프라이즈 빈이 포함될 수 있으며 JAR 파일을 애플리케이션 서버에 배포할 수 있습니다.

2.3. Jakarta Enterprise Beans 프로젝트가 포함된 EAR 프로젝트 만들기

이 작업은 Jakarta Enterprise Beans 프로젝트가 포함된 Red Hat CodeReady Studio에서 새 EAR(Enterprise Archive) 프로젝트를 생성하는 방법을 설명합니다.

사전 요구 사항

  • JBoss EAP용 서버 및 서버 런타임이 설정되었습니다.

    참고

    Red Hat CodeReady Studio에서 Target 런타임7.4 또는 이후 런타임 버전으로 설정하면 프로젝트가 Jakarta EE 8 사양과 호환됩니다.

Jakarta Enterprise Beans 프로젝트가 포함된 EAR 프로젝트 만들기

  1. 새 Java EE EAR 프로젝트 마법사 열기.

    1. File (파일) 메뉴로 이동하여 New (새로 만들기)를 선택한 다음 Project(프로젝트 )를 선택합니다.
    2. New Project(새 프로젝트) 마법사가 나타나면 Java EE/Enterprise Application Project(Java EE/엔터프라이즈 애플리케이션 프로젝트 )를 선택하고 Next (다음)를 클릭합니다.

    그림 2.4. 새로운 EAR 애플리케이션 프로젝트 마법사

    새로운 EAR 애플리케이션 프로젝트 마법사
  2. 다음 세부 정보를 입력합니다.

    • 프로젝트 이름: Red Hat CodeReady Studio에 표시되는 프로젝트의 이름과 배포된 EAR 파일의 기본 파일 이름입니다.
    • 프로젝트 위치: 프로젝트 파일이 저장될 디렉터리입니다. 기본값은 현재 작업 영역의 디렉터리입니다.
    • 대상 런타임: 프로젝트에 사용되는 서버 런타임입니다. 배포할 서버에서 사용하는 것과 동일한 JBoss EAP 런타임으로 설정해야 합니다.
    • EAR 버전: 프로젝트가 준수할 자카르타 EE 8 사양의 버전입니다.

      Red Hat은 Jakarta EE 8 사용을 권장합니다.

    • 설정: 이를 통해 프로젝트에서 지원되는 기능을 조정할 수 있습니다. 선택한 런타임에 기본 구성을 사용합니다.

      Next (다음)를 클릭하여 계속합니다.

  3. 새 Jakarta Enterprise Beans 모듈을 추가합니다.

    새 모듈은 마법사의 Enterprise Application(엔터프라이즈 애플리케이션 ) 페이지에서 추가할 수 있습니다. 모듈로 새로운 Jakarta Enterprise Beans 프로젝트를 추가하려면 다음 단계를 따르십시오.

    1. New Module(새 모듈 )을 클릭하고 Create Default Modules (기본 모듈 만들기) 확인란을 선택 취소하고 Enterprise Java Bean 을 선택한 다음 Next (다음)를 클릭합니다. New EJB Project 마법사 가 나타납니다.
    2. New EJB Project 마법사 는 새로운 독립 실행형 Jakarta Enterprise Beans 프로젝트를 생성하는 데 사용되는 마법사와 동일하며 Red Hat CodeReady Studio를 사용하여 Jakarta Enterprise Beans Archive 프로젝트 생성에 설명되어 있습니다.

      프로젝트를 생성하는 데 필요한 최소 세부 사항은 다음과 같습니다.

      • 프로젝트 이름
      • 대상 런타임
      • Jakarta Enterprise Beans 모듈 버전
      • 설정

        마법사의 다른 모든 단계는 선택 사항입니다. Finish (완료)를 클릭하여 Jakarta Enterprise Beans Project 생성을 완료합니다.

        새로 생성된 Jakarta Enterprise Beans 프로젝트는 Java EE 모듈 종속성에 나열되며 확인란이 선택됩니다.

  4. 선택적으로, application.xml 배포 설명자를 추가합니다.

    필요한 경우 Generate application.xml deployment descriptor 확인란을 선택합니다.

  5. 완료를 클릭합니다.

    Jakarta Enterprise Beans 프로젝트와 EAR 프로젝트라는 두 개의 새 프로젝트가 나타납니다.

  6. 배포를 위해 서버에 빌드 아티팩트를 추가합니다.

    서버 탭에서 빌드된 아티팩트를 배포할 서버의 Servers(서버 ) 탭을 마우스 오른쪽 버튼으로 클릭한 다음 Add and Remove (추가 및 제거)를 선택하여 Add and Remove (추가 및 제거) 대화 상자를 엽니다.

    Available (사용 가능한) 열에서 배포할 EAR 리소스를 선택하고 Add (추가) 버튼을 클릭합니다. 리소스는 Configured 열로 이동합니다. Finish( 완료 )를 클릭하여 대화 상자를 닫습니다.

그림 2.5. 대화 상자 추가 및 제거

대화 상자 추가 및 제거

이제 회원 Jakarta Enterprise Beans Project가 포함된 Enterprise Application Project를 갖게 되었습니다. 그러면 Jakarta Enterprise Beans 하위 배포가 포함된 단일 EAR 배포로 지정된 서버에 빌드 및 배포됩니다.

2.4. Jakarta Enterprise Beans 프로젝트에 배포 설명자 추가

Jakarta Enterprise Beans 배포 설명자를 사용하지 않고 만든 Jakarta Enterprise Beans 프로젝트에 추가할 수 있습니다. 이 작업을 수행하려면 아래 절차를 따르십시오.

사전 요구 사항

  • Jakarta Enterprise Beans 배포 설명자를 추가할 Red Hat CodeReady Studio에 Jakarta Enterprise Beans 프로젝트가 있습니다.

Jakarta Enterprise Beans 프로젝트에 배포 설명자 추가

  1. Red Hat CodeReady Studio에서 프로젝트를 엽니다.
  2. 배포 설명자를 추가합니다.

    프로젝트 보기에서 Deployment Descriptor 폴더를 마우스 오른쪽 버튼으로 클릭하고 Generate Deployment Descriptor (배포 디스크립터 생성) 탭을 선택합니다.

    그림 2.6. 배포 설명자 추가

    배포 설명자 추가

    새 파일 ejb-jar.xmlejbModule/META-INF/ 에 생성됩니다. 프로젝트 보기에서 Deployment Descriptor 폴더를 두 번 클릭하여 이 파일을 엽니다.

2.5. 빈에 대한 런타임 배포 정보

성능 모니터링을 위해 빈에 런타임 배포 정보를 추가할 수 있습니다.

사용 가능한 런타임 데이터에 대한 자세한 내용은 JBoss EAP 관리 모델의 tekton 3 하위 시스템을 참조하십시오. 애플리케이션에는 빈 코드의 주석 또는 배포 설명자에 런타임 데이터가 포함될 수 있습니다. 애플리케이션은 두 옵션을 모두 사용할 수 있습니다.

추가 리소스

3장. 세션 빈

3.1. 세션 빈

세션 빈은 관련 비즈니스 프로세스 또는 작업 집합을 캡슐화하고 요청하는 클래스에 주입되는 엔터프라이즈 빈입니다. 세션 빈에는 상태 비저장, 상태 저장 및 Singleton의 세 가지 유형이 있습니다.

3.2. 상태 비저장 세션 빈

상태 비저장 세션 빈은 가장 단순하지만 가장 널리 사용되는 세션 빈 유형입니다. 클라이언트 애플리케이션에 비즈니스 메서드를 제공하지만 메서드 호출 간에 상태를 유지하지는 않습니다. 각 메서드는 해당 세션 빈 내의 공유 상태를 사용하지 않는 전체 작업입니다. 상태가 없기 때문에 각 메서드 호출이 동일한 인스턴스에서 수행되는지 확인하는 데 애플리케이션 서버가 필요하지 않습니다. 이를 통해 상태 비저장 세션 빈을 매우 효율적이고 확장할 수 있습니다.

3.3. 상태 저장 세션 빈

상태 저장 세션 빈은 클라이언트 애플리케이션에 비즈니스 방법을 제공하고 클라이언트와의 대화 상태를 유지하는 엔터프라이즈 빈입니다. 유지 관리 중인 이전 단계의 상태에 의존하는 여러 단계에서 수행해야 하는 작업 또는 메서드 호출에 사용해야 합니다. 애플리케이션 서버를 사용하면 각 클라이언트에 각 메서드 호출에 대해 동일한 상태 저장 세션 빈 인스턴스가 수신됩니다.

3.4. Singleton 세션 빈

Singleton 세션 빈은 애플리케이션당 한 번씩 인스턴스화되는 세션 빈이며 Singleton 빈에 대한 모든 클라이언트 요청은 동일한 인스턴스로 이동합니다. Singleton 빈은 책에 설명된 대로 Singleton 디자인 패턴 구현입니다. 설계 패턴 : 재사용 가능한 객체 지향 소프트웨어의 요소 Erich Gamma, Richard Helm, Ralph Johnson 및 John Vlissides; Addison-Wesley가 2005년 게시했습니다.

Singleton 빈은 모든 세션 빈 유형의 최소 메모리 풋프린트를 제공하지만 스레드 보안으로 설계해야 합니다. Jakarta Enterprise Beans 3.2는 개발자가 스레드 안전한 Singleton 빈을 쉽게 구현할 수 있도록 CMC(컨테이너 관리 동시성)를 제공합니다. 그러나 CMC가 충분한 유연성을 제공하지 않는 경우 기존 멀티 스레드 코드(빈 관리 동시성 또는 BMC)를 사용하여 Singleton 빈을 작성할 수도 있습니다.

3.5. Red Hat CodeReady Studio의 프로젝트에 세션 빈 추가

Red Hat CodeReady Studio에는 엔터프라이즈 빈 클래스를 빠르게 만드는 데 사용할 수 있는 몇 가지 마법사가 있습니다. 다음 절차에서는 Red Hat CodeReady Studio 마법사를 사용하여 세션 빈을 프로젝트에 추가하는 방법을 보여줍니다.

사전 요구 사항

  • Red Hat CodeReady Studio에 Jakarta Enterprise Bean 또는 Dynamic Web Project가 있으며 하나 이상의 세션 빈을 추가할 수 있습니다.

Red Hat CodeReady Studio의 프로젝트에 세션 빈 추가

  1. Red Hat CodeReady Studio에서 프로젝트를 엽니다.
  2. Create EJB 3.x Session Bean(EJB 3.x 세션 빈 만들기) 마법사를 엽니다.

    Create EJB 3.x Session Bean(EJB 3.x 세션 빈 만들기) 마법사 를 열려면 File (파일) 메뉴로 이동하여 New (새로 만들기)를 선택한 다음 Session Bean(EJB 3.x) 을 선택합니다.

    그림 3.1. EJB 3.x 세션 빈 마법사 만들기

    EJB 3.x 세션 빈 마법사 만들기
  3. 다음 세부 사항을 지정합니다.

    • 프로젝트: 올바른 프로젝트가 선택되었는지 확인합니다.
    • 소스 폴더: Java 소스 파일이 에 생성되는 폴더입니다. 일반적으로 변경할 필요는 없습니다.
    • 패키지: 클래스가 속하는 패키지를 지정합니다.
    • 클래스 이름: 세션 빈이 될 클래스의 이름을 지정합니다.
    • 슈퍼 클래스: 세션 빈 클래스는 슈퍼 클래스에서 상속할 수 있습니다. 세션에 슈퍼 클래스가 있는 경우 여기에 지정합니다.
    • 상태 유형: 세션 빈의 상태 유형을 지정합니다. 상태 비저장, 상태 저장 또는 Singleton.
    • 비즈니스 인터페이스: 기본적으로 No-interface 상자가 선택되어 인터페이스가 생성되지 않습니다. 필요한 경우 이름을 정의하고 조정할 인터페이스의 확인란을 선택합니다.

      WAR(웹 아카이브)의 엔터프라이즈 빈은 Jakarta Enterprise Beans 3.2 Lite만 지원하므로 원격 비즈니스 인터페이스는 포함되지 않습니다.

      다음을 클릭합니다.

  4. 세션 빈을 추가로 사용자 지정하려면 여기에 추가 정보를 입력할 수 있습니다. 여기에서는 정보를 변경할 필요가 없습니다.

    변경할 수 있는 항목은 다음과 같습니다.

    • 빈 이름
    • 매핑된 이름
    • 트랜잭션 유형(컨테이너 관리 또는 빈 관리)
    • 빈이 구현해야 할 추가 인터페이스를 제공할 수 있습니다.
    • 필요한 경우 EJB 2.x Home 및 구성 요소 인터페이스를 지정할 수도 있습니다.
  5. Finish (완료)를 클릭하면 새 세션 빈이 생성되어 프로젝트에 추가됩니다. 새 비즈니스 인터페이스에 대한 파일도 지정된 경우 생성됩니다.

    그림 3.2. Red Hat CodeReady Studio의 새 세션 빈

    Red Hat CodeReady Studio의 새 세션 빈

4장. Message-Driven Bean

4.1. Message-Driven Bean

MDB(Message-driven Bean)는 애플리케이션 개발을 위한 이벤트 중심 모델을 제공합니다. MDB 메서드는 클라이언트 코드에 삽입되거나 클라이언트 코드에서 호출되지 않지만 자카르타 메시징 서버와 같은 메시징 서비스에서 메시지 수신에 의해 트리거됩니다. 자카르타 EE 사양에서는 자카르타 메시징이 지원되어야 하지만 다른 메시징 시스템도 지원할 수 있습니다.

MDB는 특별한 종류의 상태 비저장 세션 빈입니다. onMessage(Message message) 라는 메서드를 구현합니다. 이 메서드는 MDB가 수신 대기 중인 Jakarta Messaging 대상에서 메시지를 수신할 때 트리거됩니다. 즉, MDB는 Jakarta Enterprise Beans 클라이언트가 일반적으로 메서드를 호출하는 상태 비저장 세션 빈과 달리 Jakarta Messaging 공급자의 메시지를 수신하여 트리거됩니다.

MDB는 메시지를 비동기적으로 처리합니다. 기본적으로 각 MDB에는 각 세션이 메시지를 처리하는 최대 16개의 세션이 있을 수 있습니다. 주문 보장 메시지는 없습니다. 메시지 순서를 지정하려면 MDB의 세션 풀을 1 로 제한해야 합니다.

예제: 세션 풀을 1 로 설정하는 관리 CLI 명령 :

/subsystem=ejb3/strict-max-bean-instance-pool=mdb-strict-max-pool:write-attribute(name=derive-size,value=undefined)

/subsystem=ejb3/strict-max-bean-instance-pool=mdb-strict-max-pool:write-attribute(name=max-pool-size,value=1)

reload

4.2. Message-Driven Beans Controlled Delivery

JBoss EAP는 특정 MDB에서 메시지의 활성 수신을 제어하는 세 가지 특성을 제공합니다.

4.2.1. 제공(활성)

MDB(Message-driven Bean)의 전달 활성 구성은 MDB에서 메시지를 수신하고 있는지 여부를 나타냅니다. MDB에서 메시지를 수신하지 않으면 토픽 또는 큐 규칙에 따라 메시지가 대기열 또는 항목에 저장됩니다.

XML 또는 주석을 사용하여 delivery-group활성 특성을 구성할 수 있으며 관리 CLI를 사용하여 배포 후에 해당 값을 변경할 수 있습니다. 기본적으로 활성 특성이 활성화되고 메시지 전송은 MDB가 배포되는 즉시 수행됩니다.

jboss-ejb3.xml 파일에서 활성 상태로 전달 구성

jboss-ejb3.xml 파일에서 active 값을 false 로 설정하여 MDB가 배포되는 즉시 메시지를 받지 않을 것임을 나타냅니다.

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:d="urn:delivery-active:1.1"
    xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
    version="3.1"
    impl-version="2.0">
    <assembly-descriptor>
        <d:delivery>
            <ejb-name>HelloWorldQueueMDB</ejb-name>
            <d:active>false</d:active>
        </d:delivery>
    </assembly-descriptor>
</jboss:ejb-jar>

애플리케이션의 모든 MDB에 활성 값을 적용하려면 ejb-name 대신 와일드카드 * 를 사용할 수 있습니다.

주석을 사용하여 활성 배달 구성

org.jboss.ejb3.annotation.DeliveryActive 주석을 사용할 수도 있습니다. 예를 들면 다음과 같습니다.

@MessageDriven(name = "HelloWorldMDB", activationConfig = {
 @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
 @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"),
 @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
@DeliveryActive(false)

public class HelloWorldMDB implements MessageListener {
    public void onMessage(Message rcvMessage) {
      // ...
    }
}

Maven을 사용하여 프로젝트를 빌드하는 경우 프로젝트의 pom.xml 파일에 다음 종속성을 추가해야 합니다.

<dependency>
    <groupId>org.jboss.ejb3</groupId>
    <artifactId>jboss-ejb3-ext-api</artifactId>
    <version>2.2.0.Final</version>
</dependency>
관리 CLI를 사용하여 활성 상태로 배달 구성

관리 CLI를 사용하여 배포 후에 delivery-group활성 특성을 구성할 수 있습니다. 이러한 관리 작업은 활성 특성의 값을 동적으로 변경하여 MDB에 대한 전달을 활성화하거나 비활성화합니다. 서버를 다시 시작하면 제공 활성 값을 변경하는 이 방법이 유지되지 않습니다. 런타임에 관리할 인스턴스에 연결한 다음 배달을 관리할 MDB 경로를 입력합니다. 예를 들면 다음과 같습니다.

  • 관리할 인스턴스로 이동합니다.

    cd deployment=helloworld-mdb.war/subsystem=ejb3/message-driven-bean=HelloWorldQueueMDB
  • MDB로의 배달을 중지하려면 다음을 수행합니다.

    :stop-delivery
  • MDB에 대한 배달을 시작하려면 다음을 수행합니다.

    :start-delivery
MDB 제공 활성 상태 보기

관리 콘솔을 사용하여 모든 MDB의 현재 제공 활성 상태를 볼 수 있습니다.

  1. Runtime(런타임 ) 탭을 선택하고 적절한 서버를 선택합니다.
  2. EJB 를 클릭하고 하위 리소스(예: HelloWorldQueueMDB) 를 선택합니다.

결과

Delivery Active: true 또는 Delivery Active: false 로 상태가 표시됩니다.

4.2.2. 제공 그룹

제공 그룹은 MDB 그룹의 제공-활성 상태를 관리하는 방법을 제공합니다. MDB는 하나 이상의 배달 그룹에 속할 수 있습니다. 메시지 전송은 MDB가 속한 모든 배달 그룹이 활성화된 경우에만 활성화됩니다. 클러스터형 Singleton MDB의 경우 MDB와 연결된 모든 배달 그룹이 활성화된 경우에만 메시지 배달이 클러스터의 Singleton 노드에서만 활성화됩니다.

XML 구성 또는 관리 CLI를 사용하여 ejb3 하위 시스템에 전달 그룹을 추가할 수 있습니다.

jboss-ejb3.xml 파일에서 전달 그룹 구성
<delivery>
  <ejb-name>MdbName<ejb-name>
  <delivery-group>passive</delivery-group>
</delivery>

서버 측에서 실행 그룹은 활성 특성을 true 로 설정하거나 아래 예제와 같이 활성 특성을 false 로 설정하여 비활성화할 수 있습니다.

<delivery-groups>
  <delivery-group name="group" active="true"/>
</delivery-groups>
관리 CLI를 사용하여 배달 그룹 구성

delivery-group 의 상태는 관리 CLI를 사용하여 업데이트할 수 있습니다. 예를 들면 다음과 같습니다.

/subsystem=ejb3/mdb-delivery-group=group:add
/subsystem=ejb3/mdb-delivery-group=group:remove
/subsystem=ejb3/mdb-delivery-group=group:write-attribute(name=active,value=true)

jboss-ejb3.xml 파일에서 배달을 활성화하거나 주석을 사용하면 서버 재시작 시 지속됩니다. 그러나 관리 CLI를 사용하여 제공을 중지하거나 시작하면 서버 재시작 시 유지되지 않습니다.

주석을 사용하여 여러 배달 그룹 구성

그룹에 속하는 각 MDB 클래스에서 org.jboss.ejb3.annotation.DeliveryGroup 주석을 사용할 수 있습니다.

@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
@DeliveryGroup("delivery-group-1")
@DeliveryGroup("delivery-group-2")
public class HelloWorldQueueMDB implements MessageListener {
...
}

4.2.3. 클러스터형 Singleton MDB

MDB를 클러스터된 Singleton으로 식별하고 클러스터에 배포하면 하나의 노드만 활성화됩니다. 이 노드는 메시지를 직렬로 사용할 수 있습니다. 서버 노드가 실패하면 클러스터된 Singleton MDB의 활성 노드가 메시지 사용을 시작합니다.

MDB를 클러스터된 Singleton으로 식별

다음 절차 중 하나를 사용하여 MDB를 클러스터된 Singleton으로 식별할 수 있습니다.

  • 아래 예와 같이 clustered-singleton XML 요소를 사용합니다.

    <?xml version="1.1" encoding="UTF-8"?>
    <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
                   xmlns="http://java.sun.com/xml/ns/javaee"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:c="urn:clustering:1.1"
                   xmlns:d="urn:delivery-active:1.2"
                   xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
                   version="3.1"
                   impl-version="2.0">
        <assembly-descriptor>
            <c:clustering>
                <ejb-name>HelloWorldQueueMDB</ejb-name>
                <c:clustered-singleton>true</c:clustered-singleton>
            </c:clustering>
             <d:delivery>
                    <ejb-name>*</ejb-name>
                    <d:group>delivery-group-1</d:group>
                    <d:group>delivery-group-2</d:group>
            </d:delivery>
        </assembly-descriptor>
    </jboss:ejb-jar>
  • MDB 클래스에서 @org.jboss.ejb3.annotation.ClusteredSingleton을 사용합니다. 이 절차에는 서버에 추가 구성이 필요하지 않습니다. 클러스터형 환경에서 서비스를 실행해야 합니다.
참고

클러스터의 어떤 노드 Singleton 마스터가 되도록 선택되었는지 모르는 경우 클러스터의 모든 노드에서 특히 전체 클러스터에서 제공 그룹을 활성화해야 합니다. 서버에서 Singleton 마스터 로 노드를 선택하고 해당 노드에 필요한 delivery-group 이 활성화되지 않은 경우 클러스터의 노드가 메시지를 받지 않습니다.

JBoss EAP와 함께 제공되는 messaging-clustering-singleton 빠른 시작은 통합된 Apache ActiveMQ Artemis와의 클러스터링 사용을 보여줍니다. helloworld-mdb 빠른 시작과 동일한 소스 코드를 사용하며 클러스터형 Singleton으로 실행하는 구성에서만 차이가 있습니다. 이 빠른 시작에는 두 개의 Jakarta Messaging 리소스가 포함되어 있습니다.

  • Java 네이밍 및 디렉터리 인터페이스에 java:/queue/HELLO WORLDMDBQueue 바인딩된 HELLO WORLDMDBQueue라는 큐
  • Java Naming 및 Directory Interface에서 java:/topic/HELLOWORLDMDBTopic으로 바인딩된 HELLO WORLDMDBTopic이라는 항목

두 파일 모두 jboss-ejb3.xml 파일에 지정된 singleton 구성이 포함되어 있습니다.

<c:clustering>
    <ejb-name>*</ejb-name>
    <c:clustered-singleton>true</c:clustered-singleton>
</c:clustering>

<ejb-name> 요소의 와일드카드 별표 * 는 애플리케이션에 포함된 모든 MDB가 클러스터형 Singleton임을 나타냅니다. 결과적으로 클러스터에서 하나의 노드만 특정 시간에 이러한 MDB를 활성화하게 됩니다. 이 활성 노드를 종료하면 클러스터의 다른 노드가 MDB가 있는 활성 노드가 됩니다. 그러면 Singleton 공급자가 됩니다.

jboss-ejb3.xml 파일에서 delivery 그룹에 대한 구성도 찾을 수 있습니다.

<d:delivery>
    <ejb-name>HelloWorldTopicMDB</ejb-name>
    <d:group>my-mdb-delivery-group</d:group>
</d:delivery>

이 경우 MDB 중 HelloWorldTopicMDB 만 배달 그룹과 연결됩니다. MDB에서 사용하는 모든 배달 그룹은 ejb3 하위 시스템 구성에서 구성해야 합니다. 배달 그룹은 활성화 또는 비활성화할 수 있습니다. 클러스터 노드에서 배달 그룹을 비활성화하면 해당 배달 그룹에 속하는 모든 MDB가 해당 클러스터 노드에서 비활성화됩니다. 클러스터되지 않은 환경에서 배달 그룹을 사용하는 경우 배달 그룹이 활성화될 때마다 MDB가 활성화됩니다.

전송 그룹을 Singleton 프로바이더와 함께 사용하는 경우 해당 노드에 배달 그룹이 활성화된 경우에만 Singleton 공급자 노드에서 MDB를 활성화할 수 있습니다. 그렇지 않으면 해당 노드에서 MDB가 비활성화되고 클러스터의 다른 모든 노드가 비활성화됩니다.

메시징 클러스터링 서버를 구성하고 코드 예제를 검토하는 방법에 대한 자세한 지침은 이 빠른 시작에 포함된 README.html 파일을 참조하십시오.

JBoss EAP 빠른 시작을 다운로드하고 사용하는 방법에 대한 자세한 내용은 JBoss EAP Getting Started Guide 의 빠른 시작 예제 사용 섹션을 참조하십시오.

4.3. Red Hat CodeReady Studio에서 Jakarta Messaging 기반 Message-Driven Bean 만들기

다음 절차에서는 Red Hat CodeReady Studio의 프로젝트에 Jakarta Messaging 기반 메시지 기반 빈을 추가하는 방법을 설명합니다. 이 절차에서는 주석을 사용하는 Jakarta Enterprise Beans 3.x 메시지 기반 빈을 생성합니다.

사전 요구 사항

  • Red Hat CodeReady Studio에 기존 프로젝트가 열려 있어야 합니다.
  • 빈이 수신 대기할 자카르타 메시징 대상의 이름과 유형을 알아야 합니다.
  • 자카르타 메시징에 대한 지원은 이 빈이 배포될 JBoss EAP 구성에서 활성화해야 합니다.

Red Hat CodeReady Studio에서 Jakarta Messaging 기반 Bean 추가

  1. Create EJB 3.x Message-Driven Bean 마법사를 엽니다.

    파일 → 새 → 기타 로 이동합니다. EJB/Message-Driven Bean(EJB 3.x) 을 선택하고 Next (다음) 버튼을 클릭합니다.

    그림 4.1. EJB 3.x 메시지 드라이브 빈 마법사 만들기

    EJB 3.x 메시지 드라이브 빈 마법사 만들기
  2. 클래스 파일 대상 세부 정보를 지정합니다.

    빈 클래스에 지정할 세 가지 세부 정보, 즉 project, Java class 및 message destination이 있습니다.

    • 프로젝트:

      • 작업 영역에 여러 프로젝트가 있는 경우 프로젝트 메뉴에서 올바른 프로젝트가 선택되어 있는지 확인합니다.
      • 새 빈에 대한 소스 파일이 생성되는 폴더는 선택한 프로젝트의 디렉터리에 ejbModule 입니다. 특정 요구 사항이 있는 경우에만 변경하십시오.
    • Java 클래스:

      • 필수 필드는 다음과 같습니다. Java 패키지클래스 이름.
      • 애플리케이션의 비즈니스 로직이 필요하지 않는 한 슈퍼 클래스를 제공할 필요는 없습니다.
    • 메시지 대상:

      • 자카르타 메시징 기반 메시지 기반 빈에 제공해야 하는 세부 사항은 다음과 같습니다.

        • 빈에서 응답할 메시지를 포함하는 대기열 또는 토픽 이름인 대상 이름입니다.
        • 기본적으로 JMS 확인란이 선택됩니다. 변경하지 마십시오.
        • 필요한 경우 Destination 유형을 Queue 또는 Topic 으로 설정합니다.

          Next (다음) 버튼을 클릭합니다.

  3. 메시지 기반 빈 특정 정보 입력.

    여기에서 기본값은 컨테이너 관리 트랜잭션을 사용하는 자카르타 메시징 기반 메시지 기반 빈에 적합합니다.

    • 빈이 빈 관리 트랜잭션을 사용하는 경우 트랜잭션 유형을 빈으로 변경합니다.
    • 클래스 이름과 다른 빈 이름이 필요한 경우 빈 이름을 변경합니다.
    • JMS 메시지 리스너 인터페이스가 이미 나열됩니다. 애플리케이션의 비즈니스 로직에 고유한 인터페이스를 추가하거나 제거할 필요가 없습니다.
    • 메서드 스텁을 만들기 위한 확인란을 선택한 상태로 둡니다.

      Finish(완료 ) 버튼을 클릭합니다.

결과

메시지 기반 빈은 기본 생성자 및 onMessage() 메서드를 위한 스텁 메서드로 생성됩니다. 해당 파일이 포함된 Red Hat CodeReady Studio 편집기 창이 열립니다.

4.4. jboss-ejb3.xml 에서 MDB 리소스 어댑터 지정

jboss-ejb3.xml 배포 설명자에서 사용할 MDB의 리소스 어댑터를 지정할 수 있습니다.

MDB에 jboss-ejb3.xml 에 리소스 어댑터를 지정하려면 다음 예제를 사용합니다.

예: jboss-ejb3.xml MDB 리소스 어댑터 구성

<jboss xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:jee="http://java.sun.com/xml/ns/javaee"
  xmlns:mdb="urn:resource-adapter-binding">
  <jee:assembly-descriptor>
    <mdb:resource-adapter-binding>
      <jee:ejb-name>MyMDB</jee:ejb-name>
      <mdb:resource-adapter-name>MyResourceAdapter.rar</mdb:resource-adapter-name>
    </mdb:resource-adapter-binding>
  </jee:assembly-descriptor>
</jboss>

EAR에 있는 리소스 어댑터의 경우 <mdb:resource-adapter-name> 에 대해 다음 구문을 사용해야 합니다.

  • 다른 EAR에 있는 리소스 어댑터의 경우:

    <mdb:resource-adapter-name>OtherDeployment.ear#MyResourceAdapter.rar</mdb:resource-adapter-name>
  • MDB와 동일한 EAR에 있는 리소스 어댑터의 경우 EAR 이름을 생략할 수 있습니다.

    <mdb:resource-adapter-name>#MyResourceAdapter.rar</mdb:resource-adapter-name>

4.5. 클러스터에 배포된 MDB에서 리소스 정의 주석 사용

@JMSConnectionFactoryDefinition@JMSDestinationDefinition 주석을 사용하여 메시지 기반 빈에 대한 연결 팩토리 및 대상을 생성하는 경우 오브젝트는 MDB가 배포된 서버에서만 생성됩니다. MDB를 클러스터의 모든 노드에도 배포하지 않는 한 클러스터의 모든 노드에서 생성되지 않습니다. 이러한 주석으로 구성된 개체는 MDB가 배포된 서버에서만 생성되므로 MDB에서 원격 서버에서 메시지를 읽고 원격 서버로 전송하는 원격 Jakarta Connectors 토폴로지에 영향을 미칩니다.

4.6. 애플리케이션에서 자카르타 엔터프라이즈 빈 및 MDB 속성 대체 활성화

Red Hat JBoss Enterprise Application Platform을 사용하면 @ActivationConfigProperty 및 @ Resource 주석을 사용하여 Jakarta Enterprise Beans 및 MDB에서 속성 대체를 활성화할 수 있습니다. 속성 대체에는 다음과 같은 구성 및 코드 변경이 필요합니다.

다음 예제에서는 속성 대체를 사용하기 위해 JBoss EAP와 함께 제공되는 helloworld-mdb 빠른 시작을 수정하는 방법을 보여줍니다. 완료된 작업 예는 helloworld-mdb-propertysubstitution 빠른 시작을 참조하십시오.

4.6.1. 속성 대체를 사용하도록 서버 설정

JBoss EAP 서버에서 속성 대체를 활성화하려면 서버 구성의 하위 시스템에서 annotation-property-replacement 속성을 true 로 설정해야 합니다.

  1. 서버 구성 파일을 백업합니다.

    helloworld-mdb-propertysubstitution 빠른 시작 예제에서는 독립 실행형 서버에 대한 전체 프로필이 필요하므로 이 예제는 EAP_HOME/standalone/configuration/standalone-full.xml 파일입니다. 관리형 도메인에서 서버를 실행하는 경우 EAP_HOME/domain/configuration/domain.xml 파일입니다.

  2. JBoss EAP 설치 디렉터리로 이동하고 full 프로필로 서버를 시작합니다.

    $ EAP_HOME/bin/standalone.sh -c standalone-full.xml
    참고

    Windows Server의 경우 EAP_HOME\bin\standalone.bat 스크립트를 사용합니다.

  3. 관리 CLI를 시작합니다.

    $ EAP_HOME/bin/jboss-cli.sh --connect
    참고

    Windows Server의 경우 EAP_HOME\bin\jboss-cli.bat 스크립트를 사용합니다.

  4. 다음 명령을 입력하여 주석 속성 대체를 활성화합니다.

    /subsystem=ee:write-attribute(name=annotation-property-replacement,value=true)

    다음 결과가 표시됩니다.

    {"outcome" => "success"}
  5. JBoss EAP 서버 구성 파일의 변경 사항을 검토합니다. 이제 The ee 하위 시스템에 다음 XML이 포함되어야 합니다.

    예제 하위 시스템 구성

    <subsystem xmlns="urn:jboss:domain:ee:4.0">
      ...
      <annotation-property-replacement>true</annotation-property-replacement>
      ...
    </subsystem>

4.6.2. 시스템 속성 정의

서버 구성 파일에서 시스템 속성을 지정하거나 JBoss EAP 서버를 시작할 때 명령줄 인수로 전달할 수 있습니다. 서버 구성 파일에 정의된 시스템 속성이 서버를 시작할 때 명령줄에서 전달된 값보다 우선합니다.

4.6.2.1. 서버 구성에서 시스템 속성 정의

  1. 관리 CLI를 시작합니다.
  2. 다음 명령 구문을 사용하여 JBoss EAP 서버에서 시스템 속성을 구성합니다.

    시스템 속성 추가 구문

    /system-property=PROPERTY_NAME:add(value=PROPERTY_VALUE)

    다음 시스템 속성은 helloworld-mdb-propertysubstitution 빠른 시작에 대해 구성됩니다.

    시스템 속성을 추가하는 명령 예

    /system-property=property.helloworldmdb.queue:add(value=java:/queue/HELLOWORLDMDBPropQueue)
    /system-property=property.helloworldmdb.topic:add(value=java:/topic/HELLOWORLDMDBPropTopic)
    /system-property=property.connection.factory:add(value=java:/ConnectionFactory)

  3. JBoss EAP 서버 구성 파일의 변경 사항을 검토합니다. 이제 <extensions> 뒤에 다음 시스템 속성이 표시되어야 합니다.

    시스템 속성 구성 예

    <system-properties>
        <property name="property.helloworldmdb.queue" value="java:/queue/HELLOWORLDMDBPropQueue"/>
        <property name="property.helloworldmdb.topic" value="java:/topic/HELLOWORLDMDBPropTopic"/>
        <property name="property.connection.factory" value="java:/ConnectionFactory"/>
    </system-properties>

4.6.2.2. 서버 시작 시 시스템 속성을 인수로 전달

원하는 경우 -DPROPERTY_NAME =PROPERTY_VALUE 형식으로 JBoss EAP 서버를 시작할 때 명령줄에서 인수를 전달할 수 있습니다. 다음은 이전 섹션에서 정의한 시스템 속성에 대한 인수를 전달하는 방법의 예입니다.

시스템 속성을 통과하는 서버 시작 명령 예

$ EAP_HOME/bin/standalone.sh -c standalone-full.xml  -Dproperty.helloworldmdb.queue=java:/queue/HELLOWORLDMDBPropQueue  -Dproperty.helloworldmdb.topic=java:/topic/HELLOWORLDMDBPropTopic  -Dproperty.connection.factory=java:/ConnectionFactory

4.6.3. 시스템 속성 대체를 사용하도록 애플리케이션 코드 수정

하드 코딩된 @ActivationConfigProperty@Resource 주석 값을 새로 정의된 시스템 속성의 대체로 바꿉니다. 다음은 새로 정의된 시스템 속성 대체를 사용하도록 helloworld-mdb 빠른 시작을 변경하는 방법의 예입니다.

  1. 시스템 속성에 대체를 사용하도록 HelloWorldQueueMDB 클래스에서 @ActivationConfigProperty 대상 속성 값을 변경합니다. 이제 @MessageDriven 주석이 다음과 같이 표시됩니다.

    HelloWorldQueueMDB 코드 예

    @MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "${property.helloworldmdb.queue}"),
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })

  2. 시스템 속성에 대체를 사용하도록 HelloWorldTopicMDB 클래스에서 @ActivationConfigProperty 대상 속성 값을 변경합니다. 이제 @MessageDriven 주석이 다음과 같이 표시됩니다.

    HelloWorldTopicMDB Code Example

    @MessageDriven(name = "HelloWorldQTopicMDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "${property.helloworldmdb.topic}"),
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })

  3. 시스템 속성 대체를 사용하도록 HelloWorldMDBServletClient 클래스에서 @Resource 주석을 변경합니다. 이제 코드는 다음과 같아야 합니다.

    HelloWorldMDBServletClient 코드 예

    /**
     * Definition of the two Jakarta Messaging Service destinations used by the quickstart
     * (one queue and one topic).
     */
     @JMSDestinationDefinitions(
         value = {
             @JMSDestinationDefinition(
                 name = "java:/${property.helloworldmdb.queue}",
                 interfaceName = "javax.jms.Queue",
                 destinationName = "HelloWorldMDBQueue"
             ),
             @JMSDestinationDefinition(
                 name = "java:/${property.helloworldmdb.topic}",
                 interfaceName = "javax.jms.Topic",
                 destinationName = "HelloWorldMDBTopic"
             )
         })
    /**
     * <p>
     * A simple servlet 3 as client that sends several messages to a queue or a topic.
     * </p>
     *
     * <p>
     * The servlet is registered and mapped to /HelloWorldMDBServletClient using the {@linkplain WebServlet
     * @HttpServlet}.
     * </p>
     *
     * @author Serge Pagop (spagop@redhat.com)
     *
     */
    @WebServlet("/HelloWorldMDBServletClient")
    public class HelloWorldMDBServletClient extends HttpServlet {
    
        private static final long serialVersionUID = -8314035702649252239L;
    
        private static final int MSG_COUNT = 5;
    
        @Inject
        private JMSContext context;
    
        @Resource(lookup = "${property.helloworldmdb.queue}")
        private Queue queue;
    
        @Resource(lookup = "${property.helloworldmdb.topic}")
        private Topic topic;
    
      <!-- Remainder of code can be found in the `helloworld-mdb-propertysubstitution` quickstart. -->

  4. 시스템 속성 대체 값을 사용하도록 the activemq-jms.xml 파일을 수정합니다.

    예: .activemq-jms.xml 파일

    <?xml version="1.0" encoding="UTF-8"?>
    <messaging-deployment xmlns="urn:jboss:messaging-activemq-deployment:1.0">
        <server>
             <jms-destinations>
                <jms-queue name="HELLOWORLDMDBQueue">
                    <entry name="${property.helloworldmdb.queue}"/>
                </jms-queue>
                <jms-topic name="HELLOWORLDMDBTopic">
                    <entry name="${property.helloworldmdb.topic}"/>
                </jms-topic>
            </jms-destinations>
        </server>
    </messaging-deployment>

  5. 애플리케이션을 배포합니다. 애플리케이션에서 @Resource 및 @ ActivationConfigProperty 속성 값에 대해 시스템 속성에 지정된 값을 사용합니다.

4.7. 활성화 구성 속성

4.7.1. 주석을 사용하여 MDB 구성

@ ActivationConfigProperty 주석에 해당하는 @MessageDriven 요소 및 하위 항목을 사용하여 활성화 속성을 구성할 수 있습니다. @ActivationConfigProperty 는 MDB의 활성화 구성 속성 배열입니다. @ActivationConfigProperty 주석 사양은 다음과 같습니다.

@Target(value={})
@Retention(value=RUNTIME)
public @interface ActivationConfigProperty
{
	String propertyName();
	String propertyValue();
}

@ActivationConfigProperty표시 예

@MessageDriven(name="MyMDBName",
activationConfig =
{
    @ActivationConfigProperty(propertyName="destinationLookup",propertyValue="queueA"),
    @ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
})

4.7.2. 배포 설명자를 사용하여 MDB 구성

ejb -jar.xml의 <message- driven> 요소는 빈을 MDB로 정의합니다. <activation-config> 및 요소에는 activation-config-property 요소를 통해 MDB 구성이 포함됩니다.

ejb-jar.xml

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.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-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
               version="3.1">
    <enterprise-beans>
        <message-driven>
            <ejb-name>MyMDBName</ejb-name>
            <ejb-class>org.jboss.tutorial.mdb_deployment_descriptor.bean.MyMDBName</ejb-class>
            <activation-config>
                <activation-config-property>
                    <activation-config-property-name>destinationLookup</activation-config-property-name>
                    <activation-config-property-value>queueA</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>destinationType</activation-config-property-name>
                    <activation-config-property-value>javax.jms.Queue</activation-config-property-value>
                </activation-config-property>
                <activation-config-property>
                    <activation-config-property-name>acknowledgeMode</activation-config-property-name>
                    <activation-config-property-value>Auto-acknowledge</activation-config-property-value>
                </activation-config-property>
            </activation-config>
        </message-driven>
    <enterprise-beans>
</jboss:ejb-jar>

표 4.1. 자카르타 메시징 서비스 사양에 정의된 활성화 구성 속성

이름설명

destinationLookup

대기열 또는 항목의 Java 네이밍 및 디렉터리 인터페이스 이름입니다. 필수 값입니다.

connectionFactoryLookup

엔드포인트에서 메시지를 수신하는 데 사용되는 관리적으로 정의된 javax.jms.ConnectionFactory, javax.jms.Queue ConnectionFactory 또는 javax.jms.TopicConnectionFactory 오브젝트의 조회 이름입니다.

명시적으로 정의되지 않은 경우 name activemq-ra 를 사용하여 풀링된 연결 팩토리가 사용됩니다.

destinationType

대상 유효한 값은 javax.jms.Queue 또는 javax.jms.Topic 입니다. 필수 값입니다.

messageSelector

messageSelector 속성의 값은 사용 가능한 메시지의 하위 집합을 선택하는 데 사용되는 문자열입니다. 구문은 SQL 92 조건부 표현식 구문의 하위 집합을 기반으로 하며 Jakarta Messaging 사양에 자세히 설명되어 있습니다. ActivationSpec JavaBean에서 messageSelector 속성의 값을 지정하는 것은 선택 사항입니다.

acknowledgeMode

트랜잭션된 자카르타 메시징을 사용하지 않는 경우 승인 유형입니다. 유효한 값은 Auto-acknowledge 또는 Dups-ok-acknowledge 입니다. 필수 값이 아닙니다.

기본값은 Auto-acknowledge 입니다.

clientID

연결의 클라이언트 ID입니다. 필수 값이 아닙니다.

subscriptionDurability

토픽 서브스크립션이 지속적인지 여부. 유효한 값은 Durable 또는 NonDurable 입니다. 필수 값이 아닙니다.

기본값은 NonDurable 입니다.

subscriptionName

서브스크립션 항목의 서브스크립션 이름입니다. 필수 값이 아닙니다.

표 4.2. JBoss EAP에서 정의한 활성화 구성 속성

이름설명

대상

useJNDI=true 와 함께 이 속성을 사용하는 것은 destinationLookup 과 동일합니다. useJNDI=false 와 함께 사용하면 대상이 조회되지 않지만 인스턴스화됩니다. destinationLookup 대신 이 속성을 사용할 수 있습니다. 필수 값이 아닙니다.

shareSubscriptions

서브스크립션을 공유하도록 연결이 구성되었는지 여부.

기본값은 False 입니다.

user

자카르타 메시징 연결 사용자입니다. 필수 값이 아닙니다.

password

Jakarta Messaging 연결의 암호입니다. 필수 값이 아닙니다.

maxSession

사용할 최대 동시 세션 수입니다. 필수 값이 아닙니다.

기본값은 15 입니다.

transactionTimeout

세션의 트랜잭션 시간 초과(밀리초)입니다. 필수 값이 아닙니다.

지정하지 않으면 속성이 무시되고 transactionTimeout 이 재정의되지 않고 트랜잭션 관리자에 정의된 기본 transactionTimeout 이 사용됩니다.

useJNDI

Java 네이밍 및 디렉터리 인터페이스를 사용하여 대상을 조회하는지 여부.

기본값은 True 입니다.

jndiParams

연결에 사용할 Java Naming 및 Directory Interface 매개변수입니다. 매개변수는 다음과 같이 구분된 name=value 쌍으로 정의됩니다 .

localTx

XA 대신 로컬 트랜잭션을 사용합니다.

기본값은 False 입니다.

setupAttempts

자카르타 메시징 연결을 설정하려는 시도 수입니다. 자카르타 메시징 리소스를 사용하기 전에 MDB를 배포할 수 있습니다. 이 경우 리소스 어댑터는 리소스를 사용할 수 있을 때까지 여러 번 설정하려고 합니다. 이는 인바운드 연결에만 적용됩니다.

기본값은 -1 입니다.

setupInterval

자카르타 메시징 연결을 설정하기 위한 연속 시도 사이의 간격(밀리초)입니다. 이는 인바운드 연결에만 적용됩니다.

기본값은 2000 입니다.

rebalanceConnections

인바운드 커넥션 리밸런싱이 활성화되었는지 여부입니다. 이 매개변수를 사용하면 기본 클러스터 토폴로지가 변경될 때 인바운드 연결을 재조정할 수 있습니다.

아웃바운드 연결에 대한 리밸런싱이 없습니다.

기본값은 False 입니다.

deserializationWhiteList

신뢰할 수 있는 클래스 및 패키지 목록인 화이트 목록에 대한 쉼표로 구분된 항목 목록입니다. 이 속성은 목록의 개체를 역직렬화하기 위해 Jakarta Messaging 리소스 어댑터에서 사용합니다.

자세한 내용은 Configuring Messaging ObjectMessage Deserialization in Configuring Messaging for JBoss EAP에서 Controlling Jakarta Messaging ObjectMessage Deserialization을 참조하십시오.

deserializationBlackList

블랙 목록에 대한 쉼표로 구분된 항목 목록입니다. 이는 신뢰할 수 없는 클래스 및 패키지 목록입니다. 이 속성은 목록의 개체가 역직렬화되지 않도록 Jakarta Messaging 리소스 어댑터에서 사용합니다.

자세한 내용은 Configuring Messaging ObjectMessage Deserialization in Configuring Messaging for JBoss EAP에서 Controlling Jakarta Messaging ObjectMessage Deserialization을 참조하십시오.

4.7.3. MDB 구성을 위한 몇 가지 예제 사용 사례

  • 메시지를 수신하는 MDB 사용 사례

    MDB에서 메시지를 수신할 때 기본 시나리오는 JBoss EAP와 함께 제공되는 helloworld-mdb 빠른 시작을 참조하십시오.

  • MDB에서 메시지를 전송하는 사용 사례

    메시지를 처리한 후 다른 비즈니스 시스템에 문의하거나 메시지에 회신해야 할 수도 있습니다. 이 경우 아래 코드 조각과 같이 MDB에서 메시지를 전송할 수 있습니다.

    package org.jboss.as.quickstarts.mdb;
    
    import javax.annotation.Resource;
    import javax.ejb.ActivationConfigProperty;
    import javax.ejb.MessageDriven;
    import javax.inject.Inject;
    import javax.jms.JMSContext;
    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.Queue;
    
    @MessageDriven(name = "MyMDB", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queue/MyMDBRequest"),
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
    public class MyMDB implements MessageListener {
    
        @Inject
        private JMSContext jmsContext;
    
        @Resource(lookup = "java:/queue/ResponseDefault")
        private Queue defaultDestination;
    
        /**
         * @see MessageListener#onMessage(Message)
         */
        public void onMessage(Message rcvMessage) {
            try {
                Message response = jmsContext.createTextMessage("Response for message " + rcvMessage.getJMSMessageID());
                if (rcvMessage.getJMSReplyTo() != null) {
                    jmsContext.createProducer().send(rcvMessage.getJMSReplyTo(), response);
                } else {
                    jmsContext.createProducer().send(defaultDestination, response);
                }
            } catch (JMSException e) {
                throw new RuntimeException(e);
            }
        }
    }

    위의 예에서 MDB는 메시지를 수신한 후 JMSReplyTo 에 지정된 대상 또는 Java Naming 및 Directory Interface name java:/queue/ResponseDefault 에 바인딩된 대상에 응답합니다.

  • 인바운드 연결 재조정을 구성하는 MDB 사용 사례

    @MessageDriven(name="MyMDBName",
        activationConfig =
        {
            @ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queueA"),
            @ActivationConfigProperty(propertyName = "rebalanceConnections", propertyValue = "true")
        }
    )

5장. 세션 빈 호출

5.1. Jakarta Enterprise Beans 클라이언트 컨텍스트 정보

JBoss EAP는 원격 Jakarta Enterprise Beans 호출을 관리하기 위한 Jakarta Enterprise Beans 클라이언트 API를 도입했습니다. JBoss Jakarta Enterprise Beans 클라이언트 API는 하나 이상의 스레드에서 동시에 연결 및 사용할 수 있는 EJBClientContext를 사용합니다. 즉 EJBClientContext에는 다수의 Jakarta Enterprise Beans 수신자가 포함될 수 있습니다. Jakarta Enterprise Beans 수신자는 Jakarta Enterprise Beans 호출을 처리할 수 있는 서버와 통신하는 방법을 아는 구성 요소입니다. 일반적으로 Jakarta Enterprise Bean 원격 애플리케이션은 다음과 같이 분류할 수 있습니다.

  • 독립 실행형 Java 애플리케이션으로 실행되는 원격 클라이언트.
  • 다른 JBoss EAP 인스턴스 내에서 실행되는 원격 클라이언트.

원격 클라이언트 유형에 따라 Jakarta Enterprise Beans 클라이언트 API 관점에서 JVM 내에 둘 이상의 EJBClientContext가 있을 수 있습니다.

독립 실행형 애플리케이션에는 일반적으로 다수의 Jakarta Enterprise Beans 수신자가 지원할 수 있는 단일 EJBClientContext가 있지만 필수는 아닙니다. 독립 실행형 애플리케이션에 EJBClientContext가 두 개 이상 있는 경우 Jakarta Enterprise Beans 클라이언트 컨텍스트 선택기가 적절한 컨텍스트를 반환합니다.

다른 JBoss EAP 인스턴스 내에서 실행되는 원격 클라이언트의 경우 배포된 각 애플리케이션에 해당하는 Jakarta Enterprise Beans 클라이언트 컨텍스트가 있습니다. 해당 애플리케이션이 다른 Jakarta Enterprise Beans를 호출할 때마다 해당 Jakarta Enterprise Beans 클라이언트 컨텍스트를 사용하여 올바른 Jakarta Enterprise Beans 수신자를 찾아 호출을 처리합니다.

5.2. 원격 자카르타 엔터프라이즈 빈 클라이언트 사용

5.2.1. 초기 컨텍스트 조회

초기 컨텍스트를 생성할 때 PROVIDER_URL 속성을 사용하여 원격 서버의 주소를 전달할 수 있습니다.

public class Client {
    public static void main(String[] args)
            throws NamingException, PrivilegedActionException, InterruptedException {
        InitialContext ctx = new InitialContext(getCtxProperties());
        String lookupName = "ejb:/server/HelloBean!ejb.HelloBeanRemote";
        HelloBeanRemote bean = (HelloBeanRemote)ctx.lookup(lookupName);
        System.out.println(bean.hello());
        ctx.close();
    }
    public static Properties getCtxProperties() {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, WildFlyInitialContextFactory.class.getName());
        props.put(Context.PROVIDER_URL, "remote+http://127.0.0.1:8080");
        props.put(Context.SECURITY_PRINCIPAL, "joe");
        props.put(Context.SECURITY_CREDENTIALS, "joeIsAwesome2013!");
        return props;
    }
}
참고

조회에 사용할 초기 컨텍스트 팩토리는 org.wildfly.naming.client.WildFlyInitialContextFactory 입니다.

5.2.2. 원격 자카르타 엔터프라이즈 빈 구성 파일

JBoss EAP에는 Elytron 보안 프레임워크가 포함되어 있습니다. 클라이언트 애플리케이션 클래스 경로의 META-INF/ 디렉터리에 있는 The wildfly- config.xml 파일은 Elytron 보안 프레임워크 및 Jakarta Enterprise Beans 클라이언트 구성에 대한 광범위한 인증 및 권한 부여 옵션을 허용합니다.

<configuration>
   <authentication-client xmlns="urn:elytron:client:1.2">
      <authentication-rules>
         <rule use-configuration="default" />
      </authentication-rules>
      <authentication-configurations>
         <configuration name="default">
            <sasl-mechanism-selector selector="DIGEST-MD5" />
            <set-user-name name="admin" />
            <credentials>
               <clear-password password="password123!" />
            </credentials>
         </configuration>
      </authentication-configurations>
   </authentication-client>
   <jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0">
      <connections>
         <connection uri="remote+http://127.0.0.1:8080" />
      </connections>
   </jboss-ejb-client>
</configuration>

초기 컨텍스트에서 PROVIDER_URL,SECURITY_PRINCIPALSECURITY_CREDENTIALS 매개변수를 포함하는 대신 <connection-uri> 및 < authentication-client> 요소를 각각 wildfly-config.xml 파일에 사용하여 연결 URI와 보안 설정을 구성할 수 있습니다.

5.2.3. ClientTransaction 주석

@org.jboss.ejb.client.annotation.ClientTransaction 주석은 자카르타 엔터프라이즈 빈 클라이언트의 트랜잭션 전파를 처리합니다. 클라이언트에 트랜잭션이 없는 경우 전파가 실패하도록 지시하거나 클라이언트가 하나의 활성 상태인 경우에도 트랜잭션 전파를 방지할 수 있습니다. org.jboss.ejb.client.annotation.ClientTransactionPolicy 인터페이스의 상수를 사용하여 ClientTransaction 주석의 정책을 제어할 수 있습니다. 다음은 org.jboss.ejb.client.annotation.ClientTransactionPolicy 인터페이스의 상수입니다.

  • 필수 항목: 클라이언트측 트랜잭션 컨텍스트가 없는 경우 예외적으로 실패합니다. 클라이언트 측 트랜잭션 컨텍스트가 존재하면 전파됩니다.
  • NEVER: 트랜잭션 컨텍스트를 전파하지 않고 호출합니다. 클라이언트 측 트랜잭션 컨텍스트가 있는 경우 예외가 발생합니다.
  • NOT_SUPPORTED: 클라이언트 측 트랜잭션 컨텍스트가 있는지 여부에 관계없이 트랜잭션 컨텍스트를 전파하지 않고 를 호출합니다.
  • 지원: 클라이언트측 트랜잭션 컨텍스트가 없는 경우 트랜잭션 없이 을 호출하고, 클라이언트 측 트랜잭션 컨텍스트가 있는 경우 전파합니다.

주석이 없으면 기본 정책은 org.jboss.ejb.client.annotation.ClientTransactionPolicy#SUPPORTS 입니다. 이는 트랜잭션이 존재하는 경우 트랜잭션이 전파되지만 트랜잭션이 있는지 여부에 관계없이 전파가 실패하지 않습니다.

@ClientTransaction(ClientTransactionPolicy.MANDATORY)
@Remote
public interface RemoteCalculator  {
   public void callRemoteEjb() { }
}
@Stateless
@Remote(RemoteCalculator.class)
public class CalculatorBean implements RemoteCalculator {

   @Override
   public void callRemoteEjb()  {   }
}

이 주석을 사용하면 원격 인터페이스 프로바이더에서 원격 인터페이스 소비자에게 메서드에 트랜잭션이 필요한지 여부를 알릴 수 있습니다.

5.3. 원격 자카르타 엔터프라이즈 빈 데이터 압축

Enterprise Beans 프로토콜 메시지가 포함된 메시지 스트림을 압축할 수 있습니다.

참고

현재 압축은 클라이언트와 서버측에 있어야 하는 Jakarta Enterprise Beans 인터페이스의 주석으로만 지정할 수 있습니다. 현재 압축 힌트를 지정하는 데 해당하는 XML이 없습니다.

데이터 압축 힌트는 JBoss 주석 org.jboss.ejb.client.annotation.CompressionHint 를 통해 지정할 수 있습니다. 힌트 값은 요청, 응답 또는 요청 및 응답을 압축할지 여부를 지정합니다. @CompressionHint 를 추가하는 기본값은 compressResponse=truecompressRequest=true 입니다.

인터페이스 수준에서 주석을 지정하여 다음과 같은 Jakarta Enterprise Beans 인터페이스의 모든 메서드에 적용할 수 있습니다.

import org.jboss.ejb.client.annotation.CompressionHint;

@CompressionHint(compressResponse = false)
public interface ClassLevelRequestCompressionRemoteView {
    String echo(String msg);
}

또는 주석은 다음과 같은 Jakarta Enterprise Beans 인터페이스의 특정 메서드에 적용할 수 있습니다.

import org.jboss.ejb.client.annotation.CompressionHint;

public interface CompressableDataRemoteView {

    @CompressionHint(compressResponse = false, compressionLevel = Deflater.BEST_COMPRESSION)
    String echoWithRequestCompress(String msg);

    @CompressionHint(compressRequest = false)
    String echoWithResponseCompress(String msg);

    @CompressionHint
    String echoWithRequestAndResponseCompress(String msg);

    String echoWithNoCompress(String msg);
}

위에 표시된 compressedLevel 설정은 다음과 같은 값을 가질 수 있습니다.

  • BEST_COMPRESSION
  • BEST_SPEED
  • DEFAULT_COMPRESSION
  • NO_COMPRESSION

compressionLevel 설정은 기본적으로 Deflater.DEFAULT_COMPRESSION 입니다.

메서드 수준 덮어쓰기가 있는 클래스 수준 주석은 다음과 같습니다.

@CompressionHint
public interface MethodOverrideDataCompressionRemoteView {

    @CompressionHint(compressRequest = false)
    String echoWithResponseCompress(final String msg);

    @CompressionHint(compressResponse = false)
    String echoWithRequestCompress(final String msg);

    String echoWithNoExplicitDataCompressionHintOnMethod(String msg);
}

클라이언트 측에서 org.jboss.ejb.client.view.annotation.scan.enabled 시스템 속성이 true 로 설정되어 있는지 확인합니다. 이 속성은 JBoss Jakarta Enterprise Beans Client에 주석을 스캔하도록 지시합니다.

5.4. Jakarta Enterprise Cryostats 클라이언트 상호 운용성 전환

원격 Jakarta Enterprise Cryostats 클라이언트 애플리케이션은 서버에 연결하기 위해 원격 하위 시스템에 정의된 커넥터를 사용합니다. 요구 사항에 따라 다음 커넥터 중 하나를 사용할 수 있습니다.

  • HTTP-connector: 기본 포트 8080으로 undertow 의 HTTP 업그레이드 기능을 통해 서버에 대한 클라이언트 연결을 지원합니다. 이 커넥터가 구성된 경우 클라이언트는 암호화되지 않은 연결에 remote+http URI 스키마를 사용하거나 암호화된 연결에 대해 remote+https URI 체계를 사용합니다.
  • 커넥터: 레거시 원격 URI 체계를 통해 서버에 대한 클라이언트 연결을 지원합니다. 이 커넥터는 이전 Jakarta Enterprise Cryostat 클라이언트 애플리케이션에서 사용하기에 적합합니다.
참고

이전 리모팅 기반 커넥터를 사용하는 것 외에도 Jakarta Enterprise Cryostats 클라이언트는 http URI 체계를 사용하여 undertow 및 HTTP 프로토콜을 통해 서버에 연결할 수 있습니다. 자세한 내용은 Jakarta Enterprise Cryostats Invocation Over HTTP 를 참조하십시오.

기본 HTTP 커넥터

기본 커넥터는 http-connector 로, 클라이언트가 URI 스키마 remote+http 또는 remote+https 를 사용해야 합니다. 기본 원격 연결 포트는 8080 입니다. 이 포트는 undertow 의 기본 포트와 동일합니다. 다음 예제에서는 jboss- Cryostat-client 속성 파일을 보여줍니다.

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

다른 JBoss EAP 버전의 클라이언트 지원

클라이언트 애플리케이션이 JBoss EAP 6의 Jakarta Enterprise Cryostats 클라이언트 라이브러리를 사용하고 JBoss EAP 7 서버에 대한 연결이 필요한 경우 8080 이외의 포트에 원격 커넥터를 노출하도록 서버를 구성해야 합니다. 그런 다음 클라이언트는 새로 구성된 커넥터를 사용하여 연결해야 합니다.

JBoss EAP 7의 Jakarta Enterprise Cryostats 클라이언트 라이브러리를 사용하고 JBoss EAP 6 서버에 연결해야 하는 클라이언트 애플리케이션은 서버 인스턴스에서 remoting http-remoting 커넥터를 사용하지 않고 리모팅 커넥터를 사용해야 합니다. 이를 위해 다음과 같은 새 클라이언트 측 연결 속성을 정의합니다.

remote.connection.default.protocol=remote

자카르타 Enterprise Cryostats 클라이언트 애플리케이션에 대한 여러 커넥터 지원

JBoss EAP 7.4 이전에는 Jakarta Enterprise Cryostats 클라이언트 애플리케이션이 리모팅 하위 시스템에 정의된 하나의 리모팅 커넥터만 사용하여 서버에 연결할 수 있도록 제한되었습니다. 이 커넥터는 Cryostat 3 하위 시스템의 원격 요소의 connector-ref 특성에 지정되었습니다. 기본 http-connector 를 사용하여 undertow 의 HTTP 업그레이드 기능을 통해 remote+http 프로토콜을 사용하거나 기존 원격 프로토콜을 통해 연결을 제공하기 위해 레거시 커넥터 를 사용할 수 있습니다.

JBoss EAP 7.4를 사용하면 Jakarta Enterprise Cryostats 클라이언트가 연결을 위해 사용할 수 있는 커넥터 목록을 지정할 수 있습니다. 이 목록을 지정하려면 원격 요소의 새 커넥터 특성을 사용합니다. connector 속성은 원격 하위 시스템에 정의된 커넥터 목록을 허용합니다. 이를 통해 단일 서버에서 Jakarta Enterprise Cryostats 클라이언트 애플리케이션에 여러 연결을 제공할 수 있습니다. 예를 들어 EAP 7.2 이상과 호환되는 클라이언트는 이전 버전의 EAP 7.2와 호환되는 레거시 클라이언트 및 이전 버전의 EAP 7.2와 호환되는 레거시 클라이언트가 커넥터와 함께 기존 원격 프로토콜을 사용하여 연결할 수 있는 remote +http 프로토콜을 사용하여 서버에 연결할 수 있습니다.

예제

legacy-remoting-connector 가 remoting 하위 시스템에 정의된 커넥터 임을 고려할 때 다음 예제는 쓰기 속성을 사용하여 원격 커넥터의 값을 업데이트하는 Cryostat 3 하위 시스템 구성을 보여줍니다.

/subsystem=ejb3/service=remote:write-attribute(name=connectors, value=[http-remoting-connector, legacy-remoting-connector])

domain.xml 또는 standalone.xml 파일을 보고 Cryostat 3 하위 시스템에서 구성된 원격 커넥터를 확인할 수 있습니다.

<remote cluster="ejb" connectors="http-remoting-connector legacy-remoting-connector" thread-pool-name="default">
  <channel-creation-options>
   <option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
  </channel-creation-options>
</remote>
참고

Jakarta Enterprise Beans 원격 호출은 JBoss EAP 7에서 JBoss EAP 6에서만 지원됩니다.

상호 운용성을 원격하는 Jakarta Enterprise Beans 외에도 다음 옵션을 사용하여 기존 클라이언트에 연결할 수 있습니다.

  • JBoss EAP 구성 가이드에서 JTS 트랜잭션의 ORB를 구성합니다.

5.5. 원격 자카르타 엔터프라이즈 빈 호출을 위한 IIOP 구성

JBoss EAP는 JBoss EAP에 배포된 Jakarta Enterprise Beans에 대한 CORBA/IIOP 기반 액세스를 지원합니다.

<iiop> 요소는 Jakarta Enterprise Bean의 IIOP, CORBA, 호출을 활성화하는 데 사용됩니다. 이 요소가 있다는 것은 iiop-openjdk 하위 시스템이 설치되어 있음을 의미합니다. <iiop> 요소에는 다음 두 가지 특성이 포함되어 있습니다.

  • enable-by-default: 이것이 사실이라면 Enterprise Beans 2.x를 사용하는 모든 Jakarta Enterprise Beans 홈 인터페이스가 IIOP를 통해 노출됩니다. 그렇지 않으면 jboss-ejb3.xml 을 통해 명시적으로 활성화해야 합니다.
  • use-qualified-name: 이 경우 Jakarta Enterprise Beans는 myear/myejbjar/MyBean 과 같은 배포의 애플리케이션 및 모듈 이름이 포함된 바인딩 이름을 사용하여 CORBA 명명 컨텍스트에 바인딩됩니다. false인 경우 기본 바인딩 이름은 단순히 빈 이름입니다.
참고

일반적으로 Jakarta Enterprise Beans 3 원격 호출에는 원격 액세스 인터페이스가 필요하지 않지만 IIOP를 사용하여 노출되는 Jakarta Enterprise Beans 3 빈에는 필요합니다. jboss-ejb3.xml 파일을 사용하거나 standalone-full.xml 구성 파일에서 모든 Jakarta Enterprise Beanss에 대해 IIOP를 활성화해야 합니다.

IIOP 활성화

IIOP를 활성화하려면 IIOP OpenJDK ORB 하위 시스템이 설치되어 있어야 하고, <iiop/> 요소가 ejb3 하위 시스템 구성에 있어야 합니다. 배포와 함께 제공되는 standalone-full.xml 구성에는 이러한 두 가지 구성이 모두 활성화되어 있습니다.

IIOP는 서버 구성 파일의 iiop-openjdk 하위 시스템에서 구성됩니다.

<subsystem xmlns="urn:jboss:domain:iiop-openjdk:2.1">

다음 관리 CLI 명령을 사용하여 iiop-openjdk 하위 시스템에 액세스하고 업데이트합니다.

/subsystem=iiop-openjdk

IIOP 요소는 서버의 기본 동작을 제어하는 두 개의 특성을 사용합니다.

<subsystem xmlns="urn:jboss:domain:ejb3:5.0">
  ...
  <iiop enable-by-default="false" use-qualified-name="false"/>
  ...
</subsystem>

다음 관리 CLI 명령은 ejb3 하위 시스템 아래에 <iiop> 요소를 추가합니다.

/subsystem=ejb3/service=iiop:add(enable-by-default=false, use-qualified-name=false)

IIOP를 사용하여 커뮤니티를 연결하는 자카르타 엔터프라이즈 빈 만들기

다음 예제에서는 클라이언트에서 원격 IIOP 호출을 생성하는 방법을 보여줍니다.

  1. 서버에 Enterprise Bean 2 빈을 생성합니다.

    @Remote(IIOPRemote.class)
    @RemoteHome(IIOPBeanHome.class)
    @Stateless
    public class IIOPBean {
        public String sayHello() throws RemoteException {
             return "hello";
        }
    }
  2. 필수 메서드 create() 가 있는 홈 구현을 만듭니다. 이 메서드는 클라이언트에서 비즈니스 메서드를 호출하기 위해 원격 인터페이스의 프록시를 가져오도록 호출합니다.

    public interface IIOPBeanHome extends EJBHome {
        public IIOPRemote create() throws RemoteException;
    }
  3. Enterprise Bean에 대한 원격 연결을 위한 원격 인터페이스를 생성합니다.

    public interface IIOPRemote extends EJBObject {
        String sayHello() throws RemoteException;
    }
  4. META-INF 에 설명자 파일 jboss-ejb3.xml 을 만들어 원격 호출을 위한 빈을 도입합니다.

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
                   xmlns="http://java.sun.com/xml/ns/javaee"
                   xmlns:iiop="urn:iiop"
                   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-ejb3-2_0.xsd
                      http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd
                      urn:iiop jboss-ejb-iiop_1_0.xsd"
                   version="3.1"
                   impl-version="2.0">
        <assembly-descriptor>
            <iiop:iiop>
                <ejb-name>*</ejb-name>
            </iiop:iiop>
        </assembly-descriptor>
    </jboss:ejb-jar>
    참고

    JAR 파일의 설명자와 함께 빈을 JBoss EAP 컨테이너에 배포할 준비가 되었습니다.

  5. 클라이언트 측에서 컨텍스트를 생성합니다.

    System.setProperty("com.sun.CORBA.ORBUseDynamicStub", "true");
    final Properties props = new Properties();
    props.put(Context.PROVIDER_URL, "corbaloc::localhost:3528/JBoss/Naming/root");
    props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.iiop.naming:org.jboss.naming.client");
    props.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");
    props.put(Context.OBJECT_FACTORIES, "org.jboss.tm.iiop.client.IIOPClientUserTransactionObjectFactory");
    참고

    클라이언트는 wildfly iiop openjdk 라이브러리를 클래스 경로에 추가해야 합니다. 또한 클라이언트는 org.wildfly:wildfly-iiop-openjdk 아티팩트를 Maven 종속성으로 추가해야 할 수도 있습니다.

  6. 컨텍스트 조회를 사용하여 IIOPBean 알아보려면 홈 인터페이스에 대한 참조를 좁힙니다. 그런 다음 홈 인터페이스 create() 메서드를 호출하여 원격 인터페이스에 액세스하여 메서드를 호출할 수 있습니다.

    try {
        Context context = new InitialContext(props);
    
        final Object iiopObj = context.lookup(IIOPBean.class.getSimpleName());
        final IIOPBeanHome beanHome = (IIOPBeanHome) PortableRemoteObject.narrow(iiopObj, IIOPBeanHome.class);
        final IIOPRemote bean = beanHome.create();
    
        System.out.println("Bean saying: " + bean.sayHello());
    } catch (Exception e) {
        e.printStackTrace();
    }

5.6. Jakarta Enterprise Beans 클라이언트 주소 구성

아래 예와 같이 SessionContext 인터페이스를 사용하여 Jakarta Enterprise Beans 클라이언트 주소를 확인할 수 있습니다.

public class HelloBean implements HelloBeanRemote {
    @Resource
    SessionContext ctx;
    private Long counter;
    public HelloBean() {
    }
    @PostConstruct
    public void init() {
        counter = 0L;
    }
    @Override
    @RolesAllowed("users")
    public String hello() {
        final String message = "method hello() invoked by user " + ctx.getCallerPrincipal().getName()
                + ", source addr = " +  ctx.getContextData().get("jboss.source-address").toString();
        System.out.println(message);
        return message;
    }
}

독립 실행형 클라이언트 구성

the wildfly -config.xml 파일에서 네임스페이스 urn:xnio:3.5 를 보유하는 작업자 요소 내에서 outbound-bind- addresses 요소를 구성할 수 있습니다. bind-address sub-element는 아래에 정의된 대로 bind -address,bind-port 속성을 사용합니다.

다음은 the wildfly-config.xml 파일을 사용하는 독립 실행형 클라이언트 구성의 예입니다.

<configuration>
    <worker xmlns="urn:xnio:3.5">
        <worker-name value="default"/>
        <outbound-bind-addresses>
            <bind-address bind-address=IP_ADDRESS_TO_BIND_TO bind-port=OPTIONAL_SOURCE_PORT_NUMBER match=CIDR_BLOCK />
        </outbound-bind-addresses>
    </worker>
</configuration>

outbound -bind-address 에는 다음 속성이 필요합니다.

  • match10.0.0.0/8,ff00::\8 ,0.0.0.0/0,::/0 과 같은 Classless Inter-Domain Routing(CIDR) 블록입니다.
  • bind-address 는 대상 주소가 match 매개변수에 지정된 CIDR 블록과 일치하는 경우 바인딩할 IP 주소를 지정합니다. CIDR 블록과 동일한 주소 제품군이어야 합니다.
  • bind-port 는 기본값이 0 인 선택적 소스 포트 번호입니다.

    일치하는 표현식이 없으면 아웃바운드 소켓은 명시적으로 바인딩되지 않습니다.

컨테이너 기반 구성

Jakarta Enterprise Beans 클라이언트 주소의 컨테이너 기반 구성은 the wildfly-config.xml 파일에 정의된 독립 실행형 클라이언트 구성과 유사합니다.

아래 예제에서는 ejb3 하위 시스템에서 기본적으로 사용하는 io 하위 시스템의 기본 worker 요소에 outbound -bind-address 를 구성합니다.

/subsystem=io/worker=default/outbound-bind-address=SPECIFY_OUTBOUND_BIND_ADDRESS:add(bind-address=IP_ADDRESS_TO_BIND_TO, bind-port=OPTIONAL_SOURCE_PORT_NUMBER, match=CIDR_BLOCK)

5.7. Jakarta Enterprise Beans Invocation over HTTP

HTTP에 대한 Jakarta Enterprise Beans 호출에는 클라이언트측 및 서버 측 구현의 두 가지 부분이 포함됩니다.

5.7.1. 클라이언트 측 구현

클라이언트 측 구현은 Undertow HTTP 클라이언트를 사용하여 서버를 호출하는 EJBReceiver 로 구성됩니다. 연결 관리는 연결 풀을 사용하여 자동으로 처리됩니다.

HTTP 전송을 사용하도록 Jakarta Enterprise Beans 클라이언트 애플리케이션을 구성하려면 HTTP 전송 구현에 다음 종속성을 추가해야 합니다.

<dependency>
    <groupId>org.wildfly.wildfly-http-client</groupId>
    <artifactId>wildfly-http-ejb-client</artifactId>
</dependency>

HTTP 호출을 수행하려면 http URL 스키마를 사용하고 HTTP 호출자( wildfly-services )의 컨텍스트 이름을 포함해야 합니다. 예를 들어 remote+http://localhost:8080 을 대상 URL로 사용하는 경우 HTTP 전송을 사용하려면 이를 http://localhost:8080/wildfly-services 로 업데이트해야 합니다.

5.7.2. 서버 측 구현

서버 측 구현은 들어오는 HTTP 요청을 처리하는 서비스로 구성되어 있으며, 해당 요청을 취소하고 결과를 내부 Jakarta Enterprise Beans 호출 코드로 전달합니다.

서버를 구성하려면 undertow 하위 시스템에서 사용하려는 각 가상 호스트에서 http-invoker 를 활성화해야 합니다. 이는 표준 구성에서 기본적으로 활성화되어 있습니다. 비활성화된 경우 다음 관리 CLI 명령을 사용하여 다시 활성화할 수 있습니다.

/subsystem=undertow/server=default-server/host=default-host/setting=http-invoker:add(http-authentication-factory=myfactory, path="wildfly-services")

HTTP-invoker 에는 두 가지 특성, 기본적으로 to wildfly-services 및 다음 중 하나가 있습니다.

  • 위의 명령에 표시된 대로 Elytron http-authentication -factory에 대한 참조여야 하는 http-authentication-factory.
  • 레거시 보안 영역.

위의 두 특성은 상호 배타적입니다. http-authentication-factory와 security- realm 을 동시에 지정할 수 없습니다.

참고

http-authentication-factory 를 사용하려는 모든 배포에서는 지정된 HTTP 인증 팩토리에 해당하는 동일한 보안 도메인과 함께 Elytron 보안을 사용해야 합니다.

6장. Jakarta Enterprise Beans 애플리케이션 보안

6.1. 보안 ID

6.1.1. Jakarta Enterprise Beans 보안 ID 정보

Jakarta Enterprise Beans는 다른 구성 요소에서 방법을 호출할 때 사용할 ID를 지정할 수 있습니다. 이는 호출 ID라고도 하는 Jakarta Enterprise Beans 보안 ID입니다.

기본적으로 Jakarta Enterprise Beans는 자체 호출자 ID를 사용합니다. ID는 또는 특정 보안 역할로 설정할 수 있습니다. 특정 보안 역할을 사용하면 세그먼트된 보안 모델을 구성하려는 경우(예: 구성 요소 집합에 대한 액세스를 내부 Jakarta Enterprise Beans로만 제한).

6.1.2. Jakarta Enterprise Bean의 보안 ID 설정

Jakarta Enterprise Beans의 보안 ID는 보안 구성의 <security-identity> 태그를 통해 지정됩니다. <security-identity> 태그가 없으면 기본적으로 Jakarta Enterprise Bean의 호출자 ID가 사용됩니다.

예제: Jakarta Enterprise Bean의 보안 ID를 호출자로 설정

이 예에서는 Jakarta Enterprise Beans에서 만든 메서드 호출에 대한 보안 ID를 현재 호출자의 ID와 동일하게 설정합니다. <security-identity> 요소 선언을 지정하지 않으면 이 동작이 기본값입니다.

<ejb-jar>
  <enterprise-beans>
     <session>
        <ejb-name>ASessionBean</ejb-name>
        ...
        <security-identity>
          <use-caller-identity/>
        </security-identity>
     </session>
     ...
  </enterprise-beans>
</ejb-jar>

예제: Jakarta Enterprise Bean의 보안 ID를 특정 역할로 설정

보안 ID를 특정 역할로 설정하려면 < security-identity> 태그 내에 <run-as> 및 <role-name > 태그를 사용합니다.

<ejb-jar>
  <enterprise-beans>
     <session>
        <ejb-name>RunAsBean</ejb-name>
        ...
        <security-identity>
          <run-as>
             <description>A private internal role</description>
             <role-name>InternalRole</role-name>
          </run-as>
        </security-identity>
     </session>
  </enterprise-beans>
  ...
</ejb-jar>

기본적으로 <run-as> 를 사용하면 anonymous 라는 주체가 발신 호출에 할당됩니다. 다른 주체를 할당하려면 <run-as-principal> 을 사용합니다.

<session>
    <ejb-name>RunAsBean</ejb-name>
    <security-identity>
        <run-as-principal>internal</run-as-principal>
    </security-identity>
</session>
참고

서블릿 요소 내에서 <run-as><run-as-principal> 요소를 사용할 수도 있습니다.

6.2. Jakarta Enterprise Beans 방법 권한

6.2.1. Jakarta Enterprise Bean 방식 권한 정보

Jakarta Enterprise Bean은 자신의 방법에 대한 액세스를 특정 보안 역할로 제한할 수 있습니다.

Jakarta Enterprise Beans <method-permission> 요소 선언은 Jakarta Enterprise Beans의 인터페이스 메서드를 호출할 수 있는 역할을 지정합니다. 다음 조합에 대한 권한을 지정할 수 있습니다.

  • 명명된 Jakarta Enterprise Bean의 모든 홈 및 구성 요소 인터페이스 방법
  • 명명 된 Jakarta Enterprise Beans의 홈 또는 구성 요소 인터페이스의 지정된 방법
  • 이름이 과부하된 메서드 세트 내에 지정된 방법

6.2.2. Jakarta Enterprise Beans 방식 사용 권한

<method-permission> 요소는 <method> 요소에서 정의한 Jakarta Enterprise Beans 메서드에 액세스할 수 있는 논리 역할을 정의합니다. xml의 구문을 보여주는 몇 가지 예는 다음과 같습니다. 여러 메서드 권한 문이 존재할 수 있으며 누적 효과가 있습니다. <method-permission> 요소는 < ejb-jar> 설명자의 <assembly-descriptor > 요소의 자식입니다.

XML 구문은 Jakarta Enterprise Beans 메서드 권한에 대한 주석을 사용하는 대신 사용됩니다.

예제: 자카르타 엔터프라이즈 빈의 모든 메서드에 액세스할 수 있도록 허용

<method-permission>
  <description>The employee and temp-employee roles may access any method
  of the EmployeeService bean </description>
  <role-name>employee</role-name>
  <role-name>temp-employee</role-name>
  <method>
    <ejb-name>EmployeeService</ejb-name>
    <method-name>*</method-name>
  </method>
</method-permission>

예제: Jakarta Enterprise Bean 및 Limit Method Parameters의 특정 메서드에 액세스할 수 있도록 허용

<method-permission>
  <description>The employee role may access the findByPrimaryKey,
  getEmployeeInfo, and the updateEmployeeInfo(String) method of
  the AcmePayroll bean </description>
  <role-name>employee</role-name>
  <method>
    <ejb-name>AcmePayroll</ejb-name>
    <method-name>findByPrimaryKey</method-name>
  </method>
  <method>
    <ejb-name>AcmePayroll</ejb-name>
    <method-name>getEmployeeInfo</method-name>
  </method>
  <method>
    <ejb-name>AcmePayroll</ejb-name>
    <method-name>updateEmployeeInfo</method-name>
    <method-params>
      <method-param>java.lang.String</method-param>
    </method-params>
  </method>
</method-permission>

예제: 인증된 사용자가 Jakarta Enterprise Bean의 메서드에 액세스할 수 있도록 허용

<unchecked/> 요소를 사용하면 인증된 사용자가 지정된 방법을 사용할 수 있습니다.

<method-permission>
  <description>Any authenticated user may access any method of the
  EmployeeServiceHelp bean</description>
  <unchecked/>
  <method>
    <ejb-name>EmployeeServiceHelp</ejb-name>
    <method-name>*</method-name>
  </method>
</method-permission>

예제: 특정 자카르타 엔터프라이즈 빈 방식 제외

<exclude-list>
  <description>No fireTheCTO methods of the EmployeeFiring bean may be
  used in this deployment</description>
  <method>
    <ejb-name>EmployeeFiring</ejb-name>
    <method-name>fireTheCTO</method-name>
  </method>
</exclude-list>

예제: 전체 <assembly-descriptor> 여러 <method-permission> 블록 포함

<ejb-jar>
    <assembly-descriptor>
        <method-permission>
            <description>The employee and temp-employee roles may access any method of the EmployeeService bean </description>
            <role-name>employee</role-name>
            <role-name>temp-employee</role-name>
            <method>
                <ejb-name>EmployeeService</ejb-name>
                <method-name>*</method-name>
            </method>
        </method-permission>
        <method-permission>
            <description>The employee role may access the findByPrimaryKey, getEmployeeInfo, and the updateEmployeeInfo(String) method of the AcmePayroll bean </description>
            <role-name>employee</role-name>
            <method>
                <ejb-name>AcmePayroll</ejb-name>
                <method-name>findByPrimaryKey</method-name>
            </method>
            <method>
                <ejb-name>AcmePayroll</ejb-name>
                <method-name>getEmployeeInfo</method-name>
            </method>
            <method>
                <ejb-name>AcmePayroll</ejb-name>
                <method-name>updateEmployeeInfo</method-name>
                <method-params>
                    <method-param>java.lang.String</method-param>
                </method-params>
            </method>
        </method-permission>
        <method-permission>
            <description>The admin role may access any method of the EmployeeServiceAdmin bean </description>
            <role-name>admin</role-name>
            <method>
                <ejb-name>EmployeeServiceAdmin</ejb-name>
                <method-name>*</method-name>
            </method>
        </method-permission>
        <method-permission>
            <description>Any authenticated user may access any method of the EmployeeServiceHelp bean</description>
            <unchecked/>
            <method>
                <ejb-name>EmployeeServiceHelp</ejb-name>
                <method-name>*</method-name>
            </method>
        </method-permission>
        <exclude-list>
            <description>No fireTheCTO methods of the EmployeeFiring bean may be used in this deployment</description>
            <method>
                <ejb-name>EmployeeFiring</ejb-name>
                <method-name>fireTheCTO</method-name>
            </method>
        </exclude-list>
    </assembly-descriptor>
</ejb-jar>

6.3. Jakarta Enterprise Beans 보안 주석

6.3.1. Jakarta Enterprise Beans 보안 주석 정보

Jakarta Enterprise Beans javax.annotation.security 주석은 Jakarta Annotations 1.3 사양에 정의되어 있습니다.

Jakarta Enterprise Beans는 보안 주석을 사용하여 보안에 대한 정보를 배포자에게 전달합니다. 여기에는 다음이 포함됩니다.

@DeclareRoles
사용 가능한 역할을 선언합니다.
@RunAs
구성 요소의 전파된 보안 ID를 구성합니다.

6.3.2. Jakarta Enterprise Beans 보안 주석 사용

XML 설명자 또는 주석을 사용하여 Jakarta Enterprise Bean의 메서드를 호출할 수 있는 보안 역할을 제어할 수 있습니다. XML 설명자 사용에 대한 자세한 내용은 Using Jakarta Enterprise Beans Method Permissions 를 참조하십시오.

배포 설명자에 명시적으로 지정된 모든 메서드 값은 주석 값을 재정의합니다. 배포 설명자에 메서드 값을 지정하지 않으면 주석을 사용하여 설정된 해당 값이 사용됩니다. 덮어쓰기 세분화는 메서드 단위로 수행됩니다.

Jakarta Enterprise Bean의 보안 권한 제어를 위한 주석

@DeclareRoles
@DeclareRoles 를 사용하여 권한을 확인할 보안 역할을 정의합니다. @DeclareRoles 가 없으면 목록은 @RolesAllowed 주석에서 자동으로 빌드됩니다.
@RolesAllowed, @PermitAll, @DenyAll
@RolesAllowed 를 사용하여 메서드 또는 메서드에 액세스할 수 있는 역할을 나열합니다. 메서드 또는 메서드를 사용하여 모든 역할을 허용하거나 거부하려면 @PermitAll 또는 @DenyAll 을 사용합니다.
@RunAs
@RunAs 를 사용하여 주석이 추가된 메서드에서 호출할 때 메서드에서 사용하는 역할을 지정합니다.

예제: 보안 주석 예

@Stateless
@RolesAllowed({"admin"})
@SecurityDomain("other")
public class WelcomeEJB implements Welcome {
    @PermitAll
    public String WelcomeEveryone(String msg) {
        return "Welcome to " + msg;
    }
    @RunAs("tempemployee")
    public String GoodBye(String msg) {
        return "Goodbye, " + msg;
    }
    public String GoodbyeAdmin(String msg) {
        return "See you later, " + msg;
    }
}

이 코드에서 모든 역할은 Welcomeœone 메서드에 액세스할 수 있습니다. GoodB ¢ 메서드는 호출할 때 tempemployee 역할을 사용합니다. admin 역할만 보안 주석 없이 메서드 GoodbyeAdmin 및 기타 모든 메서드에 액세스할 수 있습니다.

6.4. Jakarta Enterprise Bean에 대한 원격 액세스

6.4.1. 원격 자카르타 엔터프라이즈 빈 클라이언트에서 보안 영역 사용

Jakarta Enterprise Bean을 원격으로 호출하는 클라이언트에 보안을 추가하는 한 가지 방법은 보안 영역을 사용하는 것입니다. 보안 영역은 사용자 이름/암호 쌍과 사용자 이름/역할 쌍으로 이루어진 간단한 데이터베이스입니다. 또한 용어는 웹 컨테이너의 컨텍스트에서도 약간 다른 의미를 가집니다.

Jakarta Enterprise Bean에 대해 보안 영역에 있는 특정 사용자 이름/암호 쌍을 인증하려면 다음 단계를 따르십시오.

  • 도메인 컨트롤러 또는 독립 실행형 서버에 새 보안 영역을 추가합니다.
  • 다음 예와 같이 애플리케이션의 클래스 경로에 있는 wildfly-config.xml 파일을 구성합니다.

    <configuration>
       <authentication-client xmlns="urn:elytron:client:1.2">
          <authentication-rules>
             <rule use-configuration="default" />
          </authentication-rules>
          <authentication-configurations>
             <configuration name="default">
                <sasl-mechanism-selector selector="DIGEST-MD5" />
                <set-user-name name="admin" />
                <credentials>
                   <clear-password password="password123!" />
                </credentials>
             </configuration>
          </authentication-configurations>
       </authentication-client>
       <jboss-ejb-client xmlns="urn:jboss:wildfly-client-ejb:3.0">
          <connections>
             <connection uri="remote+http://127.0.0.1:8080" />
          </connections>
       </jboss-ejb-client>
    </configuration>
  • 새 보안 영역을 사용하는 도메인 또는 독립 실행형 서버에 사용자 지정 원격 커넥터를 생성합니다.
  • 사용자 지정 Remoting 커넥터로 프로필을 사용하도록 구성된 서버 그룹에 Jakarta Enterprise Bean을 배포하거나 관리형 도메인을 사용하지 않는 경우 독립 실행형 서버에 배포합니다.

6.4.2. 새 보안 영역 추가

  1. 관리 CLI를 실행합니다.

    jboss-cli.sh 또는 jboss-cli.bat 스크립트를 실행하고 서버에 연결합니다.

  2. 새 보안 영역 자체를 생성합니다.

    다음 명령을 실행하여 도메인 컨트롤러 또는 독립 실행형 서버에 MyDomainRealm 이라는 새 보안 영역을 생성합니다.

    도메인 인스턴스의 경우 다음 명령을 사용하십시오.

    /host=master/core-service=management/security-realm=MyDomainRealm:add()

    독립 실행형 인스턴스의 경우 다음 명령을 사용하십시오.

    /core-service=management/security-realm=MyDomainRealm:add()
  3. myfile.properties 라는 속성 파일을 만듭니다 :

    독립 실행형 인스턴스의 경우 EAP_HOME/standalone/configuration/myfile.properties 파일을 생성하고 도메인 인스턴스에 대해 EAP_HOME/domain/configuration/myfile.properties 파일을 생성합니다. 이러한 파일에는 파일 소유자의 읽기 및 쓰기 액세스 권한이 있어야 합니다.

    $ chmod 600 myfile.properties
  4. 새 역할에 대한 정보를 저장할 속성 파일에 대한 참조를 생성합니다.

    다음 명령을 실행하여 새 역할과 관련된 속성을 포함할 myfile.properties 파일에 대한 포인터를 생성합니다.

    참고

    속성 파일은 포함된 add-user.sh 및 add-user. bat 스크립트로 생성되지 않습니다. 외부에서 생성해야 합니다.

    도메인 인스턴스의 경우 다음 명령을 사용하십시오.

    /host=master/core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties)

    독립 실행형 인스턴스의 경우 다음 명령을 사용하십시오.

    /core-service=management/security-realm=MyDomainRealm/authentication=properties:add(path=myfile.properties)

새 보안 영역이 생성됩니다. 이 새 영역에 사용자와 역할을 추가하면 기본 보안 영역과 별도의 파일에 정보가 저장됩니다. 자체 애플리케이션 또는 절차를 사용하여 이 새 파일을 관리할 수 있습니다.

참고

add-user.sh 스크립트를 사용하여 application-users.properties 이외의 기본이 아닌 파일에 사용자를 추가하는 경우 --user-properties myfile.properties 인수를 전달해야 합니다. 그렇지 않으면 application-users.properties 를 사용하려고 합니다.

6.4.3. 보안 영역에 사용자 추가

  1. add-user 스크립트를 실행합니다. 터미널을 열고 디렉터리를 EAP_HOME/bin/ 디렉터리로 변경합니다. Red Hat Enterprise Linux 또는 기타 UNIX 유사 운영 체제인 경우 add-user.sh를 실행합니다. Windows Server인 경우 add-user.bat를 실행합니다.
  2. 관리 사용자 또는 애플리케이션 사용자를 추가할지 여부를 선택합니다. 이 절차의 경우 b 를 입력하여 애플리케이션 사용자를 추가합니다.
  3. 사용자가 추가할 영역을 선택합니다. 기본적으로 사용 가능한 유일한 영역은 ApplicationRealm 입니다. 사용자 지정 영역을 추가한 경우 대신 사용자를 추가할 수 있습니다.
  4. 메시지가 표시되면 사용자 이름, 암호 및 역할을 입력합니다. 메시지가 표시되면 원하는 사용자 이름, 암호 및 선택적 역할을 입력합니다. yes 를 입력하여 선택 사항을 확인하거나, no 를 입력하여 변경 사항을 취소합니다. 변경 사항은 보안 영역의 각 속성 파일에 작성됩니다.

6.4.4. 보안 도메인과 보안 영역 간의 관계

중요

Jakarta Enterprise Beans를 보안 영역으로 보호하려면 보안 영역에서 사용자 자격 증명을 검색하도록 구성된 보안 도메인을 사용해야 합니다. 즉, 도메인에는 Remoting 및 RealmDirect 로그인 모듈이 포함되어야 합니다. 보안 도메인 할당은 @SecurityDomain 주석으로 수행되며 Jakarta Enterprise Bean에 적용할 수 있습니다.

other 보안 도메인은 기본 보안 영역에서 사용자 및 암호 데이터를 검색합니다. 이 보안 도메인은 Jakarta Enterprise Beans에 @SecurityDomain 주석이 없는 경우 기본 도메인이지만 Jakarta Enterprise Beans에는 보안으로 간주되는 기타 보안 관련 주석이 포함되어 있습니다.

클라이언트에서 연결을 설정하는 데 사용하는 기본 http-remoting 커넥터 는 사용되는 보안 영역을 결정합니다. http-remoting 커넥터에 대한 자세한 내용은 JBoss EAP 구성 가이드의 하위 시스템 제거 정보를 참조하십시오.

기본 커넥터의 보안 영역은 다음과 같은 방식으로 변경할 수 있습니다.

/subsystem=remoting/http-connector=http-remoting-connector:write-attribute(name=security-realm,value=MyDomainRealm)

6.4.5. SSL 암호화를 사용하여 원격 자카르타 엔터프라이즈 빈 액세스 정보

기본적으로 EJB2의 RMI(Remote Method Invocation) 및 Jakarta Enterprise Beans3 Bean에 대한 네트워크 트래픽은 암호화되지 않습니다. 암호화가 필요한 경우 클라이언트와 서버 간의 연결이 암호화되도록 SSL(Secure Sockets Layer)을 사용할 수 있습니다. SSL을 사용하면 방화벽 구성에 따라 네트워크 트래픽이 일부 방화벽을 통과하도록 허용하는 추가 이점이 있습니다.

주의

Red Hat은 영향을 받는 모든 패키지에서 TLSv1.1 또는 TLSv1.2를 기반으로 SSLv2, SSLv3 및 TLSv1.0을 명시적으로 비활성화하는 것이 좋습니다.

6.5. ejb 하위 시스템과의 Elytron 통합

JBoss EAP 7.1부터 배포를 매핑하여 elytron 하위 시스템에서 보안을 처리할 수 있습니다. 배포에서 매핑된 보안 도메인을 참조하는 경우 해당 보안은 Elytron에서 처리하며, 그렇지 않으면 레거시 보안 하위 시스템에서 보안을 처리합니다. 이 매핑은 ejb 하위 시스템에서 정의됩니다.

ejb 하위 시스템 내에서 매핑은 배포 내에서 참조된 대로 보안 도메인 이름에서 참조된 Elytron security-domain으로 생성됩니다. 매핑된 보안 도메인 이름이 배포에 빈에 대해 구성되면 Elytron에서 보안을 처리해야 함을 나타냅니다. 새로운 Jakarta Enterprise Beans 보안 인터셉터가 기존 인터셉터 대신 설정됩니다.

새로운 Jakarta Enterprise Beans 보안 인터셉터는 호출과 관련된 Elytron SecurityDomain 을 사용하여 현재 SecurityIdentity 를 가져와 다음 작업을 수행합니다.

  • run-as 주체를 설정합니다.
  • run-as principal에 대한 추가 역할을 생성합니다.
  • run-as 역할을 생성합니다.
  • 권한 부여 의사 결정.

JBoss EAP 7.1은 ejb 하위 시스템 application-security-domains 에 새 관리 리소스를 도입했습니다. application-security-domains 요소에는 Elytron 보안 도메인에 매핑해야 하는 애플리케이션 보안 도메인이 포함되어 있습니다.

표 6.1. application-security-domain의 특성

속성설명

name

이 특성은 배포에 지정된 대로 보안 도메인의 이름을 나타냅니다.

security-domain

이 속성은 사용해야 하는 Elytron 보안 도메인에 대한 참조입니다.

enable-jacc

이 특성은 자카르타 인증을 사용하여 권한을 활성화합니다.

referencing-deployments

현재 ASD를 참조하는 모든 배포를 나열하는 런타임 속성입니다.

legacy-compliant-principal-propagation

이 속성은 들어오는 run-as ID가 정의되지 않은 경우 보안되지 않은 로컬 Jakarta Enterprisehieras의 주체를 결정합니다.

true 로 설정하면 보안되지 않은 로컬 Jakarta Enterprisehieras의 보안되지 않은 보안 주체는 현재 인증된 ID입니다.

false 로 설정하면 보안되지 않은 로컬 Jakarta Enterprisehieras의 보안 주체는 익명입니다.

이 속성은 선택 사항이며 기본값은 'true'입니다.

관리 콘솔 또는 관리 CLI를 사용하여 dpdk 하위 시스템에서 application-security-domain 을 구성할 수 있습니다. 자세한 내용은 다음 항목을 참조하십시오.

6.5.1. 관리 콘솔을 사용하여 애플리케이션 보안 도메인 구성

  1. 관리 콘솔에 액세스합니다. 자세한 내용은 JBoss EAP 구성 가이드의 관리 콘솔을 참조하십시오.
  2. 구성하위 시스템EJB 로 이동하여 보기를 클릭합니다.
  3. Security Domain(보안 도메인 ) 탭을 선택하고 필요에 따라 애플리케이션 보안 도메인을 구성합니다.

6.5.2. 관리 CLI를 사용하여 애플리케이션 보안 도메인 구성

다음 예에서 MyAppSecurity 는 배포에서 참조되는 보안 도메인이며 ApplicationDomainelytron 하위 시스템에서 구성된 Elytron 보안 도메인입니다.

/subsystem=ejb3/application-security-domain=MyAppSecurity:add(security-domain=ApplicationDomain)

다음 XML은 이 명령의 결과로 서버 구성 파일의 ejb 하위 시스템에 추가됩니다.

<application-security-domains>
    <application-security-domain name="MyAppSecurity" security-domain="ApplicationDomain"/>
</application-security-domains>

Elytron을 사용하여 보안을 처리하는 Jakarta Enterprise Beans의 간단한 작동 예는 JBoss EAP와 함께 제공되는 ejb-security 빠른 시작을 참조하십시오.

7장. Jakarta Enterprise Beans Interceptors

7.1. 사용자 정의 인터셉터

JBoss EAP를 사용하면 맞춤형 Jakarta Enterprise Beans 인터셉터를 개발하고 관리할 수 있습니다.

다음과 같은 유형의 인터셉터를 생성할 수 있습니다.

  • 클라이언트 인터셉터

    JBoss EAP가 클라이언트로 작동할 때 클라이언트 인터셉터가 실행됩니다.

  • 서버 인터셉터

    JBoss EAP가 서버로 작동할 때 서버 인터셉터가 실행됩니다. 이러한 인터셉터는 서버에 대해 전역적으로 구성됩니다.

  • 컨테이너 인터셉터

    JBoss EAP가 서버로 작동할 때 컨테이너 인터셉터가 실행됩니다. 이러한 인터셉터는 Jakarta Enterprise Beans 컨테이너에서 구성됩니다.

사용자 지정 인터셉터 클래스는 모듈에 추가하고 $JBOSS_HOME/modules 디렉터리에 저장해야 합니다.

7.1.1. 인터셉터 체인

사용자 지정 인터셉터는 인터셉터 체인의 특정 지점에서 실행됩니다.

Jakarta Enterprise Beans에 대해 구성된 컨테이너 인터셉터는 보안 인터셉터 또는 트랜잭션 관리 인터셉터와 같이 Wildfly에서 제공하는 인터셉터 전에 실행됩니다. 따라서 컨테이너 인터셉터는 Wildfly 인터셉터 또는 글로벌 인터셉터를 호출하기 전에 컨텍스트 데이터를 처리하거나 구성할 수 있습니다.

서버 및 클라이언트 인터셉터는 Wildfly 관련 인터셉터 이후에 실행됩니다.

7.1.2. 사용자 정의 클라이언트 인터셉터

사용자 지정 클라이언트 인터셉터는 org.jboss.ejb.client.EJBClientInterceptor 인터페이스를 구현합니다.

org.jboss.ejb.client.EJBClientInvocationContext 인터페이스도 포함되어야 합니다.

다음 코드는 클라이언트 인터셉터의 예를 보여줍니다.

클라이언트 인터셉터 코드 예

package org.foo;
import org.jboss.ejb.client.EJBClientInterceptor;
import org.jboss.ejb.client.EJBClientInvocationContext;
public class FooInterceptor implements EJBClientInterceptor {
    @Override
    public void handleInvocation(EJBClientInvocationContext context) throws Exception {
        context.sendRequest();
    }
    @Override
    public Object handleInvocationResult(EJBClientInvocationContext context) throws Exception {
        return context.getResult();
    }
}

7.1.3. 사용자 정의 서버 인터셉터

서버 인터셉터는 @javax.annotation.AroundInvoke 주석 또는 javax.interceptor.AroundTimeout 주석을 사용하여 빈에서 호출되는 메서드를 표시합니다.

다음 코드는 서버 인터셉터의 예를 보여줍니다.

서버 인터셉터 코드 예

package org.testsuite.ejb.serverinterceptor;
import javax.annotation.PostConstruct;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class TestServerInterceptor {
    @AroundInvoke
    public Object aroundInvoke(final InvocationContext invocationContext) throws Exception {

        return invocationContext.proceed();
    }
}

7.1.4. 사용자 정의 컨테이너 인터셉터

컨테이너 인터셉터는 @javax.annotation.AroundInvoke 주석 또는 javax.interceptor.AroundTimeout 주석을 사용하여 빈에서 호출되는 메서드를 표시합니다.

Jakarta Enterprise Beans 3.2 사양에 정의된 표준 Jakarta EE 인터셉터는 컨테이너에서 보안 컨텍스트 전파, 트랜잭션 관리 및 호출 처리를 완료한 후 실행될 것으로 예상됩니다.

다음 코드는 호출을 위한 iAmAround 메서드를 표시하는 인터셉터 클래스를 보여줍니다.

컨테이너 인터셉터 코드 예

public class ClassLevelContainerInterceptor {
    @AroundInvoke
    private Object iAmAround(final InvocationContext invocationContext) throws Exception {
        return this.getClass().getName() + " " + invocationContext.proceed();
    }
}

컨테이너 인터셉터와 Jakarta EE 인터셉터 API의 차이점

컨테이너 인터셉터는 Jakarta EE 인터셉터와 유사하게 모델링되지만 API의 의미 체계에서 몇 가지 차이점이 있습니다. 예를 들어 Jakarta Enterprise Beans 구성 요소가 설정되거나 인스턴스화되기 전까지는 컨테이너 인터셉터가 javax.interceptor.InvocationContext.getTarget() 메서드를 호출하지 않습니다.

7.1.5. 컨테이너 인터셉터 구성

컨테이너 인터셉터는 표준 Jakarta EE 인터셉터 라이브러리를 사용합니다.

따라서 ejb-jar 배포 설명자 3.2 버전의 ejb-jar.xml 파일에 허용되는 동일한 XSD 요소를 사용합니다.

표준 Jakarta EE 인터셉터 라이브러리를 기반으로 하므로 컨테이너 인터셉터는 배포 설명자를 사용해서만 구성할 수 있습니다. 설계상 애플리케이션에는 JBoss EAP별 주석 또는 기타 라이브러리 종속성이 필요하지 않습니다.

컨테이너 인터셉터를 구성하려면 다음을 수행합니다.

  1. Jakarta Enterprise Beans 배포의 META -INF/' 디렉토리에 jboss- ejb3.xml 파일을 만듭니다.
  2. 설명자 파일에서 컨테이너 인터셉터 요소를 구성합니다.

    1. urn:container-interceptors:1.0 네임스페이스를 사용하여 컨테이너 인터셉터 요소의 구성을 지정합니다.
    2. <container-interceptors> 요소를 사용하여 컨테이너 인터셉터를 지정합니다.
    3. <interceptor-binding> 요소를 사용하여 컨테이너 인터셉터를 Jakarta Enterprise Bean에 바인딩합니다. 인터셉터는 다음 방법 중 하나로 바인딩할 수 있습니다.

      • 와일드카드(*)를 사용하여 배포의 모든 Jakarta Enterprise Beans에 인터셉터를 연결합니다.
      • 특정 Jakarta Enterprise Beans 이름을 사용하여 개별 빈 수준에서 인터셉터를 바인딩합니다.
      • Jakarta Enterprise Bean의 특정 메서드 수준에서 인터셉터를 바인딩합니다.

        참고

        이러한 요소는 Jakarta EE 인터셉터와 동일한 방식으로 Jakarta Enterprise Beans 3.2 XSD를 사용하여 구성됩니다.

다음 예제 설명자 파일은 구성 옵션을 설명합니다.

컨테이너 인터셉터 jboss-ejb3.xml 파일 예

<jboss xmlns="http://www.jboss.com/xml/ns/javaee"
       xmlns:jee="http://java.sun.com/xml/ns/javaee"
       xmlns:ci ="urn:container-interceptors:1.0">
    <jee:assembly-descriptor>
        <ci:container-interceptors>
            <!-- Default interceptor -->
            <jee:interceptor-binding>
                <ejb-name>*</ejb-name>
                <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class>
            </jee:interceptor-binding>
            <!-- Class level container-interceptor -->
            <jee:interceptor-binding>
                <ejb-name>AnotherFlowTrackingBean</ejb-name>
                <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class>
            </jee:interceptor-binding>
            <!-- Method specific container-interceptor -->
            <jee:interceptor-binding>
                <ejb-name>AnotherFlowTrackingBean</ejb-name>
                <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class>
                <method>
                    <method-name>echoWithMethodSpecificContainerInterceptor</method-name>
                </method>
            </jee:interceptor-binding>
            <!-- container interceptors in a specific order -->
            <jee:interceptor-binding>
                <ejb-name>AnotherFlowTrackingBean</ejb-name>
                <interceptor-order>
                    <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class>
                    <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class>
                    <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class>
                </interceptor-order>
                <method>
                    <method-name>echoInSpecificOrderOfContainerInterceptors</method-name>
                </method>
            </jee:interceptor-binding>
        </ci:container-interceptors>
    </jee:assembly-descriptor>
</jboss>

allow-ejb-name-regex 특성을 사용하면 인터셉터 바인딩에서 정규 표현식을 사용하고 지정된 정규 표현식과 일치하는 모든 빈에 인터셉터를 매핑할 수 있습니다. 다음 관리 CLI 명령을 사용하여 ejb3 하위 시스템의 allow-ejb-name-regex 특성을 true 로 활성화합니다.

/subsystem=ejb3:write-attribute(name=allow-ejb-name-regex,value=true)

urn:container-interceptors:1.0 네임스페이스의 스키마는 http://www.jboss.org/schema/jbossas/jboss-ejb-container-interceptors_1_0.xsd 에서 사용할 수 있습니다.

7.1.6. 서버 및 클라이언트 인터셉터 구성

서버 및 클라이언트 인터셉터는 사용 중인 구성 파일에서 JBoss EAP 구성에 전역적으로 추가됩니다.

서버 인터셉터는 ejb3 하위 시스템 구성의 <server-interceptors> 요소에 추가됩니다. 클라이언트 인터셉터는 ejb3 하위 시스템 구성의 <client-interceptors> 요소에 추가됩니다.

다음 예제에서는 서버 인터셉터 추가를 보여줍니다.

/subsystem=ejb3:list-add(name=server-interceptors,value={module=org.abccorp:tracing-interceptors:1.0,class=org.abccorp.TracingInterceptor})

다음 예제에서는 클라이언트 인터셉터 추가를 보여줍니다.

/subsystem=ejb3:list-add(name=client-interceptors,value={module=org.abccorp:clientInterceptor:1.0,class=org.abccorp.clientInterceptor})

서버 인터셉터 또는 클라이언트 인터셉터가 추가되거나 인터셉터 구성을 변경할 때마다 서버를 다시 로드해야 합니다.

7.1.7. 보안 컨텍스트 ID 변경

여러 클라이언트 연결을 여는 대신 인증된 사용자에게 ID를 전환하고 기존 연결에 대한 요청을 다른 사용자로 실행할 수 있는 권한을 부여할 수 있습니다.

기본적으로 애플리케이션 서버에 배포된 자카르타 엔터프라이즈 빈에 대한 원격 호출을 수행할 때 서버에 대한 연결이 인증되며 해당 연결을 사용하는 후속 요청은 원래 인증된 ID를 사용하여 실행됩니다. 이는 클라이언트-서버와 서버 간 호출에 모두 적용됩니다. 동일한 클라이언트의 다른 ID를 사용해야 하는 경우 일반적으로 서로 다른 ID로 인증되도록 서버에 대한 여러 연결을 열어야 합니다. 대신 인증된 사용자가 ID를 변경할 수 있습니다.

인증된 사용자의 ID를 변경하려면 다음을 수행합니다.

  1. 인터셉터 코드에서 ID 변경 사항을 구현합니다.

    • 클라이언트 인터셉터

      인터셉터는 요청된 ID를 EJBClientInvocationContext.getContextData() 호출을 사용하여 가져올 수 있는 컨텍스트 데이터 맵을 통해 전달해야 합니다. 다음 예제 코드는 ID를 전환하는 클라이언트 인터셉터를 보여줍니다.

      클라이언트 인터셉터 코드 예

      public class ClientSecurityInterceptor implements EJBClientInterceptor {
      
          public void handleInvocation(EJBClientInvocationContext context) throws Exception {
              Principal currentPrincipal = SecurityActions.securityContextGetPrincipal();
      
              if (currentPrincipal != null) {
                  Map<String, Object> contextData = context.getContextData();
                  contextData.put(ServerSecurityInterceptor.DELEGATED_USER_KEY, currentPrincipal.getName());
              }
              context.sendRequest();
          }
      
          public Object handleInvocationResult(EJBClientInvocationContext context) throws Exception {
              return context.getResult();
          }
      }

    • 컨테이너 및 서버 인터셉터

      이러한 인터셉터는 ID가 포함된 InvocationContext 를 수신하고 해당 새 ID로 전환하도록 요청합니다. 다음 코드는 컨테이너 인터셉터의 축약 예를 보여줍니다.

      컨테이너 인터셉터 코드 예

      public class ServerSecurityInterceptor {
      
          private static final Logger logger = Logger.getLogger(ServerSecurityInterceptor.class);
      
          static final String DELEGATED_USER_KEY = ServerSecurityInterceptor.class.getName() + ".DelegationUser";
      
          @AroundInvoke
          public Object aroundInvoke(final InvocationContext invocationContext) throws Exception {
              Principal desiredUser = null;
              UserPrincipal connectionUser = null;
      
              Map<String, Object> contextData = invocationContext.getContextData();
              if (contextData.containsKey(DELEGATED_USER_KEY)) {
                  desiredUser = new SimplePrincipal((String) contextData.get(DELEGATED_USER_KEY));
      
                  Collection<Principal> connectionPrincipals = SecurityActions.getConnectionPrincipals();
      
                  if (connectionPrincipals != null) {
                      for (Principal current : connectionPrincipals) {
                          if (current instanceof UserPrincipal) {
                              connectionUser = (UserPrincipal) current;
                              break;
                          }
                      }
      
                  } else {
                      throw new IllegalStateException("Delegation user requested but no user on connection found.");
                  }
              }
      
              ContextStateCache stateCache = null;
              try {
                  if (desiredUser != null && connectionUser != null
                      && (desiredUser.getName().equals(connectionUser.getName()) == false)) {
                      // The final part of this check is to verify that the change does actually indicate a change in user.
                      try {
                          // We have been requested to use an authentication token
                          // so now we attempt the switch.
                          stateCache = SecurityActions.pushIdentity(desiredUser, new OuterUserCredential(connectionUser));
                      } catch (Exception e) {
                          logger.error("Failed to switch security context for user", e);
                          // Don't propagate the exception stacktrace back to the client for security reasons
                          throw new EJBAccessException("Unable to attempt switching of user.");
                      }
                  }
      
                  return invocationContext.proceed();
              } finally {
                  // switch back to original context
                  if (stateCache != null) {
                      SecurityActions.popIdentity(stateCache);;
                  }
              }
          }

  2. 애플리케이션은 프로그래밍 방식으로 또는 서비스 로더 메커니즘을 사용하여 클라이언트 인터셉터를 EJBClientContext 인터셉터 체인에 삽입할 수 있습니다. 클라이언트 인터셉터 구성 지침은 애플리케이션에서 클라이언트 인터셉터 사용을 참조하십시오.
  3. Jakarta Authentication 로그인 모듈을 생성합니다.

    Jakarta Authentication LoginModule 구성 요소는 사용자가 요청한 ID로 요청을 실행할 수 있는지 확인합니다. 다음 abridged 코드 예제는 로그인 및 검증을 수행하는 방법을 보여줍니다.

    LoginModule 코드 예

        @SuppressWarnings("unchecked")
        @Override
        public boolean login() throws LoginException {
            if (super.login() == true) {
                log.debug("super.login()==true");
                return true;
            }
    
            // Time to see if this is a delegation request.
            NameCallback ncb = new NameCallback("Username:");
            ObjectCallback ocb = new ObjectCallback("Password:");
    
            try {
                callbackHandler.handle(new Callback[] { ncb, ocb });
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                }
                // If the CallbackHandler can not handle the required callbacks then no chance.
                return false;
            }
    
            String name = ncb.getName();
            Object credential = ocb.getCredential();
    
            if (credential instanceof OuterUserCredential) {
                // This credential type will only be seen for a delegation request, if not seen then the request is not for us.
    
                if (delegationAcceptable(name, (OuterUserCredential) credential)) {
                    identity = new SimplePrincipal(name);
                    if (getUseFirstPass()) {
                        String userName = identity.getName();
                        if (log.isDebugEnabled())
                            log.debug("Storing username '" + userName + "' and empty password");
                        // Add the username and an empty password to the shared state map
                        sharedState.put("javax.security.auth.login.name", identity);
                        sharedState.put("javax.security.auth.login.password", "");
                    }
                    loginOk = true;
                    return true;
                }
            }
            return false; // Attempted login but not successful.
        }
    
        // Make a trust user to decide if the user switch is acceptable.
        protected boolean delegationAcceptable(String requestedUser, OuterUserCredential connectionUser) {
        if (delegationMappings == null) {
            return false;
        }
    
        String[] allowedMappings = loadPropertyValue(connectionUser.getName(), connectionUser.getRealm());
        if (allowedMappings.length == 1 && "*".equals(allowedMappings[0])) {
            // A wild card mapping was found.
            return true;
        }
        for (String current : allowedMappings) {
            if (requestedUser.equals(current)) {
                return true;
            }
        }
        return false;
    }

7.1.8. 애플리케이션에서 클라이언트 인터셉터 사용

애플리케이션은 서비스 로더 메커니즘을 사용하거나 ClientInterceptors 주석을 사용하여 EJBClientContext 인터셉터 체인에 클라이언트 인터셉터를 프로그래밍 방식으로 삽입할 수 있습니다.

참고

EJBClientInterceptororg.jboss.ejb.client.EJBClientInvocationContext#addReturnedContextDataKey(문자열 키) 를 호출하여 서버 측 호출 컨텍스트에서 특정 데이터를 요청할 수 있습니다. 요청된 데이터가 컨텍스트 데이터 맵에 제공된 키 아래에 있는 경우 클라이언트로 전송됩니다.

7.1.8.1. 프로그래밍 방식으로 클라이언트 인터셉터 삽입

등록된 인터셉터를 사용하여 EJBClientContext 를 생성한 후 인터셉터를 삽입합니다.

다음 코드는 인터셉터 등록을 사용하여 EJBClientContext 를 생성하는 방법을 보여줍니다.

EJBClientContext ctxWithInterceptors = EJBClientContext.getCurrent().withAddedInterceptors(clientInterceptor);

EJBClientContext 생성 후 인터셉터를 삽입하는 데 두 가지 옵션을 사용할 수 있습니다.

  • 호출 가능한 작업을 사용하여 EJBClientContext 가 적용된 다음 코드를 실행할 수 있습니다. call able 작업 내에서 수행되는 Jakarta Enterprise Beans 호출은 클라이언트 측 인터셉터를 적용합니다.

    ctxWithInterceptors.runCallable(() -> {
        // perform the calls which should use the interceptor
    })
  • 또는 새로 생성된 EJBClientContext 를 새 기본값으로 표시할 수 있습니다.

    EJBClientContext.getContextManager().setThreadDefault(ctxWithInterceptors);

7.1.8.2. 서비스 로더 메커니즘을 사용하여 클라이언트 인터셉터 삽입

META-INF/services/org.jboss.ejb.client.EJBClientInterceptor 파일을 만들어 클라이언트 애플리케이션의 클래스 경로에 배치하거나 패키징합니다.

파일의 규칙은 Java ServiceLoader Mechanism 에 의해 지정됩니다.

  • 이 파일에는 Jakarta Enterprise Beans 클라이언트 인터셉터 구현의 정규화된 클래스 이름에 대해 별도의 줄이 포함되어야 합니다.
  • class 경로에서 Jakarta Enterprise Beans 클라이언트 인터셉터 클래스를 사용할 수 있어야 합니다.

서비스 로더 메커니즘을 사용하여 추가된 Jakarta Enterprise Beans 클라이언트 인터셉터는 클래스 경로에서 발견되고 클라이언트 인터셉터 끝에 추가됩니다.

7.1.8.3. ClientInterceptor 주석을 사용하여 클라이언트 인터셉터 삽입

@org.jboss.ejb.client.annotation.ClientInterceptors 주석을 사용하면 원격 호출의 클라이언트측에 Jakarta Enterprise Beans 인터셉터를 배치할 수 있습니다.

import org.jboss.ejb.client.annotation.ClientInterceptors;
@ClientInterceptors({HelloClientInterceptor.class})

public interface HelloBeanRemote {
   public String hello();
}

8장. 클러스터형 자카르타 엔터프라이즈 빈

8.1. 클러스터형 자카르타 엔터프라이즈 빈 정보

자카르타 엔터프라이즈 빈 구성 요소는 고가용성 시나리오에 대해 클러스터링할 수 있습니다. HTTP 구성 요소와 다른 프로토콜을 사용하므로 서로 다른 방식으로 클러스터링됩니다. Enterprise Beans 2 및 3 상태 저장 빈 및 상태 비저장 빈을 클러스터링할 수 있습니다.

Singleton에 대한 자세한 내용은 JBoss EAP 개발 가이드HA Singleton Service 를 참조하십시오.

8.2. 자카르타 엔터프라이즈 빈 클라이언트 코드 단순화

Jakarta Enterprise Beans 서버 측 클러스터 구성 요소를 호출할 때 Jakarta Enterprise Beans 클라이언트 코드를 단순화할 수 있습니다. 다음 절차에서는 Jakarta Enterprise Beans 클라이언트 코드를 간소화하는 여러 가지 방법을 간략하게 설명합니다.

참고

jboss-ejb-client.properties 파일의 사용은 더 이상 사용되지 않습니다 .

8.3. 클러스터형 자카르타 엔터프라이즈 빈 배포

클러스터링 지원은 JBoss EAP 7.4의 HA 프로필에서 사용할 수 있습니다. HA 기능을 활성화한 독립 실행형 서버를 시작하려면 standalone -ha.xml 또는 standalone- full-ha.xml 파일로 시작해야 합니다.

$ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml

그러면 HA 기능이 있는 서버의 단일 인스턴스가 시작됩니다.

클러스터링의 이점을 보려면 서버의 두 개 이상의 인스턴스가 필요합니다. HA 기능을 사용하여 다른 서버를 시작하겠습니다. 서버의 다른 인스턴스는 동일한 시스템 또는 다른 시스템에 있을 수 있습니다. 동일한 시스템에 있는 경우 다음 두 가지를 처리해야 합니다.

  • 두 번째 인스턴스의 포트 오프셋 전달
  • 각 서버 인스턴스에 고유한 jboss.node.name 시스템 속성이 있는지 확인합니다.

다음 두 시스템 속성을 startup 명령에 전달하여 이를 수행할 수 있습니다.

$ EAP_HOME/bin/standalone.sh --server-config=standalone-ha.xml -Djboss.socket.binding.port-offset=PORT_OFFSET -Djboss.node.name=UNIQUE_NODE_NAME

이 인스턴스에도 Jakarta Enterprise Beans 배포를 배포하는 데 친숙한 접근 방식을 따르십시오.

주의

클러스터된 서버의 독립 실행형 인스턴스의 한 노드에만 애플리케이션을 배포하는 것은 다른 클러스터된 인스턴스에 자동으로 배포된다는 의미는 아닙니다. 다른 독립 실행형 클러스터 인스턴스에도 명시적으로 배포해야 합니다. 또는 서버 그룹 내의 모든 서버에 배포를 배포할 수 있도록 도메인 모드에서 서버를 시작할 수 있습니다.

이제 두 인스턴스에 클러스터형 Jakarta Enterprise Beans가 있는 애플리케이션을 배포했으므로 Jakarta Enterprise Beans는 이제 클러스터링 기능을 사용할 수 있습니다.

참고

JBoss EAP 7부터는 HA 프로필을 사용하여 JBoss EAP를 시작하면 상태 저장 세션 빈의 상태가 복제됩니다. 더 이상 @Clustered 주석을 사용하여 클러스터링 동작을 활성화할 필요가 없습니다.

@Stateful 주석에서 passivationCapablefalse 로 설정하여 상태 저장 세션 빈에 대한 복제를 비활성화할 수 있습니다.

@Stateful(passivationCapable=false)

이렇게 하면 서버가 cache- ref 대신 passivation-disabled-cache-ref 로 정의된 ejb 캐시를 사용하도록 지시합니다.

상태 저장 세션 빈의 복제를 전역적으로 비활성화하려면 다음 관리 CLI 명령을 사용합니다.

/subsystem=ejb3:write-attribute(name=default-sfsb-cache,value=simple)

8.4. 클러스터형 자카르타 엔터프라이즈 빈에 대한 페일오버

클러스터형 Jakarta Enterprise Bean의 페일오버 기능. @Stateful Jakarta Enterprise Beans의 상태가 클러스터 노드에 복제되므로 클러스터의 노드 중 하나가 다운되면 다른 노드에서 호출을 인계받을 수 있습니다.

클러스터의 서버가 충돌하는 경우와 같이 클러스터형 환경에서 일부 상황에서 Jakarta Enterprise Beans 클라이언트에서 응답 대신 예외를 받을 수 있습니다. Jakarta Enterprise Beans 클라이언트 라이브러리는 발생하는 오류 유형에 따라 안전한 경우 호출을 자동으로 다시 시도합니다. 그러나 요청이 실패하고 재시도에 안전하게 확인할 수 없는 경우 환경에 적절하게 예외를 처리할 수 있습니다. 그러나 사용자 지정 인터셉터를 사용하여 재시도 동작을 추가할 수 있습니다.

8.5. 원격 독립 실행형 클라이언트

참고

jboss-ejb-client.properties 파일의 사용은 더 이상 사용되지 않습니다 .

독립 실행형 원격 클라이언트는 Java Naming 및 Directory Interface 접근법 또는 기본 JBoss Jakarta Enterprise Beans 클라이언트 API를 사용하여 서버와 통신할 수 있습니다. 중요한 점은 클러스터형 Jakarta Enterprise Beans 배포를 호출할 때 클러스터 내의 모든 서버를 나열할 필요가 없다는 것입니다. 이는 클러스터 내에서 클러스터 노드 추가의 동적 특성으로 인해 불가능할 수 있었습니다.

원격 클라이언트는 클러스터링 기능이 있는 서버 중 하나만 나열해야 합니다. 이 서버는 클라이언트와 클러스터된 노드 간의 클러스터 토폴로지 통신의 시작 지점 역할을 합니다.

jboss-ejb-client.properties 구성 파일에서 ejb 클러스터를 구성해야 합니다.

remote.clusters=ejb
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false

8.6. 클러스터 토폴로지 통신

참고

jboss-ejb-client.properties 파일의 사용은 더 이상 사용되지 않습니다 .

클라이언트가 서버에 연결하면 서버에 클러스터링 기능이 있는 경우 JBoss Jakarta Enterprise Beans 클라이언트 구현이 클러스터 토폴로지 정보용 서버와 내부적으로 통신합니다. 예를 들어 서버 X가 연결할 초기 서버로 나열되는 경우 클라이언트가 서버 X에 연결할 때 서버는 비동기 클러스터 토폴로지 메시지를 클라이언트에 다시 보냅니다. 이 토폴로지 메시지는 클러스터 이름과 클러스터에 속하는 노드의 정보로 구성됩니다. 노드 정보에는 필요한 경우 연결할 노드 주소와 포트 번호가 포함됩니다. 이 예에서 서버 X는 클러스터에 속하는 다른 서버 Y로 구성된 클러스터 토폴로지를 다시 보냅니다.

상태 저장 클러스터형 Jakarta Enterprise Bean의 경우 호출 흐름이 두 단계로 수행됩니다.

  1. 상태 저장 빈에 대한 세션 생성은 해당 빈에 대해 Java 네이밍 및 디렉터리 인터페이스 조회를 수행할 때 발생합니다.
  2. 반환된 프록시를 호출합니다.

상태 저장 빈에 대한 조회는 내부적으로 클라이언트에서 서버로 동기 세션 생성 요청을 트리거합니다. 이 경우 세션 생성 요청은 jboss-ejb-client.properties 파일에 구성되었으므로 서버 X로 이동합니다. 서버 X가 클러스터되므로 세션 ID를 반환하고 해당 세션의 선호도 를 다시 보냅니다. 클러스터된 서버의 경우 선호도 는 상태 저장 빈이 서버 측에 속하는 클러스터의 이름과 동일합니다. 비클러스터형 빈의 경우 선호도는 세션이 생성된 노드 이름입니다. 이 선호도 를 사용하면 Jakarta Enterprise Beans 클라이언트가 클러스터형 빈의 노드 또는 클러스터되지 않은 빈의 경우 특정 노드로 프록시에서 호출을 라우팅할 수 있습니다. 이 세션 생성 요청이 실행되는 동안 서버 X는 클러스터 토폴로지를 포함하는 비동기 메시지를 다시 보냅니다. JBoss Jakarta Enterprise Beans 클라이언트 구현은 이 토폴로지 정보를 기록하고 나중에 클러스터 내의 노드에 연결하고 필요한 경우 호출을 라우팅하는 데 사용합니다.

장애 조치(failover)가 작동하는 방식을 이해하기 위해 서버 X가 시작점이며 클라이언트 애플리케이션이 상태 저장 빈을 찾아 호출하는 것과 동일한 예제를 고려합니다. 이러한 호출 중에 클라이언트 측은 서버에서 클러스터 토폴로지 정보를 수집합니다. 어떤 이유로든 서버 X가 다운되고 클라이언트 애플리케이션이 프록시에서 호출된다고 가정합니다. 이 단계에서 JBoss Jakarta Enterprise Beans 클라이언트 구현은 선호도 를 인식해야 하며, 이 경우 클러스터 선호도입니다. 클라이언트에 있는 클러스터 토폴로지 정보에서 클러스터에 서버 X와 서버 Y의 두 개의 노드가 있음을 알고 있습니다. 호출이 도착하면 클라이언트에서 서버 X가 다운되었음을 알 수 있으므로 선택기를 사용하여 클러스터 노드에서 적합한 노드를 가져옵니다. 선택기가 클러스터 노드에서 노드를 반환하면 JBoss Jakarta Enterprise Beans 클라이언트 구현에서 연결이 이전에 생성되지 않은 경우 해당 노드에 대한 연결을 생성하고 Jakarta Enterprise Beans 수신자를 생성합니다. 이 예에서 클러스터의 다른 노드만 server Y이므로 선택기는 서버 Y를 노드로 반환하고 JBoss Jakarta Enterprise Beans 클라이언트 구현에서는 이 수신자를 사용하여 Jakarta Enterprise Beans 수신자를 생성하고 이 수신자를 사용하여 프록시의 호출을 전달합니다. 이제 클러스터 내의 다른 노드로 호출이 실패했습니다.

8.7. Jakarta Enterprise Bean의 자동 트랜잭션 고정

Jakarta Enterprise Beans 프록시와 동일한 컨텍스트에서 검색되는 트랜잭션 개체는 동일한 호스트를 대상으로 합니다. 컨텍스트가 다중 호스트이거나 클러스터된 경우 활성 트랜잭션을 보유하면 호출 컨텍스트가 동일한 노드에 고정됩니다.

이 동작은 트랜잭션이 오버플로되었는지 또는 원격 사용자 트랜잭션을 사용 중인지에 따라 달라집니다.

아웃플로된 트랜잭션의 경우 애플리케이션이 특정 노드에서 조회되면 동일한 트랜잭션에서 해당 애플리케이션에 대한 모든 호출이 이 노드를 대상으로 시도합니다. 아웃플로된 트랜잭션을 이미 수신한 노드는 아직 받지 않은 노드보다 선호됩니다.

원격 사용자 트랜잭션의 경우 첫 번째 성공적인 호출이 트랜잭션을 지정된 노드에 잠그고 이 트랜잭션에서 호출한 후 동일한 노드로 이동해야 합니다. 그렇지 않으면 예외가 발생합니다.

8.8. 다른 인스턴스의 원격 클라이언트

이 섹션에서는 JBoss EAP 인스턴스에 배포된 클라이언트 애플리케이션이 다른 JBoss EAP 인스턴스에 배포된 클러스터형 상태 저장 빈을 호출하는 방법에 대해 설명합니다.

다음 예에서는 3개의 서버가 관련되어 있습니다. 서버 X와 Y는 모두 클러스터에 속하며 클러스터형 Jakarta Enterprise Beans를 배포합니다. 클러스터링 기능이 없을 수도 있고 클러스터링 기능이 없을 수도 있는 다른 서버 인스턴스 서버 서버 C가 있습니다. 서버 C는 서버 X 및 Y에 배포된 클러스터형 빈을 호출하고 페일오버를 수행하려는 배포가 있는 클라이언트 역할을 합니다.

구성은 jboss-ejb-client.xml 파일에서 수행되며, 다른 서버에 대한 원격 아웃바운드 연결을 가리킵니다. jboss-ejb-client.xml 파일의 구성은 서버 C가 클라이언트이기 때문에 서버 C의 배포에 있습니다. 클라이언트 구성은 모든 클러스터된 노드를 가리켜야 하는 것이 아니라 그 중 하나를 가리켜야 합니다. 이는 통신의 시작점으로 사용될 것입니다.

이 경우 원격 아웃바운드 연결이 서버 C에서 서버 X로 생성되고 서버 X가 통신의 시작점으로 사용됩니다. 원격 독립 실행형 클라이언트의 경우와 유사하게 서버 C에서 상태 저장 빈을 찾을 때 세션 생성 요청이 세션 ID와 클러스터 선호도를 반환하는 서버 X로 전송됩니다. 또한 서버 X는 비동기 메시지를 클러스터 토폴로지를 포함하는 서버 C로 보냅니다. 서버 Y는 서버 X와 함께 클러스터에 속해 있기 때문에 이 토폴로지 정보에는 서버 Y의 노드 정보가 포함됩니다. 프록시에서 후속 호출은 클러스터의 노드로 적절하게 라우팅됩니다. 앞에서 설명한 대로 서버 X가 종료되면 클러스터와 다른 노드가 선택되고 호출이 해당 노드로 전달됩니다.

다른 JBoss EAP 인스턴스의 원격 클라이언트 및 원격 클라이언트 모두 장애 조치(failover) 측면에서 유사하게 작동합니다.

8.9. 독립 실행형 및 서버 인 서버 클라이언트 설정

참고

jboss-ejb-client.properties 파일의 사용은 더 이상 사용되지 않습니다 .

Jakarta Enterprise Beans 클라이언트를 클러스터형 Jakarta Enterprise Beans 애플리케이션에 연결하려면 독립 실행형 Jakarta Enterprise Beans 클라이언트 또는 in-server Jakarta Enterprise Beans 클라이언트에서 기존 구성을 확장하여 클러스터 연결 구성을 포함해야 합니다. 독립 실행형 Jakarta Enterprise Beans 클라이언트의 jboss-ejb-client.properties 또는 서버 측 애플리케이션의 jboss-ejb-client.xml 파일까지 클러스터 구성을 포함하도록 확장해야 합니다.

참고

Jakarta Enterprise Beans 클라이언트는 원격 서버에서 Jakarta Enterprise Bean을 사용하는 모든 프로그램입니다. 원격 서버를 호출하는 Jakarta Enterprise Beans 클라이언트가 서버 내부에서 실행되는 경우 클라이언트는 in-server 입니다. 즉, 다른 JBoss EAP 인스턴스에 호출하는 JBoss EAP 인스턴스는 서버 내 클라이언트로 간주됩니다.

이 예에서는 독립 실행형 Jakarta Enterprise Beans 클라이언트에 필요한 추가 클러스터 구성을 보여줍니다.

remote.clusters=ejb
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false
remote.cluster.ejb.username=test
remote.cluster.ejb.password=password

애플리케이션이 remote-outbound-connection을 사용하는 경우 jboss-ejb-client.xml 파일을 구성하고 다음 예와 같이 클러스터 구성을 추가해야 합니다.

<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd">
  <client-context>
    <ejb-receivers>
      <!-- this is the connection to access the app-one -->
      <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" />
      <!-- this is the connection to access the app-two -->
      <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-2" />
    </ejb-receivers>

    <!-- If an outbound connection connects to a cluster,
             a list of members is provided after successful connection.
         To connect to this node this cluster element must be defined. -->

    <clusters>
      <!-- cluster of remote-ejb-connection-1 -->
      <cluster name="ejb" security-realm="ejb-security-realm-1" username="quickuser1">
        <connection-creation-options>
        <property name="org.xnio.Options.SSL_ENABLED" value="false" />
        <property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" />
        </connection-creation-options>
      </cluster>
    </clusters>
  </client-context>
</jboss-ejb-client>

remote-outbound-connection에 대한 자세한 내용은 JBoss EAP 구성 가이드 의 Remoting Subsystem 정보를 참조하십시오.

참고

보안 연결의 경우 인증 예외가 발생하지 않도록 클러스터 구성에 인증 정보를 추가해야 합니다.

8.10. 자카르타 엔터프라이즈 빈 호출에 대한 사용자 정의 로드 밸런싱 정책 구현

참고

jboss-ejb-client.properties 파일의 사용은 더 이상 사용되지 않습니다 .

서버 간에 애플리케이션의 Jakarta Enterprise Beans 호출의 균형을 맞추기 위해 대체 또는 사용자 지정 로드 밸런싱 정책을 구현할 수 있습니다.

Jakarta Enterprise Beans 호출에 대한 AllClusterNodeSelector 를 구현할 수 있습니다. AllClusterNodeSelector 의 노드 선택 동작은 대규모 클러스터(노드 수 > 20)에서도 AllClusterNodeSelector 가 사용 가능한 모든 클러스터 노드를 사용한다는 점을 제외하고 기본 선택기와 유사합니다. 연결되지 않은 클러스터 노드가 반환되면 자동으로 열립니다. 다음 예제에서는 AllClusterNodeSelector 구현을 보여줍니다.

package org.jboss.as.quickstarts.ejb.clients.selector;

import java.util.Arrays;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.ejb.client.ClusterNodeSelector;
public class AllClusterNodeSelector implements ClusterNodeSelector {
  private static final Logger LOGGER = Logger.getLogger(AllClusterNodeSelector.class.getName());

  @Override
  public String selectNode(final String clusterName, final String[] connectedNodes, final String[] availableNodes) {
    if(LOGGER.isLoggable(Level.FINER)) {
      LOGGER.finer("INSTANCE "+this+ " : cluster:"+clusterName+" connected:"+Arrays.deepToString(connectedNodes)+" available:"+Arrays.deepToString(availableNodes));
    }

    if (availableNodes.length == 1) {
        return availableNodes[0];
    }
    final Random random = new Random();
    final int randomSelection = random.nextInt(availableNodes.length);
    return availableNodes[randomSelection];
  }

}

Jakarta Enterprise Beans 호출에 대한 SimpleLoadFactorNodeSelector 를 구현할 수도 있습니다. SimpleLoadFactorNodeSelector 의 부하 분산은 부하 요인에 따라 수행됩니다. 로드 계수(2/3/4)는 각 노드의 부하와 관계없이 노드 이름(A/B/C)에 따라 계산됩니다. 다음 예는 SimpleLoadFactorNodeSelector 구현을 보여줍니다.

package org.jboss.as.quickstarts.ejb.clients.selector;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.ejb.client.DeploymentNodeSelector;
public class SimpleLoadFactorNodeSelector implements DeploymentNodeSelector {
  private static final Logger LOGGER = Logger.getLogger(SimpleLoadFactorNodeSelector.class.getName());
  private final Map<String, List<String>[]> nodes = new HashMap<String, List<String>[]>();
  private final Map<String, Integer> cursor = new HashMap<String, Integer>();

  private ArrayList<String> calculateNodes(Collection<String> eligibleNodes) {
    ArrayList<String> nodeList = new ArrayList<String>();

    for (String string : eligibleNodes) {
      if(string.contains("A") || string.contains("2")) {
        nodeList.add(string);
        nodeList.add(string);
      } else if(string.contains("B") || string.contains("3")) {
        nodeList.add(string);
        nodeList.add(string);
        nodeList.add(string);
      } else if(string.contains("C") || string.contains("4")) {
        nodeList.add(string);
        nodeList.add(string);
        nodeList.add(string);
        nodeList.add(string);
      }
    }
    return nodeList;
  }

  @SuppressWarnings("unchecked")
  private void checkNodeNames(String[] eligibleNodes, String key) {
    if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) {
      // must be synchronized as the client might call it concurrent
      synchronized (nodes) {
        if(!nodes.containsKey(key) || nodes.get(key)[0].size() != eligibleNodes.length || !nodes.get(key)[0].containsAll(Arrays.asList(eligibleNodes))) {
          ArrayList<String> nodeList = new ArrayList<String>();
          nodeList.addAll(Arrays.asList(eligibleNodes));

          nodes.put(key, new List[] { nodeList, calculateNodes(nodeList) });
        }
      }
    }
  }
   private synchronized String nextNode(String key) {
    Integer c = cursor.get(key);
    List<String> nodeList = nodes.get(key)[1];

    if(c == null || c >= nodeList.size()) {
      c = Integer.valueOf(0);
    }

    String node = nodeList.get(c);
    cursor.put(key, Integer.valueOf(c + 1));

    return node;
  }

  @Override
  public String selectNode(String[] eligibleNodes, String appName, String moduleName, String distinctName) {
    if (LOGGER.isLoggable(Level.FINER)) {
      LOGGER.finer("INSTANCE " + this + " : nodes:" + Arrays.deepToString(eligibleNodes) + " appName:" + appName + " moduleName:" + moduleName
          + " distinctName:" + distinctName);
    }

    // if there is only one there is no sense to choice
    if (eligibleNodes.length == 1) {
      return eligibleNodes[0];
    }
    final String key = appName + "|" + moduleName + "|" + distinctName;

    checkNodeNames(eligibleNodes, key);
    return nextNode(key);
  }
}

jboss-ejb-client.properties 파일 구성

구현 클래스(AllClusterNodeSelector 또는 SimpleLoadFactorNodeSelector )의 이름으로 remote .cluster.ejb.clusternode.selector 속성을 추가해야 합니다. 선택기는 호출 시 사용할 수 있는 구성된 모든 서버가 표시됩니다. 다음 예제에서는 AllClusterNodeSelector 를 클러스터 노드 선택기로 사용합니다.

remote.clusters=ejb
remote.cluster.ejb.clusternode.selector=org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false
remote.cluster.ejb.username=test
remote.cluster.ejb.password=password

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=one,two
remote.connection.one.host=localhost
remote.connection.one.port = 8080
remote.connection.one.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.one.username=user
remote.connection.one.password=user123
remote.connection.two.host=localhost
remote.connection.two.port = 8180
remote.connection.two.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false

Jakarta Enterprise Beans 클라이언트 API 사용

PropertiesBasedEJBClientConfiguration 생성자의 목록에 remote.cluster.ejb.clusternode.selector 속성을 추가해야 합니다. 다음 예제에서는 AllClusterNodeSelector 를 클러스터 노드 선택기로 사용합니다.

Properties p = new Properties();
p.put("remote.clusters", "ejb");
p.put("remote.cluster.ejb.clusternode.selector", "org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector");
p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false");
p.put("remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED", "false");
p.put("remote.cluster.ejb.username", "test");
p.put("remote.cluster.ejb.password", "password");

p.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false");
p.put("remote.connections", "one,two");
p.put("remote.connection.one.port", "8080");
p.put("remote.connection.one.host", "localhost");
p.put("remote.connection.two.port", "8180");
p.put("remote.connection.two.host", "localhost");

EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(p);
ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc);
EJBClientContext.setSelector(selector);

p = new Properties();
p.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(p);

jboss-ejb-client.xml 파일 구성

서버에서 서버 간 통신에 부하 분산 정책을 사용하려면 클래스를 애플리케이션과 함께 패키징하고 META-INF 폴더에 있는 jboss-ejb-client.xml 설정 내에 구성합니다. 다음 예제에서는 AllClusterNodeSelector 를 클러스터 노드 선택기로 사용합니다.

<jboss-ejb-client xmlns:xsi="urn:jboss:ejb-client:1.2" xsi:noNamespaceSchemaLocation="jboss-ejb-client_1_2.xsd">
  <client-context deployment-node-selector="org.jboss.ejb.client.DeploymentNodeSelector">
    <ejb-receivers>
      <!-- This is the connection to access the application. -->
      <remoting-ejb-receiver outbound-connection-ref="remote-ejb-connection-1" />
    </ejb-receivers>
    <!-- Specify the cluster configurations applicable for this client context -->
    <clusters>
      <!-- Configure the cluster of remote-ejb-connection-1. -->
      <cluster name="ejb" security-realm="ejb-security-realm-1" username="test" cluster-node-selector="org.jboss.as.quickstarts.ejb.clients.selector.AllClusterNodeSelector">
        <connection-creation-options>
          <property name="org.xnio.Options.SSL_ENABLED" value="false" />
          <property name="org.xnio.Options.SASL_POLICY_NOANONYMOUS" value="false" />
        </connection-creation-options>
      </cluster>
    </clusters>
  </client-context>
</jboss-ejb-client>

보안과 함께 위의 구성을 사용하려면 ejb-security-realm-1을 클라이언트- 서버 구성에 추가해야 합니다. 다음 예제에서는 보안 영역(ejb-security-realm-1)을 추가하기 위한 CLI 명령을 보여줍니다. 값은 "test" 사용자의 base64 인코딩 암호입니다.

/core-service=management/security-realm=ejb-security-realm-1:add()
/core-service=management/security-realm=ejb-security-realm-1/server-identity=secret:add(value=cXVpY2sxMjMr)

서버 간 통신에 부하 분산 정책을 사용해야 하는 경우 클래스를 애플리케이션 또는 모듈과 함께 패키징할 수 있습니다. 이 클래스는 최상위 EAR 아카이브의 META -INF 디렉터리에 있는 jboss- ejb-client 설정 파일에서 구성됩니다. 다음 예제에서는 배포 노드 선택기로 RoundRobinNodeSelector 를 사용합니다.

<jboss-ejb-client xmlns="urn:jboss:ejb-client:1.2">
    <client-context deployment-node-selector="org.jboss.example.RoundRobinNodeSelector">
        <ejb-receivers>
            <remoting-ejb-receiver outbound-connection-ref="..."/>
        </ejb-receivers>
        ...
    </client-context>
</jboss-ejb-client>
참고

독립 실행형 서버를 실행하는 경우 start 옵션 -Djboss.node.name= 또는 서버 구성 파일 standalone.xml 을 사용하여 서버 이름을 구성합니다. 서버 이름이 고유한지 확인합니다. 관리형 도메인을 실행하는 경우 호스트 컨트롤러는 이름이 고유함을 자동으로 확인합니다.

8.11. 클러스터형 환경에서 자카르타 엔터프라이즈 빈 트랜잭션

클라이언트 코드가 클러스터형 Jakarta Enterprise Bean을 호출하면 클러스터 선호도가 자동으로 설정됩니다. 클라이언트 측에서 트랜잭션을 관리하는 경우 클러스터에서 특정 노드를 대상으로 하도록 선택하거나 클라이언트가 트랜잭션을 처리할 클러스터 노드를 지연적으로 선택할 수 있습니다. 이 섹션에서는 두 옵션에 대해 설명합니다.

Jakarta Enterprise Beans Transactions 특정 노드를 대상으로 합니다

다음 절차에 따라 클러스터의 특정 노드를 대상으로 트랜잭션을 처리할 수 있습니다.

  1. InitialContext 를 생성할 때 PROVIDER_URL 속성을 사용하여 대상 클러스터 노드 주소를 지정합니다.

    props.put(Context.PROVIDER_URL, "remote+http://127.0.0.1:8080");
    ...
    InitialContext ctx = new InitialContext(props);
  2. 클라이언트에서 InitialContext 에서 txn:RemoteUserTransaction 을 조회합니다.

    UserTransaction ut = (UserTransaction)ctx.lookup("txn:RemoteUserTransaction");

    PROVIDER_URL 속성을 서버의 URL로 설정한 다음 아래 코드 예와 같이 txn:User Transaction을 조회하여 User Transaction 에 대한 Java 네이밍 및 디렉터리 인터페이스 조회를 수행할 수 있습니다.

    final Hashtable<String, String> jndiProperties = new Hashtable<>();
    jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
    jndiProperties.put(Context.PROVIDER_URL, "remote+http://localhost:8080");
    final Context context = new InitialContext(jndiProperties);
    
    SecuredEJBRemote reference = (SecuredEJBRemote) context.lookup("txn:UserTransaction");

    UserTransaction 은 실제 호출이 수행될 때까지 특정 대상에 바인딩되지 않습니다. 호출 시 이 UserTransaction 은 트랜잭션의 전체 수명 동안 해당 대상에 바인딩됩니다.

    UserTransaction 을 시작하기 전에 노드 이름이나 대상을 알 필요가 없습니다. org.jboss.ejb.client.EJBClient.getUserTransaction() 메서드는 첫 번째 호출에 따라 대상을 자동으로 선택하는 원격 UserTransaction 을 제공합니다. Java 네이밍 및 디렉터리 인터페이스에서 원격 UserTransaction 을 조회하는 방법도 동일한 방식으로 작동합니다.

    참고

    org.jboss.ejb.client.EJBClient.getUserTransaction() 메서드는 더 이상 사용되지 않습니다.

  3. 트랜잭션이 시작되면 모든 Jakarta Enterprise Beans 호출이 트랜잭션 기간 동안 해당 특정 노드에 바인딩되어 서버 선호도를 설정합니다.
  4. 트랜잭션이 종료되면 서버 선호도가 릴리스되고 Jakarta Enterprise Beans 프록시는 일반 클러스터 선호도로 돌아갑니다.

Jakarta Enterprise Beans Transactions Lazily Select a Node

클라이언트에서 트랜잭션과 관련된 첫 번째 호출 중에 트랜잭션을 처리하도록 클러스터 노드를 지연적으로 선택할 수 있습니다. 이를 통해 클러스터 전체에서 트랜잭션의 부하를 분산할 수 있습니다. 이 옵션을 사용하려면 아래 절차를 따르십시오.

  1. Jakarta Enterprise Bean을 호출하는 데 사용되는 InitialContextPROVIDER_URL 속성을 지정하지 마십시오.
  2. 클라이언트에서 InitialContext 에서 txn:RemoteUserTransaction 을 조회합니다.

    UserTransaction ut = (UserTransaction)ctx.lookup("txn:RemoteUserTransaction");
  3. 트랜잭션이 시작되면 하나의 클러스터 노드가 자동으로 선택되어 서버 선호도를 설정하고 모든 Jakarta Enterprise Beans 호출이 트랜잭션 기간 동안 해당 특정 노드에 바인딩됩니다.
  4. 트랜잭션이 종료되면 서버 선호도가 릴리스되고 Jakarta Enterprise Beans 프록시는 일반 클러스터 선호도로 돌아갑니다.

8.12. Jakarta Enterprise Beans-clustered 데이터베이스 타이머

JBoss EAP는 클러스터형 환경에서 Jakarta Enterprise Bean 타이머를 유지하기 위해 클러스터형 데이터베이스 지원 타이머를 지원합니다. 클러스터링이 데이터베이스를 통해 제공되기 때문에 짧은 시간 내에 타이머 수가 꺼지면 성능이 저하됩니다. ejb3/service=timer-service/database -data -store 구성 요소의 refresh-interval 및 allow- execution 특성을 사용하여 성능을 최적화할 수 있습니다.

다음과 같이 비클러스터형 모드에서 데이터베이스 타이머를 사용할 수도 있습니다.

  • refresh-interval0 으로 설정합니다.
  • 모든 노드에 고유한 파티션 이름을 제공하거나 각 노드에 다른 데이터베이스를 사용합니다.

Jakarta Enterprise Beans-clustered 데이터베이스 타이머는 다음과 같이 작동합니다.

  • 타이머를 실행할 수 있는 모든 노드는 알고 있는 모든 타이머에 대한 시간 초과를 예약합니다.
  • 이 시간 초과가 만료되면 각 노드는 상태를 running으로 업데이트하여 타이머를 잠그려고 시도합니다.

    상태 업데이트 쿼리는 다음 쿼리와 유사합니다.

    UPDATE JBOSS_EJB_TIMER SET TIMER_STATE=? WHERE ID=? AND TIMER_STATE<>? AND NEXT_DATE=?;

트랜잭션과 READ_COMMITTED 또는 SERIALIZABLE 격리 모드를 사용하므로 행 업데이트에는 하나의 노드만 성공적으로 수행되며 타이머가 실행되는 노드입니다.

8.12.1. 자카르타 Enterpise Bean-clustered 타이머 설정

데이터베이스 지원 타이머 저장소를 추가하여 Jakarta Enterprise Beans-clustered 타이머를 설정할 수 있습니다.

사전 요구 사항

  • 데이터베이스는 READ_COMMITTED 또는 SERIALIZABLE 격리 모드를 지원해야 합니다.

절차

  • 데이터베이스 지원 타이머 저장소를 생성합니다.

    /subsystem=ejb3/service=timer-service/database-data-store=my-clustered-store:add(allow-execution=true, datasource-jndi-name="java:/MyDatasource", refresh-interval=60000, database="postgresql", partition="mypartition")

    다음과 같이 매개변수를 설정합니다.

    • allow-execution : 이 노드에서 타이머를 실행할 수 있도록 하려면 true 로 설정합니다. false 로 설정하면 JBoss EAP는 이 노드의 타이머를 다른 노드의 데이터베이스에 추가합니다. 타이머 실행을 클러스터의 몇 개 노드로만 제한하면 전체 데이터베이스 로드가 줄어듭니다.
    • datasource-jndi-name : 사용할 데이터 소스입니다.
    • refresh-interval : 이 노드가 데이터베이스에 다른 노드에서 추가한 새 타이머가 있는지 확인하기 전에 경과해야 하는 기간을 설정합니다. 값은 밀리초 단위입니다.

      중요

      작은 값을 설정하면 JBoss EAP에서 타이머를 더 빨리 선택하지만 데이터베이스의 에서 부하가 증가합니다. 타이머를 추가한 노드가 실패했거나 allow-execution 이 false이므로 타이머를 실행할 수 없는 경우 노드가 새로 고쳐질 때까지 타이머가 실행되지 않을 수 있습니다.

    • database : 사용 중인 데이터베이스 유형을 정의합니다. 일부 SQL 문은 데이터베이스에서 사용자 지정합니다.

      이 속성을 정의하지 않으면 서버에서 유형을 자동으로 탐지하려고 합니다. 현재 지원되는 유형은 postgresql,mysql,oracle,db2,hsqlh2 입니다.

      SQL은 다음 파일에 있습니다. modules/system/layers/base/org/jboss/as/ejb3/main/timers/timer-sql.properties

      이 파일에 새 데이터베이스별 SQL 문을 추가하여 실행되는 SQL을 수정하거나 새 데이터베이스에 대한 지원을 추가할 수 있습니다.

    • partition : 이 노드가 포함될 파티션의 이름으로 값을 설정합니다. 동일한 파티션에 있는 노드의 타이머만 이 노드에 표시됩니다. 성능 향상을 위해 대규모 클러스터를 여러 개의 작은 클러스터로 분리하려면 이 속성을 사용합니다.
참고

클러스터되지 않은 타이머에 이 데이터베이스 데이터 저장소를 사용하려면 새로 고침 인터럽트를 0으로 설정하고 모든 노드에 고유한 파티션 이름이 있는지 확인하거나 각 노드에 다른 데이터베이스를 사용합니다.

8.12.2. 배포 시 Jakarta Enterprise Beans-clustered 타이머 사용

단일 데이터 저장소를 모든 애플리케이션의 기본값으로 사용하거나 각 애플리케이션에 특정 데이터 저장소를 사용할 수 있습니다.

사전 요구 사항

  • Jakarta Enterprise Beans-clustered 데이터베이스 지원 타이머 저장소를 설치했습니다.

절차

  • 단일 데이터 저장소를 모든 애플리케이션의 기본값으로 사용하려면 다음과 같이 ejb3 하위 시스템 내의 default-data-store 를 업데이트합니다.

    <timer-service thread-pool-name="timer" default-data-store="clustered-store">
        <data-stores>
            <database-data-store name="clustered-store" datasource-jndi-name="java:jboss/datasources/ExampleDS" partition="timer"/>
        </data-stores>
    </timer-service>
  • 특정 애플리케이션에 별도의 데이터 저장소를 사용하려면 jboss-ejb3.xml 파일에서 타이머 데이터 저장소 이름을 설정합니다.

    <?xml version="1.1" encoding="UTF-8"?>
    <jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:timer="urn:timer-service:1.0" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" version="3.1" impl-version="2.0">
        <assembly-descriptor>
            <timer:timer>
                <ejb-name>*</ejb-name>
                <timer:persistence-store-name>my-clustered-store</timer:persistence-store-name>
            </timer:timer>
        </assembly-descriptor>
    </jboss:ejb-jar>

8.12.3. Jakarta Interceptors를 사용하여 Jakarta Enterprise Bean-clustered 타이머 새로 고침

새로 고침 간격이 만료되기 전에 타이머를 새로 고치도록 비즈니스 방법에 Jakarta Interceptor를 설정하여 타이머를 프로그래밍 방식으로 새로 고칠 수 있습니다.

참고

클러스터형 배포에서는 여러 노드가 짧은 간격으로 데이터 저장소를 업데이트하면 메모리 내 타이머 상태가 일시적으로 동기화되지 않을 수 있습니다.

사전 요구 사항

  • 데이터베이스 지원 클러스터형 Jakarta Enterprise Bean을 구성했습니다.

절차

  1. wildfly.ejb.timer.refresh.enabledtrue 로 활성화하는 Jakarta Interceptors를 구현합니다.

    import javax.interceptor.AroundInvoke;
    import javax.interceptor.Interceptor;
    import javax.interceptor.InvocationContext;
    
    /**
     * An interceptor to enable programmatic timer refresh across multiple nodes.
     */
    @Interceptor
    public class RefreshInterceptor {
        @AroundInvoke
        public Object intercept(InvocationContext context) throws Exception {
            context.getContextData().put("wildfly.ejb.timer.refresh.enabled", Boolean.TRUE);
            return context.proceed();
        }
    }
  2. 자카르타 인터셉터 구성.

    • 대상 상태 비저장 또는 Singleton 빈 비즈니스 방법으로 자카르타 인터셉터를 구성할 수 있습니다. When wildfly.ejb.timer.refresh.enabledtrue 로 설정되어 타이머를 반환하기 전에 TimerService.getAllTimers() 를 호출하여 타이머 데이터 저장소를 새로 고칩니다.

      @Singleton
      public class RefreshBean1 ... {
      
          @Interceptors(RefreshInterceptor.class)
          public void businessMethod1() {
              ...
              // since wildfly.ejb.timer.refresh.enabled is set to true in interceptor for this business method,
              // calling timerService.getAllTimers() will first refresh from timer datastore before returning timers.
              final Collection<Timer> allTimers = timerService.getAllTimers();
              ...
          }
      }
    • 또는 전용 비즈니스 방법을 구현하여 필요한 경우 애플리케이션의 다른 부분이 호출하는 타이머를 프로그래밍 방식으로 새로 고칠 수 있습니다.

          @Interceptors(RefreshInterceptor.class)
          public List<Timer> getAllTimerInfoWithRefresh() {
              return timerService.getAllTimers();
          }
      
          public void businessMethod1() {
              final LocalBusinessInterface businessObject = sessionContext.getBusinessObject(LocalBusinessInterface.class);
              businessObject.getAllTimerInfoWithRefresh();
      
              // timer has been programmatically refreshed from datastore.
              // continue with other business logic...
          }

9장. Jakarta Enterprise Bean 3 하위 시스템 튜닝

ejb3 하위 시스템의 성능 최적화에 대한 팁은 성능 튜닝 가이드의 Jakarta Enterprise Beans 하위 시스템 튜닝 섹션을 참조하십시오.

부록 A. 참고 자료

A.1. Jakarta Enterprise Beans Java Naming and Directory Interface 참조

세션 빈의 Java Naming 및 Directory Interface 조회 이름은 다음 구문을 사용합니다.

ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful
  • <appName>: 세션 빈의 JAR 파일이 EAR(엔터프라이즈 아카이브) 내에 배포된 경우 appName 은 해당 EAR의 이름입니다. 기본적으로 EAR의 이름은 .ear 접미사가 없는 파일 이름입니다. 애플리케이션 이름은 application.xml 파일에서 재정의할 수 있습니다. 세션 빈이 EAR에 배포되지 않은 경우 appName 을 비워 둡니다.
  • <moduleName>: moduleName 은 세션 빈이 배포되는 JAR 파일의 이름입니다. JAR 파일의 기본 이름은 .jar 접미사가 없는 파일 이름입니다. 모듈 이름은 JAR의 ejb-jar.xml 파일에서 재정의할 수 있습니다.
  • <distinctName>: JBoss EAP를 사용하면 각 배포에서 선택적 고유 이름을 지정할 수 있습니다. 배포에 고유한 이름이 없는 경우 distinctName 을 비워둡니다.
  • <beanName>: beanName 은 호출할 세션 빈의 간단한 클래스 이름입니다.
  • <viewClassName>: viewClassName 은 원격 인터페이스의 정규화된 클래스 이름입니다. 여기에는 인터페이스의 패키지 이름이 포함됩니다.
  • ?stateful: Java Naming 및 Directory Interface 이름이 상태 저장 세션 빈을 참조하는 경우 ?stateful 접미사가 필요합니다. 다른 빈 유형에는 포함되지 않습니다.

예를 들어, 원격 인터페이스 org . jboss.example.HelloBean을 노출하는 상태 저장 빈 org. jboss.example.Hello가 hello. jar 를 배포한 경우 Java Naming 및 Directory Interface 조회 이름은 다음과 같습니다.

ejb:/hello/HelloBean!org.jboss.example.Hello?stateful"

A.2. Jakarta Enterprise Beans 참조 해상도

이 섹션에서는 JBoss EAP에서 @EJB 및 @ Resource 를 구현하는 방법에 대해 설명합니다. XML은 항상 주석을 재정의하지만 동일한 규칙이 적용됩니다.

@EJB 주석에 대한 규칙
  • @EJB 주석에는 mappedName() 속성도 있습니다. 사양은 벤더별 메타데이터로 남겨둡니다. JBoss EAP는 mappedName() 을 참조하는 자카르타 엔터프라이즈 빈의 글로벌 Java 네이밍 및 디렉터리 인터페이스 이름으로 인식합니다. mappedName() 을 지정하면 다른 모든 속성이 무시되고 이 글로벌 Java Naming 및 Directory Interface 이름이 바인딩에 사용됩니다.
  • 속성이 정의되어 있지 않은 @EJB 를 지정하는 경우:

    @EJB
    ProcessPayment myEjbref;

    그러면 다음 규칙이 적용됩니다.

    • 참조 빈의 Jakarta Enterprise Beans JAR은 @EJB 주입에 사용되는 인터페이스를 사용하여 Jakarta Enterprise Beans를 검색합니다. 동일한 비즈니스 인터페이스를 게시하는 Jakarta Enterprise Beans가 두 개 이상 있는 경우 예외가 발생합니다. 해당 인터페이스가 있는 빈만 있는 경우 해당 인터페이스가 사용됩니다.
    • 해당 인터페이스를 게시하는 Jakarta Enterprise Beans의 EAR를 검색합니다. 중복이 있는 경우 예외가 발생합니다. 그렇지 않으면 일치하는 빈이 반환됩니다.
    • JBoss EAP 런타임에서 해당 인터페이스의 Jakarta Enterprise Bean을 전역적으로 검색합니다. 중복이 발견되면 예외가 발생합니다.
  • @EJB.beanName()<ejb-link> 에 해당합니다. beanName() 이 정의된 경우 검색에서 beanName() 을 사용하여 속성이 정의되지 않은 @EJB 와 동일한 알고리즘을 사용합니다. 이 규칙의 예외는 ejb-link # 구문을 사용하는 경우입니다. 참조하는 Jakarta Enterprise Beans가 있는 EAR에서 JAR에 상대 경로를 배치할 수 있습니다. 자세한 내용은 Jakarta Enterprise Beans 3.2 사양을 참조하십시오.

A.3. 원격 자카르타 엔터프라이즈 빈 클라이언트에 대한 프로젝트 종속성

원격 클라이언트에서 세션 빈의 호출을 포함하는 Maven 프로젝트에는 JBoss EAP Maven 리포지토리의 다음과 같은 종속성이 필요합니다. 아래 하위 섹션에 설명된 대로 Jakarta Enterprise Beans 클라이언트 종속성을 선언하는 방법은 두 가지가 있습니다.

참고

artifactId 버전은 변경될 수 있습니다. 최신 버전은 JBoss EAP Maven 리포지토리 를 참조하십시오.

원격 자카르타 엔터프라이즈 빈 클라이언트의 Maven 종속성

jboss-eap-jakartaee8 BOM(Bill of Materials)은 JBoss EAP 애플리케이션에서 일반적으로 필요로 하는 여러 아티팩트의 올바른 버전을 패키징합니다. BOM 종속성은 가져오기 범위와 함께 pom.xml<dependencyManagement> 섹션에 지정됩니다.

예제: POM 파일 <dependencyManagement> 섹션

<dependencyManagement>
   <dependencies>
      <dependency>
      <groupId>org.jboss.bom</groupId>
        <artifactId>jboss-eap-jakartaee8</artifactId>
        <version>7.4.0.GA</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
   </dependencies>
</dependencyManagement>

나머지 종속성은 pom.xml 파일의 <dependencies> 섹션에 지정됩니다.

예제: POM 파일 <dependencies> 섹션

<dependencies>
    <!-- Include the Enterprise Java Bean client JARs -->
    <dependency>
        <groupId>org.jboss.eap</groupId>
        <artifactId>wildfly-ejb-client-bom</artifactId>
        <type>pom</type>
    </dependency>

    <!-- Include any additional dependencies required by the application
        ...
    -->

</dependencies>

JBoss EAP와 함께 제공되는 ejb-remote 빠른 시작 기능은 원격 Jakarta Enterprise Beans 클라이언트 애플리케이션의 전체 작업 예제를 제공합니다. 원격 세션 빈 호출에 대한 종속성 구성의 전체 예는 해당 빠른 시작의 루트 디렉터리에 있는 client/pom.xml 파일을 참조하십시오.

jboss-ejb-client 종속성을 위한 단일 아티팩트ID

wildfly-ejb-client-bom artifactID를 사용하고 jboss-ejb-client 라이브러리를 추가하여 Jakarta Enterprise Beans 클라이언트에 필요한 모든 종속성을 포함할 수 있습니다.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.eap</groupId>
            <artifactId>wildfly-ejb-client-bom</artifactId>
            <version>JAKARTA_ENTERPRISE_BEANS_CLIENT_BOM_VERSION</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.jboss</groupId>
        <artifactId>jboss-ejb-client</artifactId>
    </dependency>
</dependencies>

JBoss EAP Maven 리포지토리에서 사용할 수 있는 JAKARTA_ENTERPRISE_BEANS_CLIENT_BOM_VERSION 을 사용해야 합니다.

A.4. jboss-ejb3.xml 배포 설명자 참조

jboss-ejb3.xml 은 Jakarta Enterprise Beans JAR 또는 WAR 아카이브에서 사용할 수 있는 사용자 지정 배포 설명자입니다. Jakarta Enterprise Beans JAR 아카이브에서는 META-INF/ 디렉터리에 있어야 합니다. WAR 아카이브에서는 WEB-INF/ 디렉토리에 있어야 합니다.

형식은 동일한 네임스페이스 중 일부를 사용하고 다른 추가 네임스페이스를 제공하는 ejb-jar.xml 과 유사합니다. jboss-ejb3.xml 의 내용은 우선 순위의 jboss -ejb3.xml 항목과 ejb-jar.xml 의 내용과 병합됩니다.

이 문서에서는 jboss-ejb3.xml 에서 사용하는 표준이 아닌 추가 네임스페이스만 다룹니다. 표준 네임 스페이스에 대한 설명서는 http://xmlns.jcp.org/xml/ns/javaee/ 을 참조하십시오.

루트 네임스페이스는 http://xmlns.jcp.org/xml/ns/javaee 입니다.

어셈블리 설명자 네임스페이스
다음 네임스페이스는 모두 <assembly-descriptor> 요소에서 사용할 수 있습니다. 와일드카드(*)를 ejb-name 으로 사용하여 단일 빈 또는 배포의 모든 빈에 구성을 적용하는 데 사용할 수 있습니다.
보안 네임스페이스(urn:security)
xmlns:s="urn:security"

그러면 Jakarta Enterprise Bean의 security-domainrun-as-principal 을 설정할 수 있습니다.

<s:security>
  <ejb-name>*</ejb-name>
  <s:security-domain>myDomain</s:security-domain>
  <s:run-as-principal>myPrincipal</s:run-as-principal>
</s:security>
리소스 어댑터 네임스페이스: urn:resource-adapter-binding
xmlns:r="urn:resource-adapter-binding"

이를 통해 Message-Driven Bean의 리소스 어댑터를 설정할 수 있습니다.

<r:resource-adapter-binding>
  <ejb-name>*</ejb-name>
  <r:resource-adapter-name>myResourceAdapter</r:resource-adapter-name>
</r:resource-adapter-binding>
IIOP 네임스페이스: urn:iiop
xmlns:u="urn:iiop"

IIOP 네임스페이스는 IIOP 설정이 구성된 위치입니다.

풀 네임스페이스: urn:ejb-pool:1.0
xmlns:p="urn:ejb-pool:1.0"

이를 통해 포함된 상태 비저장 세션 빈 또는 Message-Driven Bean에서 사용하는 풀을 선택할 수 있습니다. 풀은 서버 구성에 정의됩니다.

<p:pool>
   <ejb-name>*</ejb-name>
   <p:bean-instance-pool-ref>my-pool</p:bean-instance-pool-ref>
</p:pool>
캐시 네임스페이스: urn:ejb-cache:1.0
xmlns:c="urn:ejb-cache:1.0"

이를 통해 포함된 상태 저장 세션 빈에서 사용하는 캐시를 선택할 수 있습니다. 캐시는 서버 구성에 정의됩니다.

<c:cache>
   <ejb-name>*</ejb-name>
   <c:cache-ref>my-cache</c:cache-ref>
</c:cache>
<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
    xmlns="http://xmlns.jcp.org/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-ejb3-2_0.xsd"
    version="3.1"
    impl-version="2.0">
  <enterprise-beans>
     <message-driven>
        <ejb-name>ReplyingMDB</ejb-name>
        <ejb-class>org.jboss.as.test.integration.ejb.mdb.messagedestination.ReplyingMDB</ejb-class>
        <activation-config>
           <activation-config-property>
              <activation-config-property-name>destination</activation-config-property-name>
              <activation-config-property-value>java:jboss/mdbtest/messageDestinationQueue
              </activation-config-property-value>
           </activation-config-property>
        </activation-config>
     </message-driven>
  </enterprise-beans>
 </jboss:ejb-jar>
참고

jboss-ejb3-spec-2_0.xsd 파일에는 스키마 검증 오류가 발생할 수 있는 알려진 문제가 있습니다. 이러한 오류는 무시할 수 있습니다. 자세한 내용은 https://bugzilla.redhat.com/show_bug.cgi?id=1192591 의 내용을 참조하십시오.

A.5. 자카르타 엔터프라이즈 빈 스레드 풀 구성

관리 콘솔 또는 관리 CLI를 사용하여 Jakarta Enterprise Beans 스레드 풀을 생성할 수 있습니다.

A.5.1. 관리 콘솔을 사용하여 자카르타 엔터프라이즈 빈 스레드 풀 구성

절차

  1. 관리 콘솔에 로그인합니다.
  2. 구성하위 시스템EJB 로 이동하여 보기를 클릭합니다.
  3. 컨테이너스레드 풀을 선택합니다.
  4. Add(추가 )를 클릭하고 Name (이름) 및 Max Threads (최대 스레드) 값을 지정합니다.
  5. 저장을 클릭합니다.

A.5.2. 관리 CLI를 사용하여 자카르타 엔터프라이즈 빈 스레드 풀 구성

절차

  1. 다음 구문으로 add 작업을 사용합니다.

    /subsystem=ejb3/thread-pool=THREAD_POOL_NAME:add(max-threads=MAX_SIZE)
    1. THREAD_POOL_NAME 을 스레드 풀에 필요한 이름으로 바꿉니다.
    2. MAX_SIZE 를 스레드 풀의 최대 크기로 바꿉니다.
  2. read-resource 작업을 사용하여 스레드 풀 생성을 확인합니다.

    /subsystem=ejb3/thread-pool=THREAD_POOL_NAME:read-resource
    1. 새 스레드 풀을 사용하도록 ejb3 하위 시스템에서 모든 서비스를 재구성하려면 다음 명령을 사용합니다.

      /subsystem=ejb3/thread-pool=bigger:add(max-threads=100, core-threads=10)
      /subsystem=ejb3/service=async:write-attribute(name=thread-pool-name, value="bigger")
      /subsystem=ejb3/service=remote:write-attribute(name=thread-pool-name, value="bigger")
      /subsystem=ejb3/service=timer-service:write-attribute(name=thread-pool-name, value="bigger")
      reload

      XML 설정 샘플:

      <subsystem xmlns="urn:jboss:domain:ejb3:5.0">
          ...
          <async thread-pool-name="bigger"/>
          ...
          <timer-service thread-pool-name="bigger" default-data-store="default-file-store">
          ...
          <remote connectors="http-remoting-connector" thread-pool-name="bigger"/>
          ...
          <thread-pools>
              <thread-pool name="default">
                  <max-threads count="10"/>
                  <core-threads count="5"/>
                  <keepalive-time time="100" unit="milliseconds"/>
              </thread-pool>
              <thread-pool name="bigger">
                  <max-threads count="100"/>
                  <core-threads count="5"/>
              </thread-pool>
          </thread-pools>
          ...

A.5.3. Jakarta Enterprise Beans 스레드 풀 속성

Jakarta Enterprise Beans 스레드 풀은 특정 구성 요구 사항에 대해 보다 효율적으로 실행되도록 특성을 사용하여 구성할 수 있습니다.

  • max-threads 속성은 실행자가 지원하는 총 또는 최대 스레드 수를 결정합니다.
/subsystem=ejb3/thread-pool=default:write-attribute(name=max-threads, value=9)
{"outcome" => "success"}
  • core-threads 속성은 실행자 풀에 보관되는 스레드 수를 결정합니다. 여기에는 유휴 스레드가 포함됩니다. core-threads 속성을 지정하지 않으면 기본값은 max-threads 입니다.
/subsystem=ejb3/thread-pool=default:write-attribute(name=core-threads, value=3)
{"outcome" => "success"}
  • keepalive-time 특성은 코어가 아닌 스레드가 유휴 상태로 유지되도록 허용하는 시간을 결정합니다. 이번에는 코어가 아닌 스레드가 제거됩니다.
/subsystem=ejb3/thread-pool=default:write-attribute(name=keepalive-time, value={time=5, unit=MINUTES})
{"outcome"=> "success"}
  • keepalive-time 속성의 시간을 변경하지 않고 시간을 변경하려면 다음 명령을 사용합니다.
/subsystem=ejb3/thread-pool=default:write-attribute(name=keepalive-time.time, value=10)
{"outcome"=> "success"}





2024-02-09에 최종 업데이트된 문서

법적 공지

Copyright © 2024 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.