Apache Karaf 트랜잭션 가이드
머리말
이 가이드에서는 Fuse 트랜잭션 애플리케이션을 구현하기 위한 정보와 지침을 제공합니다. 정보는 다음과 같이 구성됩니다.
1장. 트랜잭션 소개
이 장에서는 일부 기본 트랜잭션 개념과 트랜잭션 관리자에서 중요한 서비스 특성을 논의하여 트랜잭션을 도입합니다. 정보는 다음과 같이 구성됩니다.
1.1. Transaction이란 무엇입니까?
트랜잭션의 프로토타입은 개념적으로 단일 단계(예: 계정 A에서 계정 B로의 양도)로 구성되지만 일련의 단계로 구현되어야 합니다. 이러한 작업은 시스템 실패에 취약합니다. 실패가 완료되지 않은 일부 단계를 떠나 시스템을 일관되지 않은 상태로 둘 수 있기 때문입니다. 예를 들어, 계정 A에서 계정 B로의 양도 작업을 고려하십시오. 계정 A를 인출 한 후 시스템이 실패하지만 계정 B를 계산하기 전에는 시스템이 실패합니다. 그 결과는 일부 비용이 사라집니다.
이와 같은 작업이 안정적인지 확인하려면 이를 트랜잭션 으로 구현하십시오. 트랜잭션은 원자, 일관되고, 격리되고, 세련되기 때문에 안정적인 실행을 보장합니다. 이러한 속성을 트랜잭션의 ACID 속성이라고 합니다.
1.2. 트랜잭션의 ACID 속성
트랜잭션의 ACID 속성은 다음과 같이 정의됩니다.
- Atomic-a 트랜잭션은 전체 또는 아무 절차입니다. 개별 업데이트가 어셈블되고 트랜잭션이 완료될 때 커밋되거나 취소(롤백)됩니다.
- 일관된트랜잭션은 하나의 일관된 상태에서 다른 일관된 상태로 시스템을 사용하는 작업 단위입니다.
- 격리된- 트랜잭션이 실행되는 동안 부분 결과는 다른 엔티티에서 숨겨집니다.
- Cryostat - 트랜잭션이 커밋된 후 즉시 시스템이 실패하더라도 트랜잭션 결과가 지속됩니다.
1.3. 트랜잭션 클라이언트 정보
트랜잭션 클라이언트는 트랜잭션 을 시작하고 종료할 수 있는 API 또는 오브젝트입니다. 일반적으로 트랜잭션 클라이언트는 트랜잭션을 시작,커밋 또는 롤백 하는 작업을 노출합니다.
표준 Cryostat 애플리케이션에서 javax. Cryostat.UserTransaction 인터페이스는 트랜잭션
클라이언트 API를 노출합니다. Spring Framework, Spring Boot의 컨텍스트에서 org.springframework. Cryostat.PlatformTransactionManager
인터페이스는 트랜잭션 클라이언트 API를 노출합니다.
1.4. 트랜잭션 용어 설명
다음 표에서는 몇 가지 중요한 트랜잭션 용어를 정의합니다.
용어 | 설명 |
---|---|
demarcation | 트랜잭션 분리는 트랜잭션 시작 및 종료를 나타냅니다. 트랜잭션 종료는 트랜잭션에서 수행한 작업이 커밋되거나 롤백되었음을 의미합니다. 예를 들어 트랜잭션 클라이언트 API를 호출하여 명시적이거나 트랜잭션 끝점에서 메시지를 폴링할 때마다 암시적일 수 있습니다. 자세한 내용은 9장. 트랜잭션을 사용하는 Camel 애플리케이션 작성의 내용을 참조하십시오. |
Resources | 리소스는 영구적인 또는 영구적으로 변경할 수 있는 컴퓨터 시스템의 모든 구성 요소입니다. 실제로 리소스는 거의 항상 데이터베이스 또는 데이터베이스에 계층화된 서비스(예: 지속성을 갖는 메시지 서비스)입니다. 그러나 다른 종류의 리소스는 실현할 수 있습니다. 예를 들어 ATM(Automated Teller Machine)은 일종의 리소스입니다. 고객이 물리적으로 기계에서 인출을 수락한 후에는 거래를 되돌릴 수 없습니다. |
트랜잭션 관리자 | 트랜잭션 관리자는 하나 이상의 리소스에서 트랜잭션을 조정합니다. 대부분의 경우 트랜잭션 관리자가 리소스에 빌드됩니다. 예를 들어 엔터프라이즈 수준 데이터베이스에는 일반적으로 해당 데이터베이스의 콘텐츠를 변경하는 트랜잭션을 관리할 수 있는 트랜잭션 관리자가 포함되어 있습니다. 두 개 이상의 리소스를 포함하는 트랜잭션에는 일반적으로 외부 트랜잭션 관리자가 필요합니다. |
트랜잭션 컨텍스트 | 트랜잭션 컨텍스트 는 트랜잭션을 추적하는 데 필요한 정보를 캡슐화하는 개체입니다. 트랜잭션 컨텍스트 형식은 전적으로 관련 트랜잭션 관리자 구현에 따라 달라집니다. 최소한 트랜잭션 컨텍스트에는 고유한 트랜잭션 식별자가 포함됩니다.At a minimum, the transaction context contains a unique transaction identifier. |
분산 트랜잭션 | 분산 트랜잭션은 트랜잭션 범위가 여러 네트워크 노드에 걸쳐 있는 분산 시스템의 트랜잭션을 나타냅니다. 분산 트랜잭션을 지원하기 위한 기본 전제 조건은 정식 형식으로 트랜잭션 컨텍스트 전송을 지원하는 네트워크 프로토콜입니다. 분산 트랜잭션은 Apache Camel 트랜잭션 범위를 벗어납니다. 3.2.3절. “분산 트랜잭션 관리자 정보” 도 참조하십시오. |
X/Open XA 표준 | X/Open XA 표준은 리소스를 트랜잭션 관리자와 통합하기 위한 인터페이스를 설명합니다. 두 개 이상의 리소스가 포함된 트랜잭션을 관리하려면 참여하는 리소스는 XA 표준을 지원해야 합니다. XA 표준을 지원하는 리소스는 트랜잭션 관리자(또는 트랜잭션 처리 모니터)가 리소스의 트랜잭션을 제어할 수 있도록 하는 특수 오브젝트인 XA 스위치 를 노출합니다. XA 표준은 1단계 커밋 프로토콜과 2단계 커밋 프로토콜을 모두 지원합니다. |
1.5. 여러 리소스를 수정하는 트랜잭션 관리
단일 리소스와 관련된 트랜잭션의 경우 일반적으로 리소스에 빌드된 트랜잭션 관리자를 사용할 수 있습니다. 여러 리소스가 포함된 트랜잭션의 경우 외부 트랜잭션 관리자 또는 트랜잭션 처리(TP) 모니터를 사용해야 합니다. 이 경우 리소스를 XA 스위치를 등록하여 트랜잭션 관리자와 통합해야 합니다.
단일 리소스 시스템에서 작동하는 트랜잭션을 커밋하는 데 사용되는 프로토콜과 다중 리소스 시스템에서 작동하는 트랜잭션을 커밋하는 데 사용되는 프로토콜에는 중요한 차이점이 있습니다.
- 1단계 커밋- 단일 리소스 시스템용입니다. 이 프로토콜은 트랜잭션을 단일 단계로 커밋합니다.
- 2단계 커밋- 다중 리소스 시스템용입니다. 이 프로토콜은 두 단계로 트랜잭션을 커밋합니다.
트랜잭션에 여러 리소스를 포함하면 일부 리소스에서 트랜잭션을 커밋한 후 시스템 오류가 발생할 수 있는 위험이 추가됩니다. 이로 인해 시스템이 일관성 없는 상태로 유지됩니다. 2단계 커밋 프로토콜은 이러한 위험을 제거하도록 설계되었습니다. 시스템을 재시작한 후 항상 일관된 상태로 복원할 수 있습니다.
1.6. 트랜잭션 및 스레드 간 관계
트랜잭션 처리를 이해하려면 트랜잭션과 스레드 간의 기본 관계를 이해하는 것이 중요합니다: 트랜잭션이 스레드에 따라 다릅니다. 즉, 트랜잭션이 시작되면 특정 스레드에 연결됩니다. (기술적으로 트랜잭션 컨텍스트 오브젝트가 생성되고 현재 스레드와 연결됩니다). 트랜잭션이 종료될 때까지 스레드의 모든 활동이 이 트랜잭션 범위 내에서 수행됩니다.From this point until the transaction ends, all of the activity in the thread occurs within this transaction scope. 다른 스레드의 Activity는 이 트랜잭션의 범위 내에 속하지 않습니다. 그러나 다른 스레드의 활성은 다른 트랜잭션의 범위 내에 있을 수 있습니다.
이러한 트랜잭션과 스레드 간의 관계는 다음을 의미합니다.
- 애플리케이션은 각 트랜잭션이 별도의 스레드에서 생성되는 한 동시에 여러 트랜잭션을 처리할 수 있습니다.
-
트랜잭션 내에 하위 스레드를 생성해야 합니다. 트랜잭션 중간에 있고
threads()
Camel DSL 명령을 호출하여 새 스레드 풀을 생성하는 경우 새 스레드는 원래 트랜잭션의 범위에 있지 않습니다. - 이전 시점에서 지정된 것과 동일한 이유로 새 스레드를 암시적으로 생성하는 처리 단계를 주의하십시오.
-
트랜잭션 범위는 일반적으로 라우팅 세그먼트 간에 확장되지 않습니다. 즉, 하나의 경로 세그먼트가
to(JoinEndpoint)
로 끝나고 다른 경로 세그먼트가(JoinEndpoint)에서
시작하는 경우 이러한 경로 세그먼트는 일반적으로 동일한 트랜잭션에 속하지 않습니다. 그러나 예외가 있습니다.
일부 고급 트랜잭션 관리자 구현에서는 트랜잭션 컨텍스트를 원하는 대로 스레드에 분리하고 연결할 수 있습니다. 예를 들어 한 스레드에서 다른 스레드로 트랜잭션 컨텍스트를 이동할 수 있습니다.For example, this makes it possible to move a transaction context from one thread to another thread. 경우에 따라 단일 트랜잭션 컨텍스트를 여러 스레드에 연결할 수도 있습니다.
1.7. 거래 서비스 특성 정보
거래 시스템을 구현하는 제품을 선택할 때 다양한 데이터베이스 제품과 거래 관리자, 무료 및 일부 상용이 있습니다. 모두 트랜잭션 처리에 대한 일반 지원이 있지만 이러한 제품에 의해 지원되는 서비스의 특성에는 상당한 차이가 있습니다. 이 섹션에서는 서로 다른 트랜잭션 제품의 안정성과 세분화를 비교할 때 고려해야 할 기능에 대한 간략한 가이드를 제공합니다.
1.7.1. 리소스에서 제공하는 서비스의 특성
다음 기능에 따라 리소스의 서비스 품질이 결정됩니다.
1.7.1.1. 트랜잭션 격리 수준
ANSI SQL은 다음과 같이 네 가지 트랜잭션 격리 수준을 정의합니다.
직렬화 가능
- 트랜잭션이 서로 완벽하게 격리됩니다. 즉, 트랜잭션이 커밋될 때까지 하나의 트랜잭션이 다른 트랜잭션에 영향을 미칠 수 없습니다. 이 격리 수준은 모든 트랜잭션이 다른 트랜잭션 후 실행되는 것처럼 이므로 직렬화 가능 으로 설명됩니다(실제로 리소스는 일부 트랜잭션이 동시에 진행할 수 있도록 종종 알고리즘을 최적화할 수 있음).
REPEATABLE_READ
-
트랜잭션이 데이터베이스를 읽거나 업데이트할 때마다 트랜잭션이 종료될 때까지 읽기 또는 쓰기 잠금을 확보하고 유지됩니다. 이는 거의 완벽한 격리를 제공합니다. 그러나 격리가 완전하지 않은 한 가지 사례가 있습니다. a Cryostat 절을 사용하여 행 범위를 읽는 SQL
SELECT
문을 고려하십시오.다른 트랜잭션이 첫 번째 트랜잭션이 실행 중인 동안 이 범위에 행을 추가하는 경우 첫 번째 트랜잭션에서 새 행을 볼 수 있습니다.If another transaction adds a row to this range while the first transaction is running, the first transaction can see this new row, if it repeats the
SELECT
call (a phantom read). READ_COMMITTED
- 쓰기 잠금은 트랜잭션이 종료될 때까지 유지됩니다. 읽기 잠금은 트랜잭션이 종료될 때까지 유지되지 않습니다. 결과적으로 다른 트랜잭션에서 커밋한 업데이트가 진행중인 트랜잭션에 표시되므로 반복된 읽기가 다른 결과를 제공할 수 있습니다.Consequently, repeated reads can give different results because updates committed by other transactions become visible to an ongoing transaction.
READ_UNCOMMITTED
- 읽기 잠금 또는 쓰기 잠금은 트랜잭션이 종료될 때까지 유지되지 않습니다. 따라서 더티 읽기가 가능합니다. 더티 준비는 다른 트랜잭션에 의해 커밋되지 않은 변경 사항이 진행 중인 트랜잭션에 표시되는 경우입니다.
일반적으로 데이터베이스는 다양한 트랜잭션 격리 수준을 모두 지원하지 않습니다. 예를 들어 일부 무료 데이터베이스는 READ_UNCOMMITTED
만 지원합니다. 또한 일부 데이터베이스는 ANSI 표준과 하위 다른 방식으로 트랜잭션 격리 수준을 구현합니다. 격리는 데이터베이스 성능과의 거래 중단과 관련된 복잡한 문제입니다(예: Wiki 의 격리를 참조하십시오).
1.7.1.2. XA 표준에 대한 지원
리소스가 여러 리소스가 포함된 트랜잭션에 참여하려면 X/Open XA 표준을 지원해야 합니다. 리소스의 XA 표준 구현에 특수 제한 사항이 적용되는지 확인하십시오. 예를 들어 XA 표준의 일부 구현은 단일 데이터베이스 연결로 제한되므로 한 번에 하나의 스레드만 해당 리소스를 포함하는 트랜잭션을 처리할 수 있습니다.
1.7.2. 트랜잭션 관리자가 제공하는 서비스의 특성
다음 기능은 트랜잭션 관리자의 서비스 품질을 결정합니다.
1.7.2.1. 일시 중단/재사용 및 연결/수집 지원
일부 트랜잭션 관리자는 다음과 같이 트랜잭션 컨텍스트와 애플리케이션 스레드 간의 연결을 조작하기 위한 고급 기능을 지원합니다.
- 애플리케이션이 현재 스레드에서 일부 비-전달 작업을 수행하는 동안 현재 트랜잭션 컨텍스트를 일시적으로 일시 중단할 수 있습니다.Sust/resume current transaction-enables you to suspend temporarily the current transaction context, while the application does some non- Cryostatal work in the current thread.
- attach/detach 트랜잭션 컨텍스트 - 한 스레드에서 다른 스레드로 트랜잭션 컨텍스트를 이동하거나 여러 스레드를 포함하도록 트랜잭션 범위를 확장할 수 있습니다.Aach/detach transaction context -enables you to move a transaction context from one thread to another or to extend a transaction scope to include multiple threads.
1.7.2.2. 여러 리소스 지원
트랜잭션 관리자의 주요 차이점은 여러 리소스를 지원하는 기능입니다. 이는 일반적으로 XA 표준을 지원하며 트랜잭션 관리자는 XA 스위치를 등록하는 리소스에 대한 방법을 제공합니다.
엄격하게 말하면 XA 표준은 여러 리소스를 지원하는 데 사용할 수있는 유일한 접근 방식은 아니지만 가장 실용적인 방법입니다. 대안은 일반적으로 XA 스위치에서 일반적으로 제공하는 알고리즘을 구현하기 위해 번거 (및 중요한) 사용자 정의 코드를 작성하는 것과 관련이 있습니다.
1.7.2.3. 분산 트랜잭션
일부 트랜잭션 관리자는 범위에 분산 시스템에 여러 노드가 포함된 트랜잭션을 관리하는 기능이 있습니다. 트랜잭션 컨텍스트는 WS-AtomicTransactions 또는 CORBA OTS와 같은 특수 프로토콜을 사용하여 노드에서 노드로 전파됩니다.
1.7.2.4. 트랜잭션 모니터링
고급 트랜잭션 관리자는 일반적으로 보류 중인 트랜잭션의 상태를 모니터링하는 시각적 도구를 제공합니다. 이러한 종류의 도구는 시스템 오류 후 특히 유용합니다. 이 경우 불명확한 상태에 남아 있는 트랜잭션을 식별하고 해결하는 데 도움이 될 수 있습니다(심각적인 예외).
1.7.2.5. 실패에서 복구
시스템 장애 (crash) 발생시 트랜잭션 관리자 사이에는 강력한 차이점이 있습니다. 트랜잭션 관리자가 사용하는 주요 전략은 트랜잭션의 각 단계를 수행하기 전에 영구 로그에 데이터를 쓰는 것입니다. 오류가 발생하는 경우 로그의 데이터를 사용하여 트랜잭션을 복구할 수 있습니다. 일부 거래 관리자는이 전략을 다른 전략보다 더 신중하게 구현합니다. 예를 들어 고급 트랜잭션 관리자는 일반적으로 영구 트랜잭션 로그를 복제하고 각 로그를 별도의 호스트 시스템에 저장할 수 있습니다.
2장. Karaf (OSGi)에서 트랜잭션 시작하기
이 섹션에서는 트랜잭션을 사용하여 Artemis JMS 브로커에 액세스하는 Camel 애플리케이션을 설명합니다. 정보는 다음과 같이 구성됩니다.
2.1. 사전 요구 사항
이 Camel 애플리케이션의 구현에는 다음과 같은 사전 요구 사항이 있습니다.
외부 AMQ 7 JMS 메시지 브로커가 실행 중이어야 합니다.
다음 샘플 코드는
amq-broker-7.1.0-bin.zip
의 독립 실행형 (Docker이 아닌) 버전을 실행합니다. 실행은amq7
인스턴스를 생성하고 실행합니다.$ pwd /data/servers/amq-broker-7.1.0 $ bin/artemis create --user admin --password admin --require-login amq7 Creating ActiveMQ Artemis instance at: /data/servers/amq-broker-7.1.0/amq7 Auto tuning journal ... done! Your system can make 27.78 writes per millisecond, your journal-buffer-timeout will be 36000 You can now start the broker by executing: "/data/servers/amq-broker-7.1.0/amq7/bin/artemis" run Or you can run the broker in the background using: "/data/servers/amq-broker-7.1.0/amq7/bin/artemis-service" start $ amq7/bin/artemis run __ __ ____ ____ _ /\ | \/ |/ __ \ | _ \ | | / \ | \ / | | | | | |_) |_ __ ___ | | _____ _ __ / /\ \ | |\/| | | | | | _ <| '__/ _ \| |/ / _ \ '__| / ____ \| | | | |__| | | |_) | | | (_) | < __/ | /_/ \_\_| |_|\___\_\ |____/|_| \___/|_|\_\___|_| Red Hat JBoss AMQ 7.1.0.GA 018-05-02 16:37:19,294 INFO [org.apache.activemq.artemis.integration.bootstrap] AMQ101000: Starting ActiveMQ Artemis Server ...
클라이언트 라이브러리가 필요합니다. Artemis 라이브러리는 Maven Central 또는 Red Hat 리포지토리에서 사용할 수 있습니다. 예를 들어 다음을 사용할 수 있습니다.
-
mvn:org.apache.activemq/artemis-core-client/2.4.0.amq-710008-redhat-1
-
mvn:org.apache.activemq/artemis-jms-client/2.4.0.amq-710008-redhat-1
또는 Artemis/AMQ 7 클라이언트 라이브러리는 Karaf 기능으로 설치할 수 있습니다. 예를 들면 다음과 같습니다.
-
Karaf@root()> feature:install artemis-jms-client artemis-core-client
-
Karaf 쉘 명령 또는 전용 Artemis 지원을 제공하는 일부 지원 기능이 필요합니다.
karaf@root()> feature:install jms pax-jms-artemis pax-jms-config
필수 Camel 기능은 다음과 같습니다.
karaf@root()> feature:install camel-jms camel-blueprint
2.2. camel-jms 프로젝트 빌드
Fuse Software Downloads 페이지에서 빠른 시작을
다운로드할 수 있습니다.
zip 파일의 내용을 로컬 폴더(예: quickstarts
라는 새 폴더 )로 추출합니다.
그런 다음 OSGi 번들로 /camel/camel-jms
예제를 빌드하고 설치할 수 있습니다. 이 번들에는 AMQ 7 JMS 큐로 메시지를 전송하는 Camel 경로에 대한 블루프린트 XML 정의가 포함되어 있습니다.
다음 예에서 $FUSE_HOME
은 압축 해제된 Fuse 배포의 위치입니다. 이 프로젝트를 빌드하려면 다음을 수행합니다.
Maven을 호출하여 프로젝트를 빌드합니다.
$ cd quickstarts $ mvn clean install -f camel/camel-jms/
javax.jms.ConnectionFactory
서비스가 OSGi 런타임에 게시되도록 JMS 연결 팩토리 구성을 생성합니다. 이렇게 하려면quickstarts/camel/camel-jms/src/main/resources/etc/org.ops4j.connectionfactory-amq7.cfg
를$FUSE_HOME/etc
디렉터리에 복사합니다. 이 구성은 작업 연결 팩토리를 생성하기 위해 처리됩니다. 예를 들면 다음과 같습니다.$ cp camel/camel-jms/src/main/resources/etc/org.ops4j.connectionfactory-amq7.cfg ../etc/
게시된 연결 팩토리를 확인합니다.
karaf@root()> service:list javax.jms.ConnectionFactory [javax.jms.ConnectionFactory] ----------------------------- felix.fileinstall.filename = file:$FUSE_HOME/etc/org.ops4j.connectionfactory-amq7.cfg name = artemis osgi.jndi.service.name = artemis password = admin pax.jms.managed = true service.bundleid = 251 service.factoryPid = org.ops4j.connectionfactory service.id = 436 service.pid = org.ops4j.connectionfactory.d6207fcc-3fe6-4dc1-a0d8-0e76ba3b89bf service.scope = singleton type = artemis url = tcp://localhost:61616 user = admin Provided by : OPS4J Pax JMS Config (251) karaf@root()> jms:info -u admin -p admin artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1 karaf@root()> jms:queues -u admin -p admin artemis JMS Queues ──────────────────────────────────── df2501d1-aa52-4439-b9e4-c0840c568df1 DLQ ExpiryQueue
번들을 설치합니다.
karaf@root()> install -s mvn:org.jboss.fuse.quickstarts/camel-jms/7.0.0.redhat-SNAPSHOT Bundle ID: 256
작동하는지 확인합니다.
karaf@root()> camel:context-list Context Status Total # Failed # Inflight # Uptime ------- ------ ------- -------- ---------- ------ jms-example-context Started 0 0 0 2 minutes karaf@root()> camel:route-list Context Route Status Total # Failed # Inflight # Uptime ------- ----- ------ ------- -------- ---------- ------ jms-example-context file-to-jms-route Started 0 0 0 2 minutes jms-example-context jms-cbr-route Started 0 0 0 2 minutes
-
Camel 경로가 시작된 즉시 Fuse 설치에 디렉토리,
work/jms/input
가 표시됩니다. 이 빠른 시작의src/main/data
디렉토리에서 찾은 파일을 새로 생성된work/jms/input
디렉터리에 복사합니다. 잠시 기다렸다가 국가별로 구성된 동일한 파일이
work/jms/output
디렉토리 아래에 있습니다.-
work/jms/output/others
의order1.xml
,order2.xml
및order4.xml
-
work/jms/output/us
의order3.xml
및order5.xml
-
work/jms/output/fr
의order6.xml
-
비즈니스 로깅을 확인하려면 로그를 참조하십시오.
2018-05-02 17:20:47,952 | INFO | ile://work/jms/input | file-to-jms-route | 58 - org.apache.camel.camel-core - 2.21.0.fuse-000077 | Receiving order order1.xml 2018-05-02 17:20:48,052 | INFO | umer[incomingOrders] | jms-cbr-route | 58 - org.apache.camel.camel-core - 2.21.0.fuse-000077 | Sending order order1.xml to another country 2018-05-02 17:20:48,053 | INFO | umer[incomingOrders] | jms-cbr-route | 58 - org.apache.camel.camel-core - 2.21.0.fuse-000077 | Done processing order1.xml
큐가 동적으로 생성되었는지 확인합니다.
karaf@root()> jms:queues -u admin -p admin artemis JMS Queues ──────────────────────────────────── DLQ 17767323-937f-4bad-a403-07cd63311f4e ExpiryQueue incomingOrders
Camel 경로 통계를 확인합니다.
karaf@root()> camel:route-info jms-example-context file-to-jms-route Camel Route file-to-jms-route Camel Context: jms-example-context State: Started State: Started Statistics Exchanges Total: 1 Exchanges Completed: 1 Exchanges Failed: 0 Exchanges Inflight: 0 Min Processing Time: 67 ms Max Processing Time: 67 ms Mean Processing Time: 67 ms Total Processing Time: 67 ms Last Processing Time: 67 ms Delta Processing Time: 67 ms Start Statistics Date: 2018-05-02 17:14:17 Reset Statistics Date: 2018-05-02 17:14:17 First Exchange Date: 2018-05-02 17:20:48 Last Exchange Date: 2018-05-02 17:20:48
2.3. camel-jms 프로젝트에 대한 설명
Camel 경로는 다음 끝점 URI를 사용합니다.
<route id="file-to-jms-route"> ... <to uri="jms:queue:incomingOrders?transacted=true" /> </route> <route id="jms-cbr-route"> <from uri="jms:queue:incomingOrders?transacted=true" /> ... </route>
jms
구성 요소는 다음 스니펫을 사용하여 구성됩니다.
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <reference interface="javax.jms.ConnectionFactory" /> </property> <property name="transactionManager" ref="transactionManager"/> </bean>
transactionManager
참조는 다음과 같습니다.
<reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
위 화면과 같이, PlatformTransactionManager
의 JMS 연결 팩토리와 Spring 인터페이스 모두 참조일 뿐입니다. 블루프린트 XML에서 정의할 필요가 없습니다. 이러한 서비스는 Fuse 자체에 의해 노출됩니다.
javax.jms.ConnectionFactory
는 etc/org.ops4j.connectionfactory-amq7.cfg
를 사용하여 생성된 것을 이미 확인했습니다.
트랜잭션 관리자는 다음과 같습니다.
karaf@root()> service:list org.springframework.transaction.PlatformTransactionManager [org.springframework.transaction.PlatformTransactionManager] ------------------------------------------------------------ service.bundleid = 21 service.id = 527 service.scope = singleton Provided by : Red Hat Fuse :: Fuse Modules :: Transaction (21) Used by: Red Hat Fuse :: Quickstarts :: camel-jms (256)
실제 트랜잭션 관리자가 등록된 다른 인터페이스를 확인합니다.
karaf@root()> headers 21 Red Hat Fuse :: Fuse Modules :: Transaction (21) ------------------------------------------------ ... Bundle-Name = Red Hat Fuse :: Fuse Modules :: Transaction Bundle-SymbolicName = fuse-pax-transx-tm-narayana Bundle-Vendor = Red Hat ... karaf@root()> bundle:services -p 21 Red Hat Fuse :: Fuse Modules :: Transaction (21) provides: ---------------------------------------------------------- objectClass = [org.osgi.service.cm.ManagedService] service.bundleid = 21 service.id = 519 service.pid = org.ops4j.pax.transx.tm.narayana service.scope = singleton ---- objectClass = [javax.transaction.TransactionManager] provider = narayana service.bundleid = 21 service.id = 520 service.scope = singleton ---- objectClass = [javax.transaction.TransactionSynchronizationRegistry] provider = narayana service.bundleid = 21 service.id = 523 service.scope = singleton ---- objectClass = [javax.transaction.UserTransaction] provider = narayana service.bundleid = 21 service.id = 524 service.scope = singleton ---- objectClass = [org.jboss.narayana.osgi.jta.ObjStoreBrowserService] provider = narayana service.bundleid = 21 service.id = 525 service.scope = singleton ---- objectClass = [org.ops4j.pax.transx.tm.TransactionManager] provider = narayana service.bundleid = 21 service.id = 526 service.scope = singleton ---- objectClass = [org.springframework.transaction.PlatformTransactionManager] service.bundleid = 21 service.id = 527 service.scope = singleton
트랜잭션 관리자는 다음 인터페이스에서 사용할 수 있습니다.
-
javax.transaction.TransactionManager
-
javax.transaction.TransactionSynchronizationRegistry
-
javax.transaction.UserTransaction
-
org.jboss.narayana.osgi.jta.ObjStoreBrowserService
-
org.ops4j.pax.transx.tm.TransactionManager
-
org.springframework.transaction.PlatformTransactionManager
필요한 모든 컨텍스트에서 사용할 수 있습니다. 예를 들어 camel-jms
를 사용하려면 org.apache.camel.component.jms.JmsConfiguration. CryostatManager
필드를 초기화해야 합니다. 이 예제에서는 다음을 사용합니다.
<reference id="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
대신 예를 들면 다음과 같습니다.
<reference id="transactionManager" interface="javax.transaction.TransactionManager" />
3장. 트랜잭션 관리자를 구성하고 참조하는 인터페이스
Cryostat 및 Spring Boot는 각각 Fuse에서 트랜잭션 관리자를 구성하고 배포된 애플리케이션에서 트랜잭션 관리자를 사용하기 위한 트랜잭션 클라이언트 인터페이스를 제공합니다. 관리 작업인 구성과 개발 작업인 구성을 명확하게 구분할 수 있습니다. 애플리케이션 개발자는 이전에 구성된 트랜잭션 관리자를 대상으로 애플리케이션을 가리킵니다.
3.1. 트랜잭션 관리자의 역할
트랜잭션 관리자는 하나 이상의 리소스에서 트랜잭션을 조정하는 데 책임이 있는 애플리케이션의 일부입니다. 거래 관리자의 책임은 다음과 같습니다.
- 분리 - start, commit, rollback 메서드를 사용하여 트랜잭션을 시작하고 종료합니다.
- 트랜잭션 컨텍스트 관리 - 트랜잭션 컨텍스트에는 트랜잭션 관리자가 트랜잭션을 추적하는 데 필요한 정보가 포함됩니다.Managing the transaction context - a transaction context contains the information that a transaction manager needs to keep track of a transaction. 트랜잭션 관리자는 트랜잭션 컨텍스트를 생성하고 현재 스레드에 연결합니다.
여러 리소스에 걸쳐 트랜잭션 조정 - 엔터프라이즈 수준 트랜잭션 관리자는 일반적으로 여러 리소스 간에 트랜잭션을 조정하는 기능을 갖습니다. 이 기능을 사용하려면 2단계 커밋 프로토콜이 필요하며 XA 프로토콜을 사용하여 리소스를 등록하고 관리해야 합니다. 1.7.1.2절. “XA 표준에 대한 지원”을 참조하십시오.
이는 모든 트랜잭션 관리자가 지원하지 않는 고급 기능입니다.
- 실패에서 복구 - 트랜잭션 관리자는 시스템 오류가 발생하고 애플리케이션이 실패하는 경우 리소스가 일관되지 않은 상태로 유지되지 않도록 할 책임이 있습니다. 경우에 따라 시스템을 일관된 상태로 복원하려면 수동 개입이 필요할 수 있습니다.
3.2. 로컬, 글로벌 및 분산 트랜잭션 관리자 정보
트랜잭션 관리자는 로컬, 글로벌 또는 배포될 수 있습니다.
3.2.1. 로컬 트랜잭션 관리자 정보
로컬 트랜잭션 관리자는 단일 리소스에 대해서만 트랜잭션을 조정할 수 있는 트랜잭션 관리자입니다. 로컬 트랜잭션 관리자의 구현은 일반적으로 리소스 자체에 포함되어 있으며 애플리케이션에서 사용하는 트랜잭션 관리자는 이 기본 제공 트랜잭션 관리자에 대한 씬 래퍼입니다.
예를 들어 Oracle 데이터베이스에는 중복 작업(SQL BEGIN
,COMMIT
또는 ROLLBACK
문을 사용하거나 네이티브 Oracle API를 사용하여) 및 다양한 트랜잭션 격리 수준을 지원하는 기본 제공 트랜잭션 관리자가 있습니다. Oracle 트랜잭션 관리자에 대한 제어는 JDBC를 통해 내보낼 수 있으며, 이 JDBC API는 애플리케이션에서 트랜잭션을 위임하는 데 사용됩니다.
이 컨텍스트에서 리소스를 구성하는 사항을 이해하는 것이 중요합니다. 예를 들어 JMS 제품을 사용하는 경우 JMS 리소스는 개별 대기열과 주제가 아닌 JMS 제품의 단일 실행 인스턴스입니다. 또한 동일한 기본 리소스에 다른 방식으로 액세스하면 여러 리소스가 실제로 단일 리소스일 수 있습니다. 예를 들어 애플리케이션은 관계형 데이터베이스에 직접(DBC를 통해) 직접 및 간접적으로( Hibernate와 같은 객체 관계형 매핑 툴을 통해)에 액세스할 수 있습니다. 이 경우 동일한 기본 트랜잭션 관리자가 관련되므로 두 코드 조각을 동일한 트랜잭션에 등록할 수 있어야 합니다.
이 방법이 모든 경우에 효과적이라는 것을 보장할 수는 없습니다. 기본적으로 가능한 경우도 있지만 Spring Framework 또는 기타 래퍼 계층의 설계에서 일부 세부 사항으로 인해 실제로 작동하지 않을 수 있습니다.
애플리케이션에는 서로 독립적으로 작동하는 다양한 로컬 트랜잭션 관리자가 있을 수 있습니다. 예를 들어 JMS 끝점이 JMS 트랜잭션 관리자를 참조하는 JMS 대기열 및 주제를 조작하는 Camel 경로가 한 개 있을 수 있습니다. 다른 경로는 JDBC를 통해 관계형 데이터베이스에 액세스할 수 있습니다. 그러나 JDBC 및 JMS 액세스를 동일한 경로에 결합하고 둘 다 동일한 트랜잭션에 참여하도록 할 수 없습니다.
3.2.2. 글로벌 트랜잭션 관리자 정보
글로벌 트랜잭션 관리자는 여러 리소스에 대해 트랜잭션을 조정할 수 있는 트랜잭션 관리자입니다. 이는 리소스 자체에 빌드된 트랜잭션 관리자를 사용할 수 없는 경우 필요합니다. 트랜잭션 처리 모니터(TP 모니터)라고도 하는 외부 시스템은 다양한 리소스 간에 트랜잭션을 조정할 수 있습니다.
다음은 여러 리소스에서 작동하는 트랜잭션에 대한 사전 요구 사항입니다.
- 글로벌 트랜잭션 관리자 또는 TP 모니터 - 여러 XA 리소스를 조정하기 위해 2단계 커밋 프로토콜을 구현하는 외부 트랜잭션 시스템입니다.
- XA 표준을 지원하는 리소스 - 2단계 커밋에 참여하려면 리소스는 XA 표준을 지원해야 합니다. 1.7.1.2절. “XA 표준에 대한 지원”을 참조하십시오. 실제로 이는 리소스가 XA 스위치 오브젝트를 내보낼 수 있으므로 외부 TP 모니터에 대한 트랜잭션을 완전히 제어할 수 있습니다.
Spring Framework는 글로벌 트랜잭션을 관리하기 위한 TP 모니터를 자체적으로 제공하지 않습니다. 그러나 OSGi 제공 TP 모니터 또는 Cryostat 제공 TP 모니터( JtaTransactionManager 클래스에서 통합이 구현되는 경우)와의 통합을 지원합니다. 따라서 전체 트랜잭션 지원이 포함된 OSGi 컨테이너에 애플리케이션을 배포하는 경우 Spring에서 여러 트랜잭션 리소스를 사용할 수 있습니다.
3.2.3. 분산 트랜잭션 관리자 정보
일반적으로 서버는 트랜잭션과 관련된 리소스에 직접 연결합니다. 그러나 분산 시스템에서는 웹 서비스를 통해 간접적으로 노출되는 리소스에만 연결해야 합니다. 이 경우 분산 트랜잭션을 지원할 수 있는 TP 모니터가 필요합니다. 다양한 분산 프로토콜에 대한 트랜잭션을 지원하는 방법을 설명하는 여러 표준을 사용할 수 있습니다(예: 웹 서비스에 대한 WS-AtomicTransactions 사양).
3.3. Cryostat 트랜잭션 클라이언트 사용
Cryostat를 사용하는 경우 트랜잭션 관리자와 상호 작용하는 가장 많은 지원 대상 및 표준 방법은 Java Transaction API (JTA) 인터페이스 javax. Cryostat.UserTransaction
입니다. 표준 사용은 다음과 같습니다.
InitialContext context = new InitialContext(); UserTransaction ut = (UserTransaction) context.lookup("java:comp/UserTransaction"); ut.begin(); // Access transactional, JTA-aware resources such as database and/or message broker ut.commit(); // or ut.rollback()
JNDI(Java Naming and Directory Interface)에서 UserTransaction
인스턴스를 얻는 것이 트랜잭션 클라이언트를 가져오는 한 가지 방법입니다. Cryostat 환경에서는 CDI(컨텍스트 및 종속성 주입)와 같이 트랜잭션 클라이언트에 액세스할 수 있습니다.
다음 그림은 typica Cryostat Camel 애플리케이션을 보여줍니다.

이 그림은 Camel 코드와 애플리케이션 코드가 모두 액세스할 수 있음을 보여줍니다.
-
Spring
TransactionTemplate
클래스를 사용하여 애플리케이션에서 또는 내부적으로 트랜잭션 인식 Camel 구성 요소를 통해 트랜잭션을 직접 위임하는javax. Cryostat.UserTransaction
인스턴스입니다. -
JDBC API를 직접 또는 예를 들어 Spring의
JdbcTemplate
을 사용하거나camel-jdbc
구성 요소를 사용하여 데이터베이스입니다. -
Spring의
JmsTemplate
클래스를 사용하거나camel-jms
구성 요소를 사용하여 JMS API를 직접 통한 메시지 브로커입니다.
javax. Cryostat.UserTransaction
오브젝트를 사용하는 경우 트랜잭션 클라이언트에서만 직접 작업하기 때문에 사용 중인 실제 트랜잭션 관리자를 알 필요가 없습니다. ( 1.3절. “트랜잭션 클라이언트 정보” 참조) 내부적으로 Spring의 트랜잭션 기능을 사용하므로 Spring과 Camel이 다른 접근 방식을 취합니다.
JavaEE Application
일반적인 Cryostat 시나리오에서는 애플리케이션이 Cryostat 애플리케이션 서버(일반적으로 WAR
또는 EAR
아카이브)로 배포됩니다. JNDI 또는 CDI를 통해 애플리케이션은 javax. Cryostat.UserTransaction
서비스의 인스턴스에 액세스할 수 있습니다. 그런 다음, 제거에서는 이 트랜잭션 클라이언트 인스턴스를 사용하여 트랜잭션을 분리합니다. 트랜잭션 내에서 애플리케이션은 JDBC 및/또는 JMS 액세스를 수행합니다.
Camel 구성 요소 및 애플리케이션 코드
이는 JMS/JDBC 작업을 수행하는 코드를 나타냅니다. Camel에는 JMS/JDBC 리소스에 액세스하는 자체 고급 방법이 있습니다. 애플리케이션 코드는 지정된 API를 직접 사용할 수 있습니다.
JMS 연결 Cryostat
javax.jms.ConnectionFactory
인터페이스이며 javax.jms.Connection
인스턴스를 가져온 다음 javax.jms.Session
(또는 JMS 2.0의 javax.jms.JmsContext
)을 가져오는 데 사용됩니다. 이는 애플리케이션에서 직접 사용하거나 내부적으로 org.springframework.jms.core.JmsTemplate
을 사용할 수 있는 Camel 구성 요소에서 간접적으로 사용할 수 있습니다. 애플리케이션 코드나 Camel 구성 요소에는 이 연결 팩토리에 대한 세부 정보가 필요하지 않습니다. 연결 팩토리는 애플리케이션 서버에서 구성됩니다. 이 구성은 Cryostat 서버에서 확인할 수 있습니다. Fuse와 같은 OSGi 서버는 비슷합니다. 시스템 관리자는 애플리케이션과 독립적으로 연결 팩토리를 구성합니다. 일반적으로 연결 팩토리에서는 풀링 기능을 구현합니다.
JDBC 데이터 소스
java.sql.Connection
의 인스턴스를 가져오는 데 사용되는 javax.sql.DataSource
인터페이스입니다. JMS와 마찬가지로 이 데이터 소스는 직접 또는 간접적으로 사용될 수 있습니다. 예를 들어 camel-sql
구성 요소는 내부적으로 org.springframework.jdbc.core.JdbcTemplate
클래스를 사용합니다. JMS와 마찬가지로 애플리케이션 코드나 Camel에는 이 데이터 소스에 대한 세부 정보가 필요하지 않습니다. 구성은 4장. Narayana 트랜잭션 관리자 구성 에 설명된 방법을 사용하여 애플리케이션 서버 또는 OSGi 서버 내부에서 수행됩니다.
3.4. Spring Boot 트랜잭션 클라이언트 사용
Spring Framework(및 Spring Boot)의 주요 목표 중 하나는 Cryostat API를 더 쉽게 사용할 수 있도록 하는 것입니다. 모든 주요 Cryostat vanilla API는 Spring Framework (Spring Boot)에 포함됩니다. 이는 지정된 API의 대체 또는 대체 가 아니라 더 많은 구성 옵션 또는 더 일관된 사용량을 추가하는 래퍼(예: 예외 처리와 관련하여)입니다.
다음 표는 지정된 Cryostat API와 해당 Spring 관련 인터페이스와 일치합니다.
JavaEE API | Spring 유틸리티 | 다음으로 구성됨 |
---|---|---|
JDBC |
|
|
JMS |
|
|
JTA |
|
|
JdbcTemplate
및 JmsTemplate
은 각각 javax.sql.DataSource
및 javax.jms.ConnectionFactory
를 직접 사용합니다. 그러나 TransactionTemplate
은 PlatformTransactionManager
의 Spring 인터페이스를 사용합니다. 여기서 Spring은 단순히 Cryostat를 개선하는 것이 아니라 Cryostat 클라이언트 API를 자체적으로 대체합니다.
Spring은 javax. Cryostat.UserTransaction
을 실제 시나리오에 비해 너무 간단한 인터페이스로 처리합니다. 또한 javax. Cryostat.UserTransaction
은 로컬, 단일 리소스 트랜잭션과 글로벌, 다중 리소스 트랜잭션, org.springframework. Cryostat.PlatformTransactionManager
구현을 통해 개발자에게 더 많은 자유를 제공합니다.
다음은 Spring Boot의 정식 API 사용법입니다.
// Create or get from ApplicationContext or injected with @Inject/@Autowired. JmsTemplate jms = new JmsTemplate(...); JdbcTemplate jdbc = new JdbcTemplate(...); TransactionTemplate tx = new TransactionTemplate(...); tx.execute((status) -> { // Perform JMS operations within transaction. jms.execute((SessionCallback<Object>)(session) -> { // Perform operations on JMS session return ...; }); // Perform JDBC operations within transaction. jdbc.execute((ConnectionCallback<Object>)(connection) -> { // Perform operations on JDBC connection. return ...; }); return ...; });
위의 예에서 세 가지 유형의 템플릿 은 모두 간단히 인스턴스화되지만 Spring의 ApplicationContext
에서 얻거나 @Autowired
주석을 사용하여 삽입될 수도 있습니다.
3.4.1. Spring PlatformTransactionManager 인터페이스 사용
앞서 언급했듯이 javax. Cryostat.UserTransaction
은 일반적으로 Cryostat 애플리케이션의 JNDI에서 가져옵니다. 그러나 Spring은 많은 시나리오에서 이 인터페이스를 명시적으로 구현합니다. 항상 전체 JTA 시나리오가 필요하지는 않으며 애플리케이션에서 단일 리소스(예: JDBC)에 액세스해야 하는 경우가 있습니다.
일반적으로 org.springframework.PlatformTransactionManager
는 클래식 트랜잭션 클라이언트 작업( 시작
,커밋
및 롤백
)을 제공하는 Spring 트랜잭션 클라이언트 API입니다. 즉, 이 인터페이스는 런타임 시 트랜잭션을 제어하는 데 필수 메서드를 제공합니다.
트랜잭션 시스템의 다른 주요 측면은 트랜잭션 리소스를 구현하기 위한 API입니다. 그러나 트랜잭션 리소스는 일반적으로 기본 데이터베이스에 의해 구현되므로 트랜잭션 프로그래밍의 이러한 측면은 애플리케이션 구현에 거의 관련이 없습니다.
3.4.1.1. PlatformTransactionManager 인터페이스 정의
public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
3.4.1.2. TransactionDefinition 인터페이스 정보
TransactionDefinition
인터페이스를 사용하여 새로 생성된 트랜잭션의 특성을 지정합니다. 격리 수준 및 새 트랜잭션의 전파 정책을 지정할 수 있습니다. 자세한 내용은 9.4절. “트랜잭션 전파 정책”의 내용을 참조하십시오.
3.4.1.3. TransactionStatus 인터페이스 정의
TransactionStatus
인터페이스를 사용하여 현재 트랜잭션, 즉 현재 스레드와 연결된 트랜잭션의 상태를 확인하고 롤백을 위해 현재 트랜잭션을 표시할 수 있습니다. 인터페이스 정의입니다.
public interface TransactionStatus extends SavepointManager, Flushable { boolean isNewTransaction(); boolean hasSavepoint(); void setRollbackOnly(); boolean isRollbackOnly(); void flush(); boolean isCompleted(); }
3.4.1.4. PlatformTransactionManager 인터페이스에서 정의하는 방법
PlatformTransactionManager
인터페이스는 다음 방법을 정의합니다.
- getTransaction()
-
새 트랜잭션을 만들고 새 트랜잭션의 특성을 정의하는 TransactionDefinition 개체를 전달하여 현재 스레드와 연결합니다.Creates a new transaction and associates it with the current thread by passing in a
TransactionDefinition
object that defines the characteristics of the new transaction. 이는 다른 많은 트랜잭션 클라이언트 API의begin()
메서드와 유사합니다. - commit()
- 등록된 리소스에 대한 보류 중인 모든 변경 사항을 영구적으로 만드는 현재 트랜잭션을 커밋합니다.
- rollback()
- 등록된 리소스에 대한 보류 중인 모든 변경 사항을 취소하는 현재 트랜잭션을 롤백합니다.
3.4.2. 트랜잭션 관리자를 사용하는 단계
일반적으로 PlatformTransactionManager
인터페이스를 직접 사용하지 않습니다. Apache Camel에서는 일반적으로 다음과 같이 트랜잭션 관리자를 사용합니다.
- 트랜잭션 관리자의 인스턴스를 만듭니다. Spring에는 다양한 구현이 있습니다. 3.4절. “Spring Boot 트랜잭션 클라이언트 사용”을 참조하십시오.
-
트랜잭션 관리자 인스턴스를 Apache Camel 구성 요소 또는 경로의
transacted()
DSL 명령에 전달합니다. 그런 다음 트랜잭션 구성 요소 또는transacted()
명령은 트랜잭션 분리를 담당합니다. 자세한 내용은 9장. 트랜잭션을 사용하는 Camel 애플리케이션 작성에서 참조하십시오.
3.4.3. Spring PlatformTransactionManager 구현 정보
이 섹션에서는 Spring Framework에서 제공하는 트랜잭션 관리자 구현에 대한 간략한 개요를 제공합니다. 이러한 구현은 로컬 트랜잭션 관리자와 글로벌 트랜잭션 관리자의 두 가지 범주로 분류됩니다.
Camel부터 시작:
-
camel-jms
구성 요소에서 사용하는org.apache.camel.component.jms.JmsConfiguration
오브젝트에는org.springframework. Cryostat.PlatformTransactionManager
인터페이스의 인스턴스가 필요합니다. -
org.apache.camel.component.sql.SqlComponent
는org.springframework.jdbc.core.JdbcTemplate
클래스를 내부적으로 사용하며 이 JDBC 템플릿은org.springframework. Cryostat.PlatformTransactionManager
와도 통합됩니다.
위 화면과 같이 이 인터페이스의 일부 구현이 있어야 합니다. 시나리오에 따라 필요한 플랫폼 트랜잭션 관리자를 구성할 수 있습니다.
3.4.3.1. 로컬 PlatformTransactionManager 구현
아래 목록에는 Spring Framework에서 제공하는 로컬 트랜잭션 관리자 구현이 요약되어 있습니다. 이러한 트랜잭션 관리자는 단일 리소스만 지원합니다.
- org.springframework.jms.connection.JmsTransactionManager
- 이 트랜잭션 관리자 구현은 단일 JMS 리소스를 관리할 수 있습니다. 여러 큐 또는 주제에 연결할 수 있지만 동일한 기본 JMS 메시징 제품 인스턴스에 속하는 경우에만 사용할 수 있습니다. 또한 다른 유형의 리소스를 트랜잭션에 등록할 수 없습니다.
- org.springframework.jdbc.datasource.DataSourceTransactionManager
- 이 트랜잭션 관리자 구현은 단일 JDBC 데이터베이스 리소스를 관리할 수 있습니다. 여러 다른 데이터베이스 테이블을 업데이트할 수 있지만 동일한 기본 데이터베이스 인스턴스에 속하는 경우에만 업데이트할 수 있습니다.
- org.springframework.orm.jpa.JpaTransactionManager
- 이 트랜잭션 관리자 구현은 Java Persistence API(JPA) 리소스를 관리할 수 있습니다. 그러나 트랜잭션에서 다른 종류의 리소스를 동시에 등록할 수는 없습니다.
- org.springframework.orm.hibernate5.HibernateTransactionManager
- 이러한 트랜잭션 관리자 구현은 Hibernate 리소스를 관리할 수 있습니다. 그러나 트랜잭션에서 다른 종류의 리소스를 동시에 등록할 수는 없습니다. 또한 JPA API는 기본 Hibernate API보다 우선합니다.
또한 덜 자주 사용되는 다른 PlatformTransactionManager
구현도 있습니다.
3.4.3.2. 글로벌 PlatformTransactionManager 구현
Spring Framework는 OSGi 런타임에서 사용할 수 있도록 하나의 글로벌 트랜잭션 관리자 구현을 제공합니다. org.springframework. Cryostat.jta.JtaTransactionManager
는 트랜잭션의 여러 리소스에 대한 작업을 지원합니다. 이 트랜잭션 관리자는 XA 트랜잭션 API를 지원하며 트랜잭션에 두 개 이상의 리소스를 등록할 수 있습니다. 이 트랜잭션 관리자를 사용하려면 OSGi 컨테이너 또는 Cryostat 서버 내에 애플리케이션을 배포해야 합니다.
PlatformTransactionManager
의 단일 리소스 구현은 실제 구현 이지만JtaTransactionManager
는 표준 javax. Cryostat.TransactionManager
의 실제 구현에 대한 래퍼가 더 많습니다.
따라서 이미 구성된 javax. Cryostat.TransactionManager 및 일반적으로 javax. Cryostat.
구현을 사용하는 것이 좋습니다. 일반적으로 이러한 두 JTA 인터페이스는 단일 오브젝트/서비스로 구현됩니다.
UserTransaction
의 인스턴스에 액세스 할 수 있는 환경에서 PlatformTransactionManager
의 JtaTransactionManager
다음은 JtaTransactionManager
구성/사용의 예입니다.
InitialContext context = new InitialContext(); UserTransaction ut = (UserTransaction) context.lookup("java:comp/UserTransaction"); TransactionManager tm = (TransactionManager) context.lookup("java:/TransactionManager"); JtaTransactionManager jta = new JtaTransactionManager(); jta.setUserTransaction(ut); jta.setTransactionManager(tm); TransactionTemplate jtaTx = new TransactionTemplate(jta); jtaTx.execute((status) -> { // Perform resource access in the context of global transaction. return ...; });
위의 예에서 JTA 오브젝트(UserTransaction
및 TransactionManager
)의 실제 인스턴스는 JNDI에서 가져옵니다. OSGi에서는 OSGi 서비스 레지스트리에서도 가져올 수 있습니다.
3.5. OSGi는 트랜잭션 클라이언트와 트랜잭션 관리자 간의 인터페이스
Cryostat 트랜잭션 클라이언트 API 및 Spring Boot 트랜잭션 클라이언트 API에 대한 설명 후 Fuse와 같은 OSGi 서버 내의 관계를 확인하는 것이 도움이 됩니다. OSGi의 기능 중 하나는 글로벌 서비스 레지스트리이며 다음과 같이 사용할 수 있습니다.
- 필터 또는 인터페이스를 통해 서비스를 조회합니다.
- 지정된 인터페이스 및 속성으로 서비스를 등록합니다.
Cryostat 애플리케이션 서버에 배포된 애플리케이션이 JNDI(서비스 Cryostat 메서드)를 사용하여 javax. Cryostat.UserTransaction
에 대한 참조를 얻거나 OSGi에서 CDI(종속적 또는종속 항목 주입 방법)를 사용하여 삽입하는 것과 동일한 방식으로 다음과 같은 방법으로 동일한 참조(직접 또는 간접적으로)를 얻을 수 있습니다.
-
org.osgi.framework.BundleContext.getServiceReference()
메서드 호출(서비스). - 블루프린트 컨테이너에 삽입됩니다.
- SCR(Service Component Runtime) 주석(종속성 주입)을 사용합니다.
다음 그림은 OSGi 런타임에 배포된 Fuse 애플리케이션을 보여줍니다. 애플리케이션 코드 및/또는 Camel 구성 요소는 해당 API를 사용하여 트랜잭션 관리자, 데이터 소스 및 연결 팩토리에 대한 참조를 가져옵니다.

애플리케이션(번들)은 OSGi 레지스트리에 등록된 서비스와 상호 작용합니다. 액세스는 인터페이스를 통해 수행되며 이는 애플리케이션과 관련이 있어야 합니다.
Fuse에서 (직접 또는 작은 래퍼를 통해) 트랜잭션 클라이언트 인터페이스를 구현하는 기본 오브젝트는 org.jboss.narayana.osgi.jta.internal.OsgiTransactionManager
입니다. 다음 인터페이스를 사용하여 트랜잭션 관리자에 액세스할 수 있습니다.
-
javax.transaction.TransactionManager
-
javax.transaction.UserTransaction
-
org.springframework.transaction.PlatformTransactionManager
-
org.ops4j.pax.transx.tm.TransactionManager
이러한 인터페이스를 직접 사용하거나 Camel과 같은 프레임워크 또는 라이브러리를 선택하여 암시적으로 사용할 수 있습니다.
Fuse에서 org.jboss.narayana.osgi.jta.internal.OsgiTransactionManager
를 구성하는 방법에 대한 자세한 내용은 4장. Narayana 트랜잭션 관리자 구성 을 참조하십시오. 이 가이드의 뒷부분에서는 해당 장의 정보를 살펴보고 JDBC 데이터 소스 및 JMS 연결 팩토리와 같은 다른 서비스를 구성하고 사용하는 방법을 설명합니다.
4장. Narayana 트랜잭션 관리자 구성
Fuse에서 내장된 글로벌 트랜잭션 관리자는 JBoss Narayana Transaction Manager 로, EAP(Enterprise Application Platform) 7에서 사용하는 트랜잭션 관리자와 동일합니다.
Fuse for Karaf와 마찬가지로 OSGi 런타임에서는 PAX TRANSX 프로젝트에서 추가 통합 계층을 제공합니다.
다음 항목에서는 Narayana 구성에 대해 설명합니다.
4.1. Narayana 설치 정보
Narayana 트랜잭션 관리자는 다음 인터페이스의 OSGi 번들과 몇 가지 추가 지원 인터페이스에서 사용하기 위해 노출됩니다.
-
javax.transaction.TransactionManager
-
javax.transaction.UserTransaction
-
org.springframework.transaction.PlatformTransactionManager
-
org.ops4j.pax.transx.tm.TransactionManager
7.8.0.fuse-780038-redhat-00001
배포를 통해 처음부터 이러한 인터페이스를 사용할 수 있습니다.
pax-transx-tm-narayana
기능에는 Narayana를 포함하는 재정의된 번들이 포함되어 있습니다.
karaf@root()> feature:info pax-transx-tm-narayana Feature pax-transx-tm-narayana 0.3.0 Feature has no configuration Feature has no configuration files Feature depends on: pax-transx-tm-api 0.0.0 Feature contains followed bundles: mvn:org.jboss.fuse.modules/fuse-pax-transx-tm-narayana/7.0.0.fuse-000191-redhat-1 (overriden from mvn:org.ops4j.pax.transx/pax-transx-tm-narayana/0.3.0) Feature has no conditionals.
fuse-pax-transx-tm-narayana
번들에서 제공하는 서비스는 다음과 같습니다.
karaf@root()> bundle:services fuse-pax-transx-tm-narayana Red Hat Fuse :: Fuse Modules :: Transaction (21) provides: ---------------------------------------------------------- [org.osgi.service.cm.ManagedService] [javax.transaction.TransactionManager] [javax.transaction.TransactionSynchronizationRegistry] [javax.transaction.UserTransaction] [org.jboss.narayana.osgi.jta.ObjStoreBrowserService] [org.ops4j.pax.transx.tm.TransactionManager] [org.springframework.transaction.PlatformTransactionManager]
이 번들은 org.osgi.service.cm.ManagedService
를 등록하므로 CM 구성의 변경 사항을 추적하고 대응합니다.
karaf@root()> bundle:services -p fuse-pax-transx-tm-narayana Red Hat Fuse :: Fuse Modules :: Transaction (21) provides: ---------------------------------------------------------- objectClass = [org.osgi.service.cm.ManagedService] service.bundleid = 21 service.id = 232 service.pid = org.ops4j.pax.transx.tm.narayana service.scope = singleton ...
기본 org.ops4j.pax.transx.tm.narayana
PID는 다음과 같습니다.
karaf@root()> config:list '(service.pid=org.ops4j.pax.transx.tm.narayana)' ---------------------------------------------------------------- Pid: org.ops4j.pax.transx.tm.narayana BundleLocation: ? Properties: com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.localOSRoot = communicationStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.objectStoreDir = /data/servers/7.8.0.fuse-780038-redhat-00001/data/narayana com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.objectStoreType = com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.localOSRoot = defaultStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.objectStoreDir = /data/servers/7.8.0.fuse-780038-redhat-00001/data/narayana com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.objectStoreType = com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.stateStore.localOSRoot = stateStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.stateStore.objectStoreDir = /data/servers/7.8.0.fuse-780038-redhat-00001/data/narayana com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.stateStore.objectStoreType = com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean.recoveryBackoffPeriod = 10 felix.fileinstall.filename = file:/data/servers/7.8.0.fuse-780038-redhat-00001/etc/org.ops4j.pax.transx.tm.narayana.cfg service.pid = org.ops4j.pax.transx.tm.narayana
요약:
- Fuse for Karaf에는 완전한 기능을 갖춘 글로벌, 네라나나 트랜잭션 관리자가 포함되어 있습니다.
- 트랜잭션 관리자는 다양한 클라이언트 인터페이스(JTA, Spring-tx, PAX JMS)에서 올바르게 노출됩니다.
-
org.ops4j.pax.transx.tm.narayana
에서 사용할 수 있는 표준 OSGi 메서드인 Configuration Admin을 사용하여 Narayana를 구성할 수 있습니다. -
기본 구성은
$FUSE_HOME/etc/org.ops4j.pax.transx.tm.narayana.cfg
에 제공됩니다.
4.2. 지원되는 트랜잭션 프로토콜
Narayana 트랜잭션 관리자는 EAP에서 사용되는 JBoss/Red Hat 제품입니다. Narayana는 광범위한 표준 기반 트랜잭션 프로토콜을 사용하여 개발된 애플리케이션을 지원하는 트랜잭션 툴킷입니다.
- JTA
- JTS
- Web-Service 트랜잭션
- REST 트랜잭션
- STM
- XATMI/TX
4.3. narayana 구성 정보
pax-transx-tm-narayana
번들에는 트랜잭션 관리자의 다양한 측면에 대한 기본 구성을 제공하는 jbossts-properties.xml
파일이 포함되어 있습니다. 이러한 속성은 모두 $FUSE_HOME/etc/org.ops4j.pax.transx.tm.narayana.cfg
파일에서 직접 또는 Configuration Admin API를 사용하여 재정의될 수 있습니다.
narayana의 기본 구성은 다양한 EnvironmentBean
오브젝트를 통해 수행됩니다. 이러한 모든 Cryostat는 접두사가 다른 속성을 사용하여 구성할 수 있습니다. 다음 표에서는 사용되는 구성 오브젝트 및 접두사에 대한 요약을 제공합니다.
구성 Cryostat | 속성 접두사 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
접두사 는 구성을 단순화할 수 있습니다. 그러나 일반적으로 다음 형식 중 하나를 사용해야 합니다.
NameEnvironmentBean.propertyName
(기본 형식) 또는
fully-qualified-class-name.field-name
예를 들어 com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean.commitOnePhase
필드를 고려하십시오. com.arjuna.ats.arjuna.common.CoordinatorEnvironment.commitOnePhase
속성을 사용하거나 더 간단한 (preferred) 양식 CoordinatorEnvironmentBean.commitOnePhase
속성을 사용하여 구성할 수 있습니다. 속성을 설정하는 방법과 구성할 수 있는 빈에 대한 자세한 내용은 Narayana 제품 문서에서 확인할 수 있습니다.
ObjectStoreEnvironmentBean
과 같은 일부 빈은 다른 용도로 구성을 제공하는 각 명명된 인스턴스에서 여러 번 구성할 수 있습니다. 이 경우 인스턴스 이름은 접두사(위의 항목 모두)와 필드 이름
사이에 사용됩니다. 예를 들어 이름이 communicationStore
인 ObjectStoreEnvironmentBean
인스턴스의 오브젝트 저장소 유형은 이름이 지정된 속성을 사용하여 구성할 수 있습니다.
-
com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.objectStoreType
-
ObjectStoreEnvironmentBean.communicationStore.objectStoreType
4.4. 로그 스토리지 구성
가장 중요한 구성은 오브젝트 로그 스토리지의 유형 및 위치입니다. 일반적으로 com.arjuna.ats.arjuna.objectstore.ObjectStoreAPI
인터페이스의 세 가지 구현이 있습니다.
- com.arjuna.ats.internal.arjuna.objectstore.hornetq.HornetqObjectStoreAdaptor
-
AMQ 7의
org.apache.activemq.artemis.core.journal
스토리지를 내부적으로 사용합니다. - com.arjuna.ats.internal.arjuna.objectstore.jdbc.JDBCStore
- JDBC를 사용하여 TX 로그 파일을 유지합니다.
- com.arjuna.ats.internal.arjuna.objectstore.FileSystemStore (및 특수 구현)
- 사용자 정의 파일 기반 로그 스토리지를 사용합니다.
기본적으로 Fuse는 FileSystemStore
의 특수 구현인 com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore
를 사용합니다.
Narayana가 트랜잭션/오브젝트 로그를 보관하는 데 사용되는 세 개의 저장소가 있습니다.
-
defaultStore
-
communicationStore
-
stateStore
자세한 내용은 State Management in Narayana 설명서 를 참조하십시오.
이 세 저장소 의 기본 구성은 다음과 같습니다.
# default store com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.objectStoreType = com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.objectStoreDir = ${karaf.data}/narayana com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.localOSRoot = defaultStore # communication store com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.objectStoreType = com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.objectStoreDir = ${karaf.data}/narayana com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.communicationStore.localOSRoot = communicationStore # state store com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.stateStore.objectStoreType = com.arjuna.ats.internal.arjuna.objectstore.ShadowNoFileLockStore com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.stateStore.objectStoreDir = ${karaf.data}/narayana com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean.stateStore.localOSRoot = stateStore
CryostatNoFileLockStore
는 기본 디렉터리(objectStoreDir
) 및 특정 저장소의 디렉터리(localOSRoot
)로 구성됩니다.
많은 설정 옵션은 나레이나 설명서 가이드에 포함되어 있습니다. 그러나 Narayana 설명서는 구성 옵션에 대한 표준 참조가 다양한 EnvironmentBean
클래스의 Javadoc임을 나타냅니다.
5장. Narayana 트랜잭션 관리자 사용
이 섹션에서는 javax. Cryostat. UserTransaction 인터페이스,
인터페이스를 구현하여 Narayana org.springframework. Cryostat.PlatformTransactionManager 인터페이스 또는 javax
. Cryostat.Transaction트랜잭션
관리자를 사용하는 데 대한 세부 정보를 제공합니다. 사용할 인터페이스는 애플리케이션 요구 사항에 따라 다릅니다. 이 장의 끝에는 XA 리소스 등록의 문제 해결에 대한 논의가 있습니다. 정보는 다음과 같이 구성됩니다.
Java 트랜잭션 API 세부 정보는 JTA(Java Transaction API) 1.2 사양 및 Javadoc 를 참조하십시오.
5.1. UserTransaction 오브젝트 사용
트랜잭션 혼동을 위한 javax. Cryostat.UserTransaction
인터페이스를 구현합니다. 즉, 트랜잭션을 시작, 커밋 또는 롤백합니다. 애플리케이션 코드에서 직접 사용할 가능성이 가장 높은 JTA 인터페이스입니다. 그러나 UserTransaction
인터페이스는 트랜잭션을 위임하는 방법 중 하나일 뿐입니다. 트랜잭션을 분류할 수 있는 다양한 방법에 대한 설명은 9장. 트랜잭션을 사용하는 Camel 애플리케이션 작성 에서 참조하십시오.
5.1.1. UserTransaction 인터페이스 정의
JTA UserTransaction
인터페이스는 다음과 같이 정의됩니다.
public interface javax.transaction.UserTransaction { public void begin(); public void commit(); public void rollback(); public void setRollbackOnly(); public int getStatus(); public void setTransactionTimeout(int seconds); }
5.1.2. UserTransaction 메서드에 대한 설명
UserTransaction
인터페이스는 다음 방법을 정의합니다.
- begin()
- 새 트랜잭션을 시작하고 현재 스레드와 연결합니다.Starts a new transaction and associates it with the current thread. XA 리소스가 이 트랜잭션과 연결된 경우 트랜잭션은 암시적으로 XA 트랜잭션이 됩니다.
- commit()
보류 중인 모든 변경 사항이 영구적으로 되도록 현재 트랜잭션을 정상적으로 완료합니다. 커밋 후 현재 스레드와 연결된 트랜잭션이 더 이상 없습니다.
참고그러나 현재 트랜잭션이 롤백으로만 표시되면
commit()
이 호출될 때 트랜잭션이 실제로 롤백됩니다.- rollback()
- 보류 중인 모든 변경 사항이 삭제되도록 즉시 트랜잭션을 중지합니다. 롤백 후에는 더 이상 현재 스레드와 연결된 트랜잭션이 없습니다.
- setRollbackOnly()
- 롤백이 유일한 결과이지만 아직 롤백을 수행하지 않도록 현재 트랜잭션의 상태를 수정합니다.
- getStatus()
javax. Cryostat.Status 인터페이스에 정의된 대로 다음 정수 값 중 하나일 수 있는 현재 트랜잭션의 상태를 반환합니다.
-
STATUS_ACTIVE
-
STATUS_COMMITTED
-
STATUS_COMMITTING
-
STATUS_MARKED_ROLLBACK
-
STATUS_NO_TRANSACTION
-
STATUS_PREPARED
-
STATUS_PREPARING
-
STATUS_ROLLEDBACK
-
STATUS_ROLLING_BACK
-
STATUS_UNKNOWN
-
- setTransactionTimeout()
- 초 단위로 지정된 현재 트랜잭션의 시간 초과를 사용자 지정합니다. 지정된 타임아웃 내에서 트랜잭션이 해결되지 않으면 트랜잭션 관리자가 자동으로 롤백합니다.
5.2. TransactionManager 오브젝트 사용
javax. Cryostat.TransactionManager
오브젝트를 사용하는 가장 일반적인 방법은 프레임워크 API(예: Camel JMS 구성 요소)에 전달하는 것입니다. 이를 통해 프레임워크에서 트랜잭션 혼동을 확인할 수 있습니다. 경우에 따라 TransactionManager
개체를 직접 사용하려는 경우가 있습니다. 이 기능은 suspend()
및 resume()
메서드와 같은 고급 트랜잭션 API에 액세스해야 하는 경우에 유용합니다.
5.2.1. TransactionManager 인터페이스 정의
JTA TransactionManager 인터페이스에는 다음과 같은 정의가 있습니다.
interface javax.transaction.TransactionManager { // Same as UserTransaction methods public void begin(); public void commit(); public void rollback(); public void setRollbackOnly(); public int getStatus(); public void setTransactionTimeout(int seconds); // Extra TransactionManager methods public Transaction getTransaction(); public Transaction suspend() ; public void resume(Transaction tobj); }
5.2.2. TransactionManager 메서드 설명
TransactionManager
인터페이스는 UserTransaction
인터페이스에 있는 모든 메서드를 지원합니다. TransactionManager
오브젝트를 트랜잭션 분리에 사용할 수 있습니다. 또한 TransactionManager
오브젝트는 다음 메서드를 지원합니다.
- getTransaction()
-
현재 스레드와 연결된 트랜잭션인 현재 트랜잭션에 대한 참조를 가져옵니다.Gets a reference to the current transaction, which is the transaction that is associated with the current thread. 현재 트랜잭션이 없는 경우 이 메서드는
null
을 반환합니다. - suspend()
현재 스레드에서 현재 트랜잭션을 분리하고 트랜잭션에 대한 참조를 반환합니다.Detaches the current transaction from the current thread and returns a reference to the transaction. 이 메서드를 호출한 후 현재 스레드에 더 이상 트랜잭션 컨텍스트가 없습니다.After calling this method, the current thread no longer has a transaction context. 이 시점 이후에 수행하는 작업은 더 이상 트랜잭션 컨텍스트에서 수행되지 않습니다.
참고모든 트랜잭션 관리자가 트랜잭션 일시 중지를 지원하지는 않습니다. 그러나 이 기능은 나레이나에서 지원합니다.
- resume()
- 일시 중지된 트랜잭션을 현재 스레드 컨텍스트에 다시 연결합니다. 이 메서드를 호출한 후 트랜잭션 컨텍스트가 복원되고 이 시점 이후의 모든 작업이 트랜잭션 컨텍스트에서 수행됩니다.After calling this method, the transaction context is restored and any work that you do after this point is done in the context of a transaction.
5.3. 트랜잭션 오브젝트 사용
트랜잭션을 일시 중지/사용하거나 리소스를 명시적으로 추가해야 하는 경우 javax. Cryostat.Transaction
오브젝트를 직접 사용해야 할 수 있습니다. 5.4절. “XA 등록 문제 해결” 에서 설명한 대로 프레임워크 또는 컨테이너는 일반적으로 리소스 등록에 자동으로 처리됩니다.
5.3.1. 트랜잭션 인터페이스 정의
JTA 트랜잭션
인터페이스에는 다음과 같은 정의가 있습니다.
interface javax.transaction.Transaction { public void commit(); public void rollback(); public void setRollbackOnly(); public int getStatus(); public boolean enlistResource(XAResource xaRes); public boolean delistResource(XAResource xaRes, int flag); public void registerSynchronization(Synchronization sync); }
5.3.2. 트랜잭션 메서드 설명
commit()
, rollback()
, setRollbackOnly()
및 getStatus()
메서드는 UserTransaction
인터페이스에서 해당 메서드와 동일한 동작을 갖습니다. 실제로 UserTransaction
오브젝트는 현재 트랜잭션을 검색한 다음 트랜잭션 오브젝트에서 해당 메서드를 호출하는 편리한 래퍼입니다.
또한 트랜잭션
인터페이스는 UserTransaction
인터페이스에 해당하지 않는 다음 메서드를 정의합니다.
- enlistResource()
XA 리소스를 현재 트랜잭션에 연결합니다.
참고이 방법은 XA 트랜잭션 컨텍스트에서 중요합니다. XA 트랜잭션을 특성화하는 현재 트랜잭션과 함께 여러 XA 리소스를 등록할 수 있는 기능을 정확하게 설명합니다. 반면, 명시적으로 리소스를 등록하는 것은 간과이며 일반적으로 프레임워크 또는 컨테이너가 이를 수행할 것으로 예상합니다. 예를 들면 5.4절. “XA 등록 문제 해결” 을 참조하십시오.
- delistResource()
지정된 리소스를 트랜잭션에서 연결 해제합니다. 플래그 인수는
javax. Cryostat.Transaction 인터페이스에 정의된 다음 정수 값 중 하나를 사용할 수 있습니다.
-
TMSUCCESS
-
TMFAIL
-
TMSUSPEND
-
- registerSynchronization()
-
javax. Cryostat.Synchronization
개체를 현재 트랜잭션에 등록합니다.Synchronization
오브젝트는 커밋 준비 단계 직전에 콜백을 수신하고 트랜잭션이 완료된 직후 콜백을 수신합니다.
5.4. XA 등록 문제 해결
XA 리소스를 등록하기 위한 표준 JTA 접근 방식은 현재 트랜잭션을 나타내는 현재 javax. Cryostat.Transaction
오브젝트에 XA 리소스를 명시적으로 추가하는 것입니다. 즉, 새 트랜잭션이 시작될 때마다 XA 리소스를 명시적으로 추가해야 합니다.
5.4.1. XA 리소스에 가입하는 방법
트랜잭션을 사용하여 XA 리소스를 등록하려면 트랜잭션 인터페이스에서
합니다. 예를 들어 enlistResource()
메서드를 호출해야TransactionManager
개체와 XAResource 개체가 지정되면 다음과 같이 XAResource
개체를 등록할 수 있습니다.For example, given a TransactionManager object and an XAResource
object, you could enlist the XAResource object as follows:
// Java import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.xa.XAResource; ... // Given: // 'tm' of type TransactionManager // 'xaResource' of type XAResource // Start the transaction tm.begin(); Transaction transaction = tm.getTransaction(); transaction.enlistResource(xaResource); // Do some work... ... // End the transaction tm.commit();
리소스 등록의 까다로운 측면은 각 새 트랜잭션에 리소스를 등록해야 하며 리소스를 사용하기 전에 리소스를 등록해야 한다는 것입니다. 리소스를 명시적으로 추가하는 경우 enlistResource()
호출을 사용하여 리터링된 오류-prone 코드로 끝날 수 있습니다. 또한 적절한 위치에서 enlistResource()
를 호출하기 어려울 수 있습니다. 예를 들어 일부 트랜잭션 세부 정보를 숨기는 프레임워크를 사용하는 경우입니다.
5.4.2. 자동 목록 정보
XA 리소스를 명시적으로 등록하지 않고 XA 리소스의 자동 목록을 지원하는 기능을 사용하는 것이 더 쉽고 안전합니다. 예를 들어 JMS 및 JDBC 리소스 사용 컨텍스트에서 표준 기술은 자동 목록을 지원하는 래퍼 클래스를 사용하는 것입니다.
JDBC 및 JMS 액세스 모두에 대한 일반적인 패턴은 다음과 같습니다.
-
애플리케이션 코드는 JDBC 액세스에는
javax.sql.DataSource
와 JMS의 경우javax.jms.ConnectionFactory
가 JDBC 또는 JMS 연결을 가져와야 합니다. - 애플리케이션/OSGi 서버 내에서 이러한 인터페이스의 데이터베이스 또는 브로커 특정 구현이 등록됩니다.
- 애플리케이션/OSGi 서버는 데이터베이스/broker별 팩토리를 일반, 풀링, 인 목록에 포함된 팩토리로 래핑 합니다.
이러한 방식으로 애플리케이션 코드는 여전히 javax.sql.DataSource
및 javax.jms.ConnectionFactory
를 사용하지만 내부적으로 액세스하면 일반적으로 다음과 같은 추가 기능이 있습니다.
- 연결 풀링 - 매번 데이터베이스/메시지 브로커에 대한 새 연결을 생성하는 대신 사전 초기화된 연결 풀이 사용됩니다. 풀링 의 또 다른 측면은 예를 들어 연결의 주기적인 검증일 수 있습니다.
-
JTA 등록 -
java.sql.Connection
(JDBC) 또는javax.jms.Connection
(JMS)의 인스턴스를 반환하기 전에 실제 연결 개체가 실제 XA 리소스인 경우 등록됩니다. JTA 트랜잭션에서 등록이 가능한 경우 등록이 수행됩니다.
자동 목록을 사용하면 애플리케이션 코드를 변경할 필요가 없습니다.
JDBC 데이터 소스 및 JMS 연결 팩토리에 대한 래퍼 풀링 및 등록에 대한 자세한 내용은 6장. JDBC 데이터 소스 사용 및 7장. JMS 연결 팩토리 사용 를 참조하십시오.
6장. JDBC 데이터 소스 사용
다음 주제에서는 Fuse OSGi 런타임의 JDBC 데이터 소스 사용에 대해 설명합니다.
6.1. 연결 인터페이스 정보
데이터 조작을 수행하는 데 사용되는 가장 중요한 오브젝트 는 java.sql.Connection
인터페이스 구현입니다. Fuse 구성 관점에서 Connection
개체를 가져오는 방법을 알아야 합니다.
관련 오브젝트가 포함된 라이브러리는 다음과 같습니다.
-
PostgreSQL:
mvn:org.postgresql/postgresql/42.2.5
-
MySQL:
mvn:mysql/mysql-connector-java/5.1.34
기존 구현( 드라이버 JAR에 포함)은다음을 제공합니다.
-
PostgreSQL:
org.postgresql.jdbc.PgConnection
-
MySQL:
com.mysql.jdbc.JDBC4Connection
(com.mysql.jdbc.Driver
의 다양한connect*()
메서드 참조)
이러한 구현에는 DML, DDL 및 간단한 트랜잭션 관리를 수행하는 데이터베이스별 논리가 포함됩니다.
이론적으로는 이러한 연결 오브젝트를 수동으로 생성할 수 있지만 더 깔끔한 API를 제공하기 위해 세부 정보를 숨기는 두 가지 JDBC 방법이 있습니다.
-
java.sql.Driver.connect()
- 이 방법은 오래 전에 독립 실행형 애플리케이션에서 사용되었습니다. -
javax.sql.DataSource.getConnection()
- 팩토리 패턴을 사용하는 데 권장되는 방법입니다. 유사한 방법은 JMS 연결 팩토리에서 JMS 연결을 가져오는 데 사용됩니다.
드라이버 관리자 접근 방식은 여기에서 논의되지 않습니다. 이 메서드는 지정된 연결 개체에 대한 일반 생성자보다 작은 계층 임을 명시하는 것으로 충분합니다.
데이터베이스별 통신 프로토콜을 효과적으로 구현하는 java.sql.Connection
외에도 다른 두 가지 특수 연결 인터페이스가 있습니다.
-
javax.sql.PooledConnection
은 물리적 연결을 나타냅니다. 코드가 이 풀링된 연결과 직접 상호 작용하지 않습니다. 대신getConnection()
메서드에서 얻은 연결이 사용됩니다. 이 방법을 사용하면 애플리케이션 서버 수준에서 연결 풀을 관리할 수 있습니다.getConnection()
을 사용하여 얻은 연결은 일반적으로 프록시입니다. 이러한 프록시 연결이 닫히면 물리적 연결이 닫히지 않고 관리되는 연결 풀에서 다시 사용할 수 있게 됩니다. -
javax.sql.XAConnection
을 사용하면javax. Cryostat.
개체를 가져올 수 있습니다.TransactionManager와 함께 사용하기 위해 XA 인식 연결과 연결된 javax. Cryostat.xa.
XAResourcejavax.sql.XAConnection
은javax.sql.PooledConnection을 확장하므로 일반적인 DML/DQL 메서드를 사용하여 JDBC 연결 오브젝트에 대한 액세스를 제공하는 'getConnection() 메서드도 제공합니다
.
6.2. JDBC 데이터 소스 개요
JDBC 1.4 표준에는 java.sql.Connection
개체의 팩토리 역할을 하는 javax.sql.DataSource
인터페이스가 도입되었습니다. 일반적으로 이러한 데이터 소스는 JNDI 레지스트리에 바인딩되어 있고 서블릿 또는 Clevis와 같은 Java EE 구성 요소에 있거나 삽입되었습니다. 주요 측면은 이러한 데이터 소스가 애플리케이션 서버 내에 구성되고 배포된 애플리케이션에서 이름별로 참조 된다는 것입니다.
다음 연결 오브젝트에는 자체 데이터 소스가 있습니다.
데이터 소스 | 연결 |
---|---|
|
|
|
|
|
|
위의 각 데이터 소스 의 가장 중요한 차이점은 다음과 같습니다.
javax.sql.DataSource
는java.sql.Connection
인스턴스를 가져오기 위한 것과 같은 팩토리입니다. 대부분의javax.sql.DataSource
구현이 일반적으로 연결 풀링 을 수행한다는 사실은 이미지를 변경하지 않아야 합니다. 애플리케이션 코드에서 사용해야 하는 유일한 인터페이스입니다. 다음 중 어느 것을 구현했는지는 중요하지 않습니다.- 직접 JDBC 액세스
-
JPA 지속성 유닛 구성(<
jta-data-source
> 또는 <non-jta-data-source
> ) - Apache Camel 또는 Spring Framework와 같은 널리 사용되는 라이브러리
javax.sql.ConnectionPoolDataSource
는 가장 중요한 것은 일반(비 데이터베이스별) 연결 풀/데이터 소스와 데이터베이스별 데이터 소스 간의 브릿지 입니다. SPI 인터페이스로 취급될 수 있습니다. 애플리케이션 코드는 일반적으로 JNDI에서 가져와 애플리케이션 서버에서 구현한 일반적인javax.sql.DataSource
개체를 처리합니다(commons-dbcp2
와 같은 라이브러리를 사용). 애플리케이션 코드는javax.sql.ConnectionPoolDataSource
와 직접 상호 작용하지 않습니다. 애플리케이션 서버와 데이터베이스별 드라이버 간에 사용됩니다. 다음 시퀀스 다이어그램에서는 다음을 보여줍니다.
javax.sql.XADataSource
는javax.sql.XAConnection
및javax. Cryostat.xa.XAResource
를 얻는 방법입니다.javax.sql.ConnectionPoolDataSource
와 동일하며 애플리케이션 서버와 데이터베이스별 드라이버 간에 사용됩니다. 다음은 JTA 트랜잭션 관리자를 포함하여 다른 행위자와 함께 약간 수정된 다이어그램입니다.
위의 두 다이어그램에 표시된 대로 javax.sql.DataSource
및 javax. Cryostat.UserTransaction
인스턴스를 구성할 수 있는 일반화된 엔터티인 App Server 와 상호 작용합니다. 이러한 인스턴스는 JNDI를 통해 또는 CDI 또는 다른 종속성 메커니즘을 사용하여 주입하여 액세스할 수 있습니다.
중요한 점은 애플리케이션이 XA 트랜잭션 및/또는 연결 풀링을 사용하는 경우에도 애플리케이션은 다른 두 JDBC 데이터 소스 인터페이스가 아닌 javax.sql.DataSource
와 상호 작용한다는 것입니다.
6.2.1. 데이터베이스 특정 및 일반 데이터 소스
JDBC 데이터 소스 구현은 다음 두 가지 범주로 분류됩니다.
다음과 같은 일반적인
javax.sql.DataSource
구현- Apache Commons DBCP(2)
- Apache Tomcat JDBC (DBCP 기반)
-
javax.sql.DataSource
,javax.sql.XADataSource
및javax.sql.ConnectionPoolDataSource
의 데이터베이스 특정 구현
일반적인 javax.sql.DataSource
구현이 자체적으로 데이터베이스별 연결을 만들 수 없다는 혼동을 줄 수 있습니다. 일반 데이터 소스에서 java.sql.Driver.connect()
또는 java.sql.DriverManager.getConnection()
을 사용할 수 있는 경우에도 일반적으로 데이터베이스별 javax.sql.DataSource
구현을 사용하여 이 일반 데이터 소스를 구성하는 것이 좋습니다.
일반 데이터 소스가 JTA와 상호 작용하려면 javax.sql.XADataSource
의 데이터베이스별 구현으로 구성해야 합니다.
작업을 종료하기 위해 일반적인 데이터 소스에 는 일반적으로 연결 풀링을 수행하기 위해 javax.sql.ConnectionPoolDataSource
의 데이터베이스별 구현이 필요하지 않습니다. 기존 풀은 일반적으로 표준 JDBC 인터페이스(javax.sql.ConnectionPoolDataSource
및 javax.sql.PooledConnection
) 없이 풀링을 처리하고 대신 자체 사용자 지정 구현을 사용합니다.
6.2.2. 일부 일반 데이터 소스
잘 알려진 일반적인 데이터 소스인 Apache Commons DBCP(2) 샘플을 고려해 보십시오.
javax.sql.XADataSource 구현
DBCP2에는 예상되는 javax.sql.XADataSource
의 구현이 포함되어 있지 않습니다.
javax.sql.ConnectionPoolDataSource implementations
DBCP2 에는 javax.sql.ConnectionPoolDataSource
:org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS
의 구현이 포함됩니다. java.sql.DriverManager.getConnection()
을 호출하여 javax.sql.PooledConnection
개체를 생성합니다. 이 풀은 직접 사용해서는 안되며 다음과 같은 드라이버의 어댑터 로 취급해야 합니다.
-
자체
javax.sql.ConnectionPoolDataSource
구현을 제공하지 마십시오. - 연결 풀에 대한 JDBC 권장 사항에 따라 사용하려고 합니다.
위의 시퀀스 다이어그램에 표시된 대로 드라이버는 javax.sql.ConnectionPoolDataSource
를 직접 또는 org.apache.commons.dbcp2.cpds adapter.DriverAdapterCPDS
어댑터의 도움을 받아 직접 또는 DBCP2는 다음과 같은 애플리케이션 서버 계약을 구현합니다.
-
org.apache.commons.dbcp2.datasources.PerUserPoolDataSource
-
org.apache.commons.dbcp2.datasources.SharedPoolDataSource
두 풀 모두 구성 단계에서 javax.sql.ConnectionPoolDataSource
의 인스턴스를 사용합니다.
DBCP2에서 가장 중요하고 흥미로운 부분입니다.
javax.sql.DataSource 구현
연결 풀링 기능을 구현하려면 JDBC 권장 사항을 따라 javax.sql.ConnectionPoolDataSource
→ javax.sql.PooledConnection
SPI를 사용할 필요가 없습니다.
다음은 DBCP2의 일반 데이터 소스 목록입니다.
-
org.apache.commons.dbcp2.BasicDataSource
-
org.apache.commons.dbcp2.managed.BasicManagedDataSource
-
org.apache.commons.dbcp2.PoolingDataSource
-
org.apache.commons.dbcp2.managed.ManagedDataSource
여기에는 두 개의 축이 있습니다.
기본 및 풀링
이 축 은 풀링 구성 측면을 결정합니다.
두 종류의 데이터 소스 모두 java.sql.Connection
개체의 풀링 을 수행합니다. 유일한 차이점은 다음과 같습니다.
-
기본 데이터 소스는
org.apache.commons.pool2.impl.GenericObjectPool
의 내부 인스턴스를 구성하는 데 사용되는maxTotal
또는minIdle
과 같은 8080 속성을 사용하여 구성됩니다. -
풀링 데이터 소스는 외부에서 생성/구성된
org.apache.commons.pool2.ObjectPool
로 구성됩니다.
Managed vs non-managed
이 축 은 연결 생성 측면과 JTA 동작을 결정합니다.
관리되지 않는 기본 데이터 소스는 내부적으로
java.sql.Driver.connect()
를 사용하여java.sql.Connection
인스턴스를 생성합니다.관리되지 않는 풀링 데이터 소스는 전달된
org.apache.commons.pool2.ObjectPool
개체를 사용하여java.sql.Connection
인스턴스를 생성합니다.관리되는 풀링 데이터 소스는
org.apache.commons.dbcp2.managed.ManagedConnection
개체 내에서java.sql.Connection
인스턴스를 래핑하여 JTA 컨텍스트에서 필요한 경우javax. Cryostat.Transaction.enlistResource()
가 호출되도록 합니다. 그러나 여전히 래핑된 실제 연결은 풀이 구성된 모든org.apache.commons.pool2.ObjectPool
개체에서 가져옵니다.관리형 기본 데이터 소스를 사용하면 전용
org.apache.commons.pool2.ObjectPool
을 구성할 수 없습니다. 대신 기존의 실제 데이터베이스별javax.sql.XADataSource
개체를 구성하는 것으로 충분합니다. Cryostat 속성은org.apache.commons.pool2.impl.GenericObjectPool
의 내부 인스턴스를 생성하는 데 사용되며, 이 인스턴스는 관리되는 풀링 데이터 소스(org.apache.commons.dbcp2.managed.ManagedDataSource
)의 내부 인스턴스에 전달됩니다.
DBCP2에서 할 수 없는 유일한 것은 XA 트랜잭션 복구 입니다. DBCP2는 활성 JTA 트랜잭션에 XAResources를 올바르게 등록하지만 복구를 수행하지 않습니다. 이 작업은 별도로 수행해야 하며 구성은 일반적으로 선택한 트랜잭션 관리자 구현(예: 네레이나 )에 따라 다릅니다.
6.2.3. 사용할 패턴
권장 패턴은 다음과 같습니다.
-
연결/XA 연결을 생성할 수 있는 데이터베이스별
javax.sql.DataSource
또는javax.sql.XADataSource
인스턴스(URL, 인증 정보 등)를 생성하거나 가져옵니다. -
데이터베이스별 구성(연결 풀링, 트랜잭션 관리자 등)을 사용하여 데이터베이스 별
javax.sql.DataSource
인스턴스(위의 데이터베이스별 데이터 소스로 내부 구성)를 생성하거나 가져옵니다. -
javax.sql.DataSource
를 사용하여java.sql.Connection
의 인스턴스를 가져오고 JDBC 작업을 수행합니다.
다음은 표준 예입니다.
// Database-specific, non-pooling, non-enlisting javax.sql.XADataSource PGXADataSource postgresql = new org.postgresql.xa.PGXADataSource(); // Database-specific configuration postgresql.setUrl("jdbc:postgresql://localhost:5432/reportdb"); postgresql.setUser("fuse"); postgresql.setPassword("fuse"); postgresql.setCurrentSchema("report"); postgresql.setConnectTimeout(5); // ... // Non database-specific, pooling, enlisting javax.sql.DataSource BasicManagedDataSource pool = new org.apache.commons.dbcp2.managed.BasicManagedDataSource(); // Delegate to database-specific XADatasource pool.setXaDataSourceInstance(postgresql); // Delegate to JTA transaction manager pool.setTransactionManager(transactionManager); // Non database-specific configuration pool.setMinIdle(3); pool.setMaxTotal(10); pool.setValidationQuery("select schema_name, schema_owner from information_schema.schemata"); // ... // JDBC code: javax.sql.DataSource applicationDataSource = pool; try (Connection c = applicationDataSource.getConnection()) { try (Statement st = c.createStatement()) { try (ResultSet rs = st.executeQuery("select ...")) { // ....
Fuse 환경에는 많은 구성 옵션이 있으며 DBCP2를 사용할 필요가 없습니다.
6.3. JDBC 데이터 소스 구성
OSGi 트랜잭션 아키텍처에서 설명한 대로 일부 서비스는 OSGi 서비스 레지스트리에 등록되어야 합니다. 예를 들어 javax. Cryostat. UserTransaction 인터페이스를 사용하여 트랜잭션 관리자 인스턴스를 찾을 수 있는 것과 마찬가지로
인터페이스를 사용하여 JDBC 데이터 소스에서 동일한 작업을 수행할 수 있습니다. 요구 사항은 다음과 같습니다.
javax.
sql.DataSource
- 대상 데이터베이스와 통신할 수 있는 데이터베이스별 데이터 소스
- 풀링 및 가능한 트랜잭션 관리(XA)를 구성할 수 있는 일반 데이터 소스
Fuse와 같은 OSGi 환경에서는 OSGi 서비스에 등록된 경우 애플리케이션에서 데이터 소스에 액세스할 수 있습니다. 기본적으로 다음과 같이 수행됩니다.
org.osgi.framework.BundleContext.registerService(javax.sql.DataSource.class, dataSourceObject, properties); org.osgi.framework.BundleContext.registerService(javax.sql.XADataSource.class, xaDataSourceObject, properties);
이러한 서비스를 등록하는 방법은 다음 두 가지가 있습니다.
-
jdbc:ds-create
Karaf console 명령을 사용하여 데이터 소스 게시. 구성 방법입니다. -
블루프린트, OSGi 선언 서비스(SCR) 또는
BundleContext.registerService()
API 호출과 같은 메서드를 사용하여 데이터 소스 게시. 이 메서드에는 코드 및/또는 메타데이터가 포함된 전용 OSGi 번들이 필요합니다. 이 방법은 the_deployment method_입니다.
6.4. OSGi JDBC 서비스 사용
OSGi Enterprise R6 사양의 125장에서는 org.osgi.service.jdbc
패키지에서 단일 인터페이스를 정의합니다. 다음은 OSGi에서 데이터 소스를 처리하는 방법입니다.
public interface DataSourceFactory { java.sql.Driver createDriver(Properties props); javax.sql.DataSource createDataSource(Properties props); javax.sql.ConnectionPoolDataSource createConnectionPoolDataSource(Properties props); javax.sql.XADataSource createXADataSource(Properties props); }
앞서 언급했듯이 일반 java.sql.Connection
연결은 java.sql.Driver
에서 직접 가져올 수 있습니다.
Generic org.osgi.service.jdbc.DataSourceFactory
org.osgi.service.jdbc.DataSourceFactory
의 가장 간단한 구현은 org.ops4j.pax.jdbc.impl.DriverDataSourceFactory
입니다. mvn:org.ops4j.pax.jdbc/pax-jdbc/pax-jdbc/1.3.0 번들이 제공하는 org.ops4j
.impl.DriverDataSourceFactory입니다. 이 모든 작업은 표준 Java™ ServiceLoader 유틸리티에 대한 /META-INF/services/java.sql.Driver
설명자를 포함할 수 있는 번들을 추적하는 것입니다. 표준 JDBC 드라이버를 설치하는 경우 pax-jdbc
번들은 java.sql.Driver.connect()
호출을 통해 연결을 가져오기 위해 (직접은 아님) DataSourceFactory
를 등록합니다.
karaf@root()> install -s mvn:org.osgi/org.osgi.service.jdbc/1.0.0 Bundle ID: 223 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc/1.3.0 Bundle ID: 224 karaf@root()> install -s mvn:org.postgresql/postgresql/42.2.5 Bundle ID: 225 karaf@root()> install -s mvn:mysql/mysql-connector-java/5.1.34 Bundle ID: 226 karaf@root()> bundle:services -p org.postgresql.jdbc42 PostgreSQL JDBC Driver JDBC42 (225) provides: --------------------------------------------- objectClass = [org.osgi.service.jdbc.DataSourceFactory] osgi.jdbc.driver.class = org.postgresql.Driver osgi.jdbc.driver.name = PostgreSQL JDBC Driver osgi.jdbc.driver.version = 42.2.5 service.bundleid = 225 service.id = 242 service.scope = singleton karaf@root()> bundle:services -p com.mysql.jdbc Oracle Corporation's JDBC Driver for MySQL (226) provides: ---------------------------------------------------------- objectClass = [org.osgi.service.jdbc.DataSourceFactory] osgi.jdbc.driver.class = com.mysql.jdbc.Driver osgi.jdbc.driver.name = com.mysql.jdbc osgi.jdbc.driver.version = 5.1.34 service.bundleid = 226 service.id = 243 service.scope = singleton ----- objectClass = [org.osgi.service.jdbc.DataSourceFactory] osgi.jdbc.driver.class = com.mysql.fabric.jdbc.FabricMySQLDriver osgi.jdbc.driver.name = com.mysql.jdbc osgi.jdbc.driver.version = 5.1.34 service.bundleid = 226 service.id = 244 service.scope = singleton karaf@root()> service:list org.osgi.service.jdbc.DataSourceFactory [org.osgi.service.jdbc.DataSourceFactory] ----------------------------------------- osgi.jdbc.driver.class = org.postgresql.Driver osgi.jdbc.driver.name = PostgreSQL JDBC Driver osgi.jdbc.driver.version = 42.2.5 service.bundleid = 225 service.id = 242 service.scope = singleton Provided by : PostgreSQL JDBC Driver JDBC42 (225) [org.osgi.service.jdbc.DataSourceFactory] ----------------------------------------- osgi.jdbc.driver.class = com.mysql.jdbc.Driver osgi.jdbc.driver.name = com.mysql.jdbc osgi.jdbc.driver.version = 5.1.34 service.bundleid = 226 service.id = 243 service.scope = singleton Provided by : Oracle Corporation's JDBC Driver for MySQL (226) [org.osgi.service.jdbc.DataSourceFactory] ----------------------------------------- osgi.jdbc.driver.class = com.mysql.fabric.jdbc.FabricMySQLDriver osgi.jdbc.driver.name = com.mysql.jdbc osgi.jdbc.driver.version = 5.1.34 service.bundleid = 226 service.id = 244 service.scope = singleton Provided by : Oracle Corporation's JDBC Driver for MySQL (226)
위의 명령을 사용하면 javax.sql.DataSource
서비스가 아직 등록되지 않았지만 한 발짝 더 가깝습니다. 위의 중간 org.osgi.service.jdbc.DataSourceFactory
서비스를 사용하여 다음을 얻을 수 있습니다.
-
java.sql.Driver
-
속성을 전달하여
javax.sql.DataSource
:url
,user
및password
를createDataSource()
메서드에 전달합니다.
일반 org
sql.XADataSource를 가져올 수 없습니다. .osgi.service.jdbc.DataFactory에서
또는 javax.javax.sql.XADataSource
mvn:org.postgresql/postgresql/42.2.5
번들은 OSGi JDBC 사양을 올바르게 구현하고 org.osgi.service.jdbc.DataSourceFactory
인스턴스를 XA 및 ConnectionPool 데이터 소스를 생성하는 것을 포함하여 구현되는 모든 메서드에 등록합니다.
전용 데이터베이스별 org.osgi.service.jdbc.DataSourceFactory
구현
다음과 같은 추가 번들이 있습니다.
-
mvn:org.ops4j.pax.jdbc/pax-jdbc-mysql/1.3.0
-
mvn:org.ops4j.pax.jdbc/pax-jdbc-db2/1.3.0
- …
이러한 번들은 javax.sql
.DataSourcey 서비스를 등록합니다. 예를 들면 다음과 같습니다.
.ConnectionPoolDataSource
및 javax.sql.XADataSource
를 포함하여 모든 종류의 팩토리 를 반환할 수 있는 데이터베이스별 org.osgi.service.jdbc
karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-mysql/1.3.0 Bundle ID: 227 karaf@root()> bundle:services -p org.ops4j.pax.jdbc.mysql OPS4J Pax JDBC MySQL Driver Adapter (227) provides: --------------------------------------------------- objectClass = [org.osgi.service.jdbc.DataSourceFactory] osgi.jdbc.driver.class = com.mysql.jdbc.Driver osgi.jdbc.driver.name = mysql service.bundleid = 227 service.id = 245 service.scope = singleton karaf@root()> service:list org.osgi.service.jdbc.DataSourceFactory ... [org.osgi.service.jdbc.DataSourceFactory] ----------------------------------------- osgi.jdbc.driver.class = com.mysql.jdbc.Driver osgi.jdbc.driver.name = mysql service.bundleid = 227 service.id = 245 service.scope = singleton Provided by : OPS4J Pax JDBC MySQL Driver Adapter (227)
6.4.1. PAX-JDBC 구성 서비스
pax-jdbc
(또는 pax-jdbc-mysql
,pax-jdbc-oracle
, …) 번들을 사용하면 org.osgi.service.jdbc.DataSourceFactory
서비스가 등록되어 지정된 데이터베이스의 데이터 소스를 가져올 수 있습니다( 6.2.1절. “데이터베이스 특정 및 일반 데이터 소스”참조). 그러나 실제 데이터 소스는 아직 없습니다.
mvn:org.ops4j.pax.jdbc/pax-jdbc-config/1.3.0
번들은 다음 두 가지 작업을 수행하는 관리형 서비스 팩토리를 제공합니다.
메서드를 호출하기 위해
org.osgi.service.jdbc.DataSourceFactory
OSGi 서비스를 추적합니다.public DataSource createDataSource(Properties props); public XADataSource createXADataSource(Properties props); public ConnectionPoolDataSource createConnectionPoolDataSource(Properties props);
-
위의 방법에 필요한 속성을 수집하기 위해
org.ops4j.datasource
팩토리 PID 를 추적합니다. 예를 들어${karaf.etc}/org.ops4j.datasource-mysql.cfg
파일을 생성하여 구성 관리 서비스에 사용할 수 있는 방법을 사용하여 팩토리 구성을 생성하는 경우 최종 단계를 수행하여 실제 데이터베이스별 데이터 소스를 노출할 수 있습니다.
다음은 새로운 Fuse 설치부터 시작하기위한 상세한 표준 단계별 가이드입니다.
필요한 번들을 정확하게 표시하기 위해 기능 대신 번들을 명시적으로 설치합니다. 편의를 위해 PAX JDBC 프로젝트는 여러 데이터베이스 제품 및 구성 접근 방식에 대한 기능을 제공합니다.
Install a JDBC driver with
/META-INF/services/java.sql.Driver
:karaf@root()> install -s mvn:mysql/mysql-connector-java/5.1.34 Bundle ID: 223
중간
org.osgi.service.jdbc.DataSourceFactory
를 등록하는 OSGi JDBC 서비스 번들 및pax-jdbc-mysql
번들을 설치합니다.karaf@root()> install -s mvn:org.osgi/org.osgi.service.jdbc/1.0.0 Bundle ID: 224 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-mysql/1.3.0 Bundle ID: 225 karaf@root()> service:list org.osgi.service.jdbc.DataSourceFactory [org.osgi.service.jdbc.DataSourceFactory] ----------------------------------------- osgi.jdbc.driver.class = com.mysql.jdbc.Driver osgi.jdbc.driver.name = mysql service.bundleid = 225 service.id = 242 service.scope = singleton Provided by : OPS4J Pax JDBC MySQL Driver Adapter (225)
org.osgi.service.jdbc.DataSourceFactory
서비스 및org.ops4j.datasource
factory PID 를 추적하는pax-jdbc
-config 번 들과pax-jdbc-config
번들을 설치합니다.karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc/1.3.0 Bundle ID: 226 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-pool-common/1.3.0 Bundle ID: 227 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-config/1.3.0 Bundle ID: 228 karaf@root()> bundle:services -p org.ops4j.pax.jdbc.config OPS4J Pax JDBC Config (228) provides: ------------------------------------- objectClass = [org.osgi.service.cm.ManagedServiceFactory] service.bundleid = 228 service.id = 245 service.pid = org.ops4j.datasource service.scope = singleton
팩토리 구성 을 생성합니다(MySQL 서버가 실행 중이라고 가정).
karaf@root()> config:edit --factory --alias mysql org.ops4j.datasource karaf@root()> config:property-set osgi.jdbc.driver.name mysql karaf@root()> config:property-set dataSourceName mysqlds karaf@root()> config:property-set url jdbc:mysql://localhost:3306/reportdb karaf@root()> config:property-set user fuse karaf@root()> config:property-set password fuse karaf@root()> config:update karaf@root()> config:list '(service.factoryPid=org.ops4j.datasource)' ---------------------------------------------------------------- Pid: org.ops4j.datasource.a7941498-9b62-4ed7-94f3-8c7ac9365313 FactoryPid: org.ops4j.datasource BundleLocation: ? Properties: dataSourceName = mysqlds felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.datasource-mysql.cfg osgi.jdbc.driver.name = mysql password = fuse service.factoryPid = org.ops4j.datasource service.pid = org.ops4j.datasource.a7941498-9b62-4ed7-94f3-8c7ac9365313 url = jdbc:mysql://localhost:3306/reportdb user = fuse
pax-jdbc-config
가javax.sql.DataSource
서비스로 구성을 처리했는지 확인합니다.karaf@root()> service:list javax.sql.DataSource [javax.sql.DataSource] ---------------------- dataSourceName = mysqlds felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.datasource-mysql.cfg osgi.jdbc.driver.name = mysql osgi.jndi.service.name = mysqlds password = fuse pax.jdbc.managed = true service.bundleid = 228 service.factoryPid = org.ops4j.datasource service.id = 246 service.pid = org.ops4j.datasource.a7941498-9b62-4ed7-94f3-8c7ac9365313 service.scope = singleton url = jdbc:mysql://localhost:3306/reportdb user = fuse Provided by : OPS4J Pax JDBC Config (228)
이제 실제 데이터베이스별(아직 풀링 없음) 데이터 소스가 있습니다. 필요한 곳에 이미 삽입할 수 있습니다. 예를 들어 Karaf 명령을 사용하여 데이터베이스를 쿼리할 수 있습니다.
karaf@root()> feature:install -v jdbc Adding features: jdbc/[4.2.0.fuse-000237-redhat-1,4.2.0.fuse-000237-redhat-1] ... karaf@root()> jdbc:ds-list Mon May 14 08:46:22 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. Name │ Product │ Version │ URL │ Status ────────┼─────────┼─────────┼──────────────────────────────────────┼─────── mysqlds │ MySQL │ 5.7.21 │ jdbc:mysql://localhost:3306/reportdb │ OK karaf@root()> jdbc:query mysqlds 'select * from incident' Mon May 14 08:46:46 CEST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. date │ summary │ name │ details │ id │ email ──────────────────────┼────────────┼────────┼───────────────────────────────┼────┼───────────────── 2018-02-20 08:00:00.0 │ Incident 1 │ User 1 │ This is a report incident 001 │ 1 │ user1@redhat.com 2018-02-20 08:10:00.0 │ Incident 2 │ User 2 │ This is a report incident 002 │ 2 │ user2@redhat.com 2018-02-20 08:20:00.0 │ Incident 3 │ User 3 │ This is a report incident 003 │ 3 │ user3@redhat.com 2018-02-20 08:30:00.0 │ Incident 4 │ User 4 │ This is a report incident 004 │ 4 │ user4@redhat.com
위의 예제에서는 MySQL 경고를 볼 수 있습니다. 이것은 문제가 아닙니다. 모든 속성(OSGi JDBC 특정 속성뿐만 아니라)이 제공될 수 있습니다.
karaf@root()> config:property-set --pid org.ops4j.datasource.a7941498-9b62-4ed7-94f3-8c7ac9365313 useSSL false karaf@root()> jdbc:ds-list Name │ Product │ Version │ URL │ Status ────────┼─────────┼─────────┼──────────────────────────────────────┼─────── mysqlds │ MySQL │ 5.7.21 │ jdbc:mysql://localhost:3306/reportdb │ OK
6.4.2. 처리된 속성 요약
admin 팩토리 PID 구성의 속성은 관련 org.osgi.service.jdbc.DataSourceFactory
구현으로 전달됩니다.
일반
org.ops4j.pax.jdbc.impl.DriverDataSourceFactory
properties:
-
url
-
user
-
암호
DB2
org.ops4j.pax.jdbc.db2.impl.DB2DataSourceFactory
속성에는 다음과 같은 구현 클래스의 모든 empty 속성이 포함됩니다.
-
com.ibm.db2.jcc.DB2SimpleDataSource
-
com.ibm.db2.jcc.DB2ConnectionPoolDataSource
-
com.ibm.db2.jcc.DB2XADataSource
PostgreSQL
Nnative org.postgresql.osgi.PGDataSourceFactory
속성에는 org.postgresql.PGProperty
에 지정된 모든 속성이 포함됩니다.
HSQLDB
org.ops4j.pax.jdbc.hsqldb.impl.HsqldbDataSourceFactory
properties:
-
url
-
user
-
암호
-
databaseName
모든 Cryostat 속성
-
org.hsqldb.jdbc.JDBCDataSource
-
org.hsqldb.jdbc.pool.JDBCPooledDataSource
-
org.hsqldb.jdbc.pool.JDBCXADataSource
-
SQL Server 및 Sybase
org.ops4j.pax.jdbc.jtds.jtds.jtds.JTDSDataFactory
속성에는 net.sourceforge.jtds.jdbcx.JtdsDataSource
.
SQL Server
org.ops4j.pax.jdbc.mssql.impl.MSSQLDataSourceFactory
properties:
-
url
-
user
-
암호
-
databaseName
-
serverName
-
portNumber
모든 Cryostat 속성
-
com.microsoft.sqlserver.jdbc.SQLServerDataSource
-
com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource
-
com.microsoft.sqlserver.jdbc.SQLServerXADataSource
-
MySQL
org.ops4j.pax.jdbc.mysql.impl.MysqlDataSourceFactory
properties:
-
url
-
user
-
암호
-
databaseName
-
serverName
-
portNumber
모든 Cryostat 속성
-
com.mysql.jdbc.jdbc2.optional.MysqlDataSource
-
com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
-
com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
-
Oracle
org.ops4j.pax.jdbc.oracle.impl.OracleDataSourceFactory
properties:
-
url
-
databaseName
-
serverName
-
user
-
암호
모든 Cryostat 속성
-
oracle.jdbc.pool.OracleDataSource
-
oracle.jdbc.pool.OracleConnectionPoolDataSource
-
oracle.jdbc.xa.client.OracleXADataSource
-
SQLite
org.ops4j.pax.jdbc.sqlite.impl.SqliteDataSourceFactory
properties:
-
url
-
databaseName
-
org.sqlite.SQLiteDataSource
의 모든 Cryostat 속성
6.4.3. pax-jdb-config 번들이 속성을 처리하는 방법
pax-jdbc-config
번들은 jdbc 로 접두사가 지정된 속성을 처리합니다.
이러한 모든 속성은 이 접두사가 제거되고 나머지 이름은 전달됩니다.
다음은 Fuse 새로 설치부터 시작하는 예제입니다.
karaf@root()> install -s mvn:mysql/mysql-connector-java/5.1.34 Bundle ID: 223 karaf@root()> install -s mvn:org.osgi/org.osgi.service.jdbc/1.0.0 Bundle ID: 224 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-mysql/1.3.0 Bundle ID: 225 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc/1.3.0 Bundle ID: 226 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-pool-common/1.3.0 Bundle ID: 227 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-config/1.3.0 Bundle ID: 228 karaf@root()> config:edit --factory --alias mysql org.ops4j.datasource karaf@root()> config:property-set osgi.jdbc.driver.name mysql karaf@root()> config:property-set dataSourceName mysqlds karaf@root()> config:property-set dataSourceType DataSource karaf@root()> config:property-set jdbc.url jdbc:mysql://localhost:3306/reportdb karaf@root()> config:property-set jdbc.user fuse karaf@root()> config:property-set jdbc.password fuse karaf@root()> config:property-set jdbc.useSSL false karaf@root()> config:update karaf@root()> config:list '(service.factoryPid=org.ops4j.datasource)' ---------------------------------------------------------------- Pid: org.ops4j.datasource.7c3ee718-7309-46a0-ae3a-64b38b17a0a3 FactoryPid: org.ops4j.datasource BundleLocation: ? Properties: dataSourceName = mysqlds dataSourceType = DataSource felix.fileinstall.filename = file:/data/servers/7.8.0.fuse-780038-redhat-00001/etc/org.ops4j.datasource-mysql.cfg jdbc.password = fuse jdbc.url = jdbc:mysql://localhost:3306/reportdb jdbc.useSSL = false jdbc.user = fuse osgi.jdbc.driver.name = mysql service.factoryPid = org.ops4j.datasource service.pid = org.ops4j.datasource.7c3ee718-7309-46a0-ae3a-64b38b17a0a3 karaf@root()> service:list javax.sql.DataSource [javax.sql.DataSource] ---------------------- dataSourceName = mysqlds dataSourceType = DataSource felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.datasource-mysql.cfg jdbc.password = fuse jdbc.url = jdbc:mysql://localhost:3306/reportdb jdbc.user = fuse jdbc.useSSL = false osgi.jdbc.driver.name = mysql osgi.jndi.service.name = mysqlds pax.jdbc.managed = true service.bundleid = 228 service.factoryPid = org.ops4j.datasource service.id = 246 service.pid = org.ops4j.datasource.7c3ee718-7309-46a0-ae3a-64b38b17a0a3 service.scope = singleton Provided by : OPS4J Pax JDBC Config (228)
pax-jdbc-config
번들에는 다음과 같은 속성이 필요합니다.
-
osgi.jdbc.driver.name
-
dataSourceName
-
dataSourceType
관련 org.osgi.service.jdbc.DataSourceFactory
메서드를 찾아서 호출하려면 다음을 수행합니다. jdbc.
접두사가 있는 속성은 ( 접두사를 제거한 후) org.osgi.service.jdbc.DataSourceFactory.createDataSourceSource(properties)
로 전달됩니다. 그러나 이러한 속성은 접두사가 제거되지 않고 (예: javax.sql.DataSource
OSGi 서비스) 속성으로 추가됩니다.
6.5. JDBC 콘솔 명령 사용
Fuse는
범위에 쉘 명령을 포함하는 jdbc 기능을 제공합니다. 이전 예제에서는 jdbc
:*jdbc:query
를 사용하는 방법을 보여줍니다. 구성 관리 구성을 생성할 필요성을 숨기는 명령도 있습니다.
Fuse의 새로운 인스턴스부터 다음과 같이 일반 DataSourceFactory
서비스에 데이터베이스별 데이터 소스를 등록할 수 있습니다.
karaf@root()> feature:install jdbc karaf@root()> jdbc:ds-factories Name │ Class │ Version ─────┼───────┼──────── karaf@root()> install -s mvn:mysql/mysql-connector-java/5.1.34 Bundle ID: 228 karaf@root()> jdbc:ds-factories Name │ Class │ Version ───────────────┼─────────────────────────────────────────┼──────── com.mysql.jdbc │ com.mysql.jdbc.Driver │ 5.1.34 com.mysql.jdbc │ com.mysql.fabric.jdbc.FabricMySQLDriver │ 5.1.34
다음은 MySQL 관련 DataSourceFactory
서비스를 등록하는 예입니다.
karaf@root()> feature:repo-add mvn:org.ops4j.pax.jdbc/pax-jdbc-features/1.3.0/xml/features-gpl Adding feature url mvn:org.ops4j.pax.jdbc/pax-jdbc-features/1.3.0/xml/features-gpl karaf@root()> feature:install pax-jdbc-mysql karaf@root()> la -l|grep mysql 232 │ Active │ 80 │ 5.1.34 │ mvn:mysql/mysql-connector-java/5.1.34 233 │ Active │ 80 │ 1.3.0 │ mvn:org.ops4j.pax.jdbc/pax-jdbc-mysql/1.3.0 karaf@root()> jdbc:ds-factories Name │ Class │ Version ───────────────┼─────────────────────────────────────────┼──────── com.mysql.jdbc │ com.mysql.jdbc.Driver │ 5.1.34 mysql │ com.mysql.jdbc.Driver │ com.mysql.jdbc │ com.mysql.fabric.jdbc.FabricMySQLDriver │ 5.1.34
위의 표는 혼란스러울 수 있지만 위에서 언급한 것처럼 pax-jdbc-데이터베이스
번들 중 하나만 org.osgi.service.jdbc.jdbc.DataSourceFactory
인스턴스를 등록할 수 있으며 java.sql.Driver.connect()
에만 위임 되지 않는 표준/XA/connection 풀 데이터 소스를 생성할 수 있습니다.
다음 예제에서는 MySQL 데이터 소스를 생성하고 확인합니다.
karaf@root()> jdbc:ds-create -dt DataSource -dn mysql -url 'jdbc:mysql://localhost:3306/reportdb?useSSL=false' -u fuse -p fuse mysqlds karaf@root()> jdbc:ds-list Name │ Product │ Version │ URL │ Status ────────┼─────────┼─────────┼───────────────────────────────────────────────────┼─────── mysqlds │ MySQL │ 5.7.21 │ jdbc:mysql://localhost:3306/reportdb?useSSL=false │ OK karaf@root()> jdbc:query mysqlds 'select * from incident' date │ summary │ name │ details │ id │ email ──────────────────────┼────────────┼────────┼───────────────────────────────┼────┼───────────────── 2018-02-20 08:00:00.0 │ Incident 1 │ User 1 │ This is a report incident 001 │ 1 │ user1@redhat.com 2018-02-20 08:10:00.0 │ Incident 2 │ User 2 │ This is a report incident 002 │ 2 │ user2@redhat.com 2018-02-20 08:20:00.0 │ Incident 3 │ User 3 │ This is a report incident 003 │ 3 │ user3@redhat.com 2018-02-20 08:30:00.0 │ Incident 4 │ User 4 │ This is a report incident 004 │ 4 │ user4@redhat.com karaf@root()> config:list '(service.factoryPid=org.ops4j.datasource)' ---------------------------------------------------------------- Pid: org.ops4j.datasource.55b18993-de4e-4e0b-abb2-a4c13da7f78b FactoryPid: org.ops4j.datasource BundleLocation: mvn:org.ops4j.pax.jdbc/pax-jdbc-config/1.3.0 Properties: dataSourceName = mysqlds dataSourceType = DataSource osgi.jdbc.driver.name = mysql password = fuse service.factoryPid = org.ops4j.datasource service.pid = org.ops4j.datasource.55b18993-de4e-4e0b-abb2-a4c13da7f78b url = jdbc:mysql://localhost:3306/reportdb?useSSL=false user = fuse
위 화면과 같이 org.ops4j.datasource
팩토리 PID가 생성됩니다. 그러나 config:update
를 사용하면 ${karaf.etc}
에 자동으로 저장되지 않습니다.
6.6. 암호화된 구성 값 사용
pax-jdbc-config
기능은 값이 암호화된 구성 관리 구성을 처리할 수 있습니다. 널리 사용되는 솔루션은 블루프린트에서도 사용하는 Jasypt 암호화 서비스를 사용하는 것입니다.
별칭
서비스 속성을 사용하여 OSGi에 등록된 org.jasypt.encryption.StringEncryptor
서비스가 있는 경우 데이터 소스 팩토리 PID 에서 거부하고 암호화된 암호를 사용할 수 있습니다. 예를 들면 다음과 같습니다.
felix.fileinstall.filename = */etc/org.ops4j.datasource-mysql.cfg dataSourceName = mysqlds dataSourceType = DataSource decryptor = my-jasypt-decryptor osgi.jdbc.driver.name = mysql url = jdbc:mysql://localhost:3306/reportdb?useSSL=false user = fuse password = ENC(<encrypted-password>)
암호 해독기 서비스를 찾는 데 사용되는 서비스 필터는 (&(objectClass=org.jasypt.encryption.StringEncryptor)(alias=<alias>)
입니다. 여기서 < alias
>는 데이터 소스 구성 팩토리 PID 의 암호 해독
속성 값입니다.
6.7. JDBC 연결 풀 사용
이 섹션에서는 JDBC 연결 풀을 사용한 다음 이러한 연결 풀 모듈을 사용하는 방법을 보여줍니다.
이 장에서는 데이터 소스 관리의 내부에 대한 완전한 정보를 제공합니다. DBCP2 연결 풀 기능에 대한 정보가 제공되지만 이 연결 풀은 적절한 JTA 등록 기능을 제공하지만 XA 복구 는 제공하지 않습니다.
XA 복구 가 적용되도록 하려면 pax-jdbc-pool-transx
또는 pax-jdbc-pool-narayana
연결 풀 모듈을 사용합니다.
6.7.1. JDBC 연결 풀 사용 소개
이전 예제에서는 데이터베이스별 데이터 소스 팩토리 를 등록하는 방법을 보여줍니다. 데이터 소스 자체는 연결에 대한 팩토리이기 때문에 org.osgi.service.jdbc.DataSourceFactory
는 세 가지 종류의 데이터 소스를 생성할 수 있어야 하는 메타 팩토리 로 취급될 수 있으며, 보너스로 java.sql.Driver
:
-
javax.sql.DataSource
-
javax.sql.ConnectionPoolDataSource
-
javax.sql.XADataSource
예를 들어 pax-jdbc-mysql
은 org.ops4j.pax.jdbc.mysql.impl.MysqlDataSourceFactory
를 생성합니다.
-
javax.sql.DataSource
→com.mysql.jdbc.jdbc2.optional.MysqlDataSource
-
javax.sql.ConnectionPoolDataSource
→com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
-
javax.sql.XADataSource
→com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
-
java.sql.Driver
→com.mysql.jdbc.Driver
PostgreSQL 드라이버 자체는 OSGi JDBC 서비스를 구현하고 다음을 생성합니다.
-
javax.sql.DataSource
→org.postgresql.jdbc2.optional.optional.PoolingDataSource
(풀 관련 속성이 지정된 경우) 또는org.postgresql.jdbc2.optional.SimpleDataSource
-
javax.sql.ConnectionPoolDataSource
→org.postgresql.jdbc2.optional.ConnectionPool
-
javax.sql.XADataSource
→org.postgresql.xa.PGXADataSource
-
java.sql.Driver
→org.postgresql.Driver
표준 데이터 소스 예 에 표시된 것처럼 모든 풀링 (일반 데이터 소스)이 JTA 환경에서 작동하려면 실제로 (XA) 연결을 얻으려면 데이터베이스별 데이터 소스가 필요합니다.
우리는 이미 후자를 보유하고 있으며 실제적이고 일반적인 신뢰할 수 있는 연결 풀이 필요합니다.
표준 데이터 소스 예 는 데이터베이스별 데이터 소스를 사용하여 일반 풀을 구성하는 방법을 보여줍니다. pax-jdbc-pool-*
번들은 위의 org.osgi.service.jdbc.DataSourceFactory
서비스와 원활하게 작동합니다.
OSGI Enterprise R6 JDBC 사양에서 org.osgi.service.jdbc.DataSourceFactory
표준 인터페이스를 제공하는 것처럼 pax-jdbc-pool-common
은 독점 org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory
인터페이스를 제공합니다.
public interface PooledDataSourceFactory { javax.sql.DataSource create(org.osgi.service.jdbc.DataSourceFactory dsf, Properties config) }
이 인터페이스는 이전에 제시된 중요한 참고 사항에 완벽하게 부합하며 반복할 가치가 있습니다.
애플리케이션에서 XA 트랜잭션 및/또는 연결 풀링을 사용하는 경우에도 애플리케이션은 다른 두 JDBC 데이터 소스 인터페이스가 아닌 javax.sql.DataSource
와 상호 작용합니다.
이 인터페이스는 데이터베이스별 비풀링 데이터에서 간단히 풀링 데이터 소스를 생성합니다. 또는 보다 정확하게는 데이터베이스별 데이터 소스의 팩토리 를 데이터 소스 풀링 팩토리로 변환하는 데이터 소스 팩토리(meta factory)입니다.
javax.sql.DataSource
개체에 대한 풀링을 이미 반환하는 org.osgi.service.jdbc.DataSourceFactory
서비스를 사용하여 애플리케이션에서 javax.sql.DataSource
Source 개체에 대한 풀링을 구성하지 못하도록 하는 것은 없습니다.
다음 표에서는 풀링된 데이터 소스 팩토리를 등록하는 번들을 보여줍니다. 표에서 o.o.p.j.p
는 org.ops4j.pax.jdbc.pool
을 나타냅니다.
번들 | PooledDataSourceFactory | 풀 키 |
---|---|---|
|
|
|
|
|
|
|
|
|
위의 번들은 데이터 소스 자체가 아닌 데이터 소스 팩토리만 설치합니다. 애플리케이션에는 javax.sql.DataSource create(org.osgi.service.jdbc.DataSourceFactory dsf, Properties config)
메서드를 호출하는 항목이 필요합니다.
6.7.2. dbcp2
연결 풀 모듈 사용
일반 데이터 소스에 대한 섹션에서는 Apache Commons DBCP 모듈을 사용하고 구성하는 방법에 대한 예를 제공합니다. 이 섹션에서는 Fuse OSGi 환경에서 이 작업을 수행하는 방법을 설명합니다.
6.4.1절. “PAX-JDBC 구성 서비스” 번들을 고려하십시오. 다음을 추적하는 것 외에도 다음을 수행하십시오.
-
org.osgi.service.jdbc.DataSourceFactory
services -
org.ops4j.datasource
팩토리 PID
또한 번들은 pax-jc -pool-* 번들 중 하나에서 등록한
의 인스턴스도 추적합니다.
org.ops4j.pax.jdbc.pool
.common.PooledDataSourceFactory
팩토리 구성에 pool
속성이 포함된 경우 pax-jdbc-config
번들에 의해 등록된 궁극적인 데이터 소스는 데이터베이스별 데이터이며 데이터베이스별 데이터입니다. 그러나 pool=dbcp2
인 경우 다음 중 하나로 래핑됩니다.
-
org.apache.commons.dbcp2.PoolingDataSource
-
org.apache.commons.dbcp2.managed.ManagedDataSource
이는 일반 데이터 소스 예와 일치합니다. pool
속성 및 비xa 또는 xa
데이터 소스를 선택하는 부울 xa 속성 외에도 org.ops4j.datasource
팩토리 PID 에는 접두사 가 지정된 속성이 포함될 수 있습니다.
-
pool.*
-
factory.*
여기서 각 속성이 사용되는 위치는 pax-jdbc-pool-*
번들이 사용되는지에 따라 다릅니다. DBCP2의 경우 다음과 같습니다.
-
pool.*
:org.apache.commons.pool2.impl.GenericObjectPoolConfig
의 빈 속성(xa 및 비xa 시나리오 모두) -
factory.*
:org.apache.commons.dbcp2.managed.PoolableManagedConnectionFactory
(xa) 또는org.apache.commons.dbcp2.PoolableConnectionFactory
(non-xa)의 8080 속성
6.7.2.1. BasicDataSource의 구성 속성
다음 표에는 BasicDataSource의 일반 구성 속성이 나열되어 있습니다.
매개변수 | Default | 설명 |
---|---|---|
| 연결을 설정하기 위해 JDBC 드라이버에 전달할 연결 사용자 이름입니다. | |
| 연결을 설정하기 위해 JDBC 드라이버에 전달할 연결 암호입니다. | |
| 연결을 설정하기 위해 JDBC 드라이버에 전달할 연결 URL입니다. | |
| 사용할 JDBC 드라이버의 정규화된 Java 클래스 이름입니다. | |
| 0 | 풀을 시작할 때 생성되는 초기 연결 수입니다. |
| 8 | 이 풀에서 동시에 할당할 수 있는 최대 활성 연결 수 또는 제한 없음에 대해 음수입니다. |
| 8 | 추가 해제 없이 풀에서 유휴 상태로 유지할 수 있는 최대 연결 수 또는 제한 없이 음수입니다. |
| 0 | 추가 생성 없이 풀에서 유휴 상태로 유지할 수 있는 최소 연결 수 또는 0을 생성하여 none을 생성합니다. |
| 무기 | 풀에서 사용할 수 있는 최대 시간(사용 가능한 연결이 없는 경우)이 예외를 throw하거나 -1이 무기한 대기하기 전에 반환될 때까지 대기하는 최대 시간(밀리초)입니다. |
| 호출자로 반환하기 전에 이 풀의 연결을 검증하는 데 사용할 SQL 쿼리입니다. 지정된 경우 이 쿼리는 하나 이상의 행을 반환하는 SQL SELECT 문이어야 합니다. 지정하지 않으면 isValid() 메서드를 호출하여 연결을 검증합니다. | |
| 시간 초과 없음 | 연결 유효성 검사 쿼리가 실패하기 전 시간(초)입니다. 양수 값으로 설정하면 이 값은 검증 쿼리를 실행하는 데 사용되는 Statement의 setQueryTimeout 메서드를 통해 드라이버에 전달됩니다. |
| false | 생성 후 오브젝트의 유효성을 검사합니다. 오브젝트의 유효성을 검사하지 못하면 오브젝트 생성을 트리거한 차용 시도에 실패합니다. |
| true | 개체가 풀에서 빌리기 전에 유효성을 검사합니다. 개체의 유효성 검사가 실패하면 풀에서 삭제되고 다른 개체를 빌리려고 합니다. |
| false | 개체가 풀로 반환되기 전에 유효성을 검사할지 여부를 나타내는 값입니다. |
| false | 유휴 오브젝트 evictor(있는 경우)에서 오브젝트의 유효성을 검사합니다. 오브젝트의 유효성 검사가 실패하면 풀에서 삭제됩니다. |
| -1 | 유휴 개체 evictor 스레드의 실행 사이에 유휴 상태의 시간(밀리초)입니다. 양수가 아닌 경우 유휴 오브젝트 제거 스레드가 실행되지 않습니다. |
| 3 | 유휴 개체의 각 실행 중에 검사할 오브젝트 수(있는 경우)입니다. |
| 1000 * 60 * 30 | 유휴 오브젝트 제거 대상(있는 경우)을 제거하기 전에 오브젝트가 풀에 유휴 상태로 남아 있을 수 있는 최소 시간입니다. |
6.7.2.2. DBCP2 풀을 구성하는 방법의 예
다음은 jdbc와 함께 편리한 구문을 사용하는 DBCP2 풀(
org.ops4j.datasource-mysql
PID) 구성의 비현실 예제( useSSL=false
제외)입니다.
# Configuration for pax-jdbc-config to choose and configure specific org.osgi.service.jdbc.DataSourceFactory dataSourceName = mysqlds dataSourceType = DataSource osgi.jdbc.driver.name = mysql jdbc.url = jdbc:mysql://localhost:3306/reportdb jdbc.user = fuse jdbc.password = fuse jdbc.useSSL = false # Hints for pax-jdbc-config to use org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory pool = dbcp2 xa = false # dbcp2 specific configuration of org.apache.commons.pool2.impl.GenericObjectPoolConfig pool.minIdle = 10 pool.maxTotal = 100 pool.initialSize = 8 pool.blockWhenExhausted = true pool.maxWaitMillis = 2000 pool.testOnBorrow = true pool.testWhileIdle = false pool.timeBetweenEvictionRunsMillis = 120000 pool.evictionPolicyClassName = org.apache.commons.pool2.impl.DefaultEvictionPolicy # dbcp2 specific configuration of org.apache.commons.dbcp2.PoolableConnectionFactory factory.maxConnLifetimeMillis = 30000 factory.validationQuery = select schema_name from information_schema.schemata factory.validationQueryTimeout = 2
위의 구성에서 pool
및 xa
키는 등록된 org.ops4j.pax.j.jdbc.pool.common.PooledDataSourceFactory
서비스 중 하나를 선택하는 힌트 (서비스 필터 속성)입니다. DBCP2의 경우 다음과 같습니다.
karaf@root()> feature:install pax-jdbc-pool-dbcp2 karaf@root()> bundle:services -p org.ops4j.pax.jdbc.pool.dbcp2 OPS4J Pax JDBC Pooling DBCP2 (230) provides: -------------------------------------------- objectClass = [org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory] pool = dbcp2 service.bundleid = 230 service.id = 337 service.scope = singleton xa = false ----- objectClass = [org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory] pool = dbcp2 service.bundleid = 230 service.id = 338 service.scope = singleton xa = true
완전성을 위해 이전 예제에 연결 풀 구성이 추가된 전체 예제 는 다음과 같습니다. 다시 말해 새로운 Fuse 설치를 시작한다고 가정합니다.
JDBC 드라이버를 설치합니다.
karaf@root()> install -s mvn:mysql/mysql-connector-java/5.1.34 Bundle ID: 223
jdbc
,pax-jdbc-mysql
및pax-jdbc-pool-dbcp2
기능을 설치합니다.karaf@root()> feature:repo-add mvn:org.ops4j.pax.jdbc/pax-jdbc-features/1.3.0/xml/features-gpl Adding feature url mvn:org.ops4j.pax.jdbc/pax-jdbc-features/1.3.0/xml/features-gpl karaf@root()> feature:install jdbc pax-jdbc-mysql pax-jdbc-pool-dbcp2 karaf@root()> service:list org.osgi.service.jdbc.DataSourceFactory ... [org.osgi.service.jdbc.DataSourceFactory] ----------------------------------------- osgi.jdbc.driver.class = com.mysql.jdbc.Driver osgi.jdbc.driver.name = mysql service.bundleid = 232 service.id = 328 service.scope = singleton Provided by : OPS4J Pax JDBC MySQL Driver Adapter (232) karaf@root()> service:list org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory [org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory] -------------------------------------------------------- pool = dbcp2 service.bundleid = 233 service.id = 324 service.scope = singleton xa = false Provided by : OPS4J Pax JDBC Pooling DBCP2 (233) [org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory] -------------------------------------------------------- pool = dbcp2 service.bundleid = 233 service.id = 332 service.scope = singleton xa = true Provided by : OPS4J Pax JDBC Pooling DBCP2 (233)
팩토리 구성 을 생성합니다.
karaf@root()> config:edit --factory --alias mysql org.ops4j.datasource karaf@root()> config:property-set osgi.jdbc.driver.name mysql karaf@root()> config:property-set dataSourceName mysqlds karaf@root()> config:property-set dataSourceType DataSource karaf@root()> config:property-set jdbc.url jdbc:mysql://localhost:3306/reportdb karaf@root()> config:property-set jdbc.user fuse karaf@root()> config:property-set jdbc.password fuse karaf@root()> config:property-set jdbc.useSSL false karaf@root()> config:property-set pool dbcp2 karaf@root()> config:property-set xa false karaf@root()> config:property-set pool.minIdle 2 karaf@root()> config:property-set pool.maxTotal 10 karaf@root()> config:property-set pool.blockWhenExhausted true karaf@root()> config:property-set pool.maxWaitMillis 2000 karaf@root()> config:property-set pool.testOnBorrow true karaf@root()> config:property-set pool.testWhileIdle alse karaf@root()> config:property-set pool.timeBetweenEvictionRunsMillis 120000 karaf@root()> config:property-set factory.validationQuery 'select schema_name from information_schema.schemata' karaf@root()> config:property-set factory.validationQueryTimeout 2 karaf@root()> config:update
pax-jdbc-config
가javax.sql.DataSource
서비스로 구성을 처리했는지 확인합니다.karaf@root()> service:list javax.sql.DataSource [javax.sql.DataSource] ---------------------- dataSourceName = mysqlds dataSourceType = DataSource factory.validationQuery = select schema_name from information_schema.schemata factory.validationQueryTimeout = 2 felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.datasource-mysql.cfg jdbc.password = fuse jdbc.url = jdbc:mysql://localhost:3306/reportdb jdbc.user = fuse jdbc.useSSL = false osgi.jdbc.driver.name = mysql osgi.jndi.service.name = mysqlds pax.jdbc.managed = true pool.blockWhenExhausted = true pool.maxTotal = 10 pool.maxWaitMillis = 2000 pool.minIdle = 2 pool.testOnBorrow = true pool.testWhileIdle = alse pool.timeBetweenEvictionRunsMillis = 120000 service.bundleid = 225 service.factoryPid = org.ops4j.datasource service.id = 338 service.pid = org.ops4j.datasource.fd7aa3a1-695b-4342-b0d6-23d018a46fbb service.scope = singleton Provided by : OPS4J Pax JDBC Config (225)
데이터 소스를 사용합니다.
karaf@root()> jdbc:query mysqlds 'select * from incident' date │ summary │ name │ details │ id │ email ──────────────────────┼────────────┼────────┼───────────────────────────────┼────┼───────────────── 2018-02-20 08:00:00.0 │ Incident 1 │ User 1 │ This is a report incident 001 │ 1 │ user1@redhat.com 2018-02-20 08:10:00.0 │ Incident 2 │ User 2 │ This is a report incident 002 │ 2 │ user2@redhat.com 2018-02-20 08:20:00.0 │ Incident 3 │ User 3 │ This is a report incident 003 │ 3 │ user3@redhat.com 2018-02-20 08:30:00.0 │ Incident 4 │ User 4 │ This is a report incident 004 │ 4 │ user4@redhat.com
6.7.3. narayana
연결 풀 모듈 사용
pax-jdbc-pool-narayna
모듈은 pax-jdbc-pool-dbcp2
로 거의 모든 작업을 수행합니다. XA 및 비 XA 시나리오에 대해 DBCP2-specific org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory
를 설치합니다. 유일한 차이점은 XA 시나리오에서 추가 통합 포인트가 있다는 것입니다. org.jboss.tm.XAResourceRecovery
OSGi 서비스는 Narayana 트랜잭션 관리자의 일부인 com.arjuna.ats.arjuna.recovery.RecoveryManager
에서 선택하도록 등록됩니다.
6.7.4. transx
연결 풀 모듈 사용
pax-jdbc-pool-transx
번들에서는 pax- transx-jc-jdbc bundle에서
서비스를 기반으로 합니다. org.ops4j.pax.jdbc
.pool.common.PooledDataSourceFactorypax-transx-jdbc
번들에서는 org.ops4j.pax.transx.jdbc.ManagedDataSourceBuilder
기능을 사용하여 javax.sql.DataSource
Sourcec 풀을 생성합니다. JCA(Java™ Connector Architecture) 솔루션이며 나중에 설명합니다.
6.8. 데이터 소스를 아티팩트로 배포
이 장에서는 OSGi JDBC 서비스를 도입하여 데이터베이스별 및 일반 데이터 소스를 등록하는 데 pax-jdbc
번들이 어떤 도움을 주는지와 OSGi 서비스 및 구성 관리 구성의 관점에서 어떻게 보이는지 보여줍니다. 두 가지 범주의 데이터 소스 의 구성은 Configuration Admin factory PIDs( pax-jdbc-config
번들의 도움말 포함)를 사용하여 수행할 수 있지만 일반적으로 배포 방법을 사용하는 것이 좋습니다.
배포 방법 에서는javax.sql.DataSource
서비스는 일반적으로 블루프린트 컨테이너 내에서 애플리케이션 코드로 직접 등록됩니다. 블루프린트 XML은 일반 OSGi 번들의 일부일 수 있으며 mvn:
URI를 사용하여 설치하고 Maven 리포지토리(로컬 또는 원격)에 저장할 수 있습니다. 이러한 번들을 구성 관리 구성과 비교하여 버전 제어가 훨씬 쉽습니다.
pax-jdbc-config
번들 버전 1.3.0은 데이터 소스 구성에 대한 배포 방법을 추가합니다. 애플리케이션 개발자는 javax.sql.(XA)DataSource
서비스(일반적으로 Bluerpint XML를 사용하여)를 등록하고 서비스 속성을 지정합니다. pax-jdbc-config
번들은 이러한 등록된 데이터베이스별 데이터 소스를 감지하고(서비스 속성 사용) 일반 비 데이터베이스별 연결 풀 내에서 서비스를 래핑합니다.
완전성을 위해 블루프린트 XML을 사용하는 세 가지 배포 방법은 다음과 같습니다. Fuse는 Fuse 의 다양한 측면의 다양한 예와 함께 빠른 시작
다운로드를 제공합니다. Fuse Software Downloads 페이지에서 빠른 시작
zip 파일을 다운로드할 수 있습니다.
빠른 시작 zip 파일의 내용을 로컬 폴더에 추출합니다.
다음 예제에서 quickstarts/persistence
디렉터리를 $PQ_HOME
이라고 합니다.
6.8.1. 데이터 소스 수동 배포
데이터 소스의 수동 배포 예에서는 docker 기반 PostgreSQL 설치를 사용합니다. 이 방법에서는 pax-jdbc-config
가 필요하지 않습니다. 애플리케이션 코드는 데이터베이스별 및 일반 데이터 소스 모두를 등록합니다.
이 세 가지 번들이 필요합니다.
-
mvn:org.postgresql/postgresql/42.2.5
-
mvn:org.apache.commons/commons-pool2/2.5.0
-
mvn:org.apache.commons/commons-dbcp2/2.1.1
<!-- Database-specific, non-pooling, non-enlisting javax.sql.XADataSource --> <bean id="postgresql" class="org.postgresql.xa.PGXADataSource"> <property name="url" value="jdbc:postgresql://localhost:5432/reportdb" /> <property name="user" value="fuse" /> <property name="password" value="fuse" /> <property name="currentSchema" value="report" /> <property name="connectTimeout" value="5" /> </bean> <!-- Fuse/Karaf exports this service from fuse-pax-transx-tm-narayana bundle --> <reference id="tm" interface="javax.transaction.TransactionManager" /> <!-- Non database-specific, generic, pooling, enlisting javax.sql.DataSource --> <bean id="pool" class="org.apache.commons.dbcp2.managed.BasicManagedDataSource"> <property name="xaDataSourceInstance" ref="postgresql" /> <property name="transactionManager" ref="tm" /> <property name="minIdle" value="3" /> <property name="maxTotal" value="10" /> <property name="validationQuery" value="select schema_name, schema_owner from information_schema.schemata" /> </bean> <!-- Expose datasource to use by application code (like Camel, Spring, ...) --> <service interface="javax.sql.DataSource" ref="pool"> <service-properties> <entry key="osgi.jndi.service.name" value="jdbc/postgresql" /> </service-properties> </service>
위의 블루프린트 XML 조각은 표준 데이터 소스 예 과 일치합니다. 다음은 사용 방법을 보여주는 쉘 명령은 다음과 같습니다.
karaf@root()> install -s mvn:org.postgresql/postgresql/42.2.5 Bundle ID: 233 karaf@root()> install -s mvn:org.apache.commons/commons-pool2/2.5.0 Bundle ID: 224 karaf@root()> install -s mvn:org.apache.commons/commons-dbcp2/2.1.1 Bundle ID: 225 karaf@root()> install -s blueprint:file://$PQ_HOME/databases/blueprints/postgresql-manual.xml Bundle ID: 226 karaf@root()> bundle:services -p 226 Bundle 226 provides: -------------------- objectClass = [javax.sql.DataSource] osgi.jndi.service.name = jdbc/postgresql osgi.service.blueprint.compname = pool service.bundleid = 226 service.id = 242 service.scope = bundle ----- objectClass = [org.osgi.service.blueprint.container.BlueprintContainer] osgi.blueprint.container.symbolicname = postgresql-manual.xml osgi.blueprint.container.version = 0.0.0 service.bundleid = 226 service.id = 243 service.scope = singleton karaf@root()> feature:install jdbc karaf@root()> jdbc:ds-list Name │ Product │ Version │ URL │ Status ────────────────┼────────────┼───────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────── jdbc/postgresql │ PostgreSQL │ 10.3 (Debian 10.3-1.pgdg90+1) │ jdbc:postgresql://localhost:5432/reportdb?prepareThreshold=5&preparedStatementCacheQueries=256&preparedStatementCacheSizeMiB=5&databaseMetadataCacheFields=65536&databaseMetadataCacheFieldsMiB=5&defaultRowFetchSize=0&binaryTransfer=true&readOnly=false&binaryTransferEnable=&binaryTransferDisable=&unknownLength=2147483647&logUnclosedConnections=false&disableColumnSanitiser=false&tcpKeepAlive=false&loginTimeout=0&connectTimeout=5&socketTimeout=0&cancelSignalTimeout=10&receiveBufferSize=-1&sendBufferSize=-1&ApplicationName=PostgreSQL JDBC Driver&jaasLogin=true&useSpnego=false&gsslib=auto&sspiServiceClass=POSTGRES&allowEncodingChanges=false¤tSchema=report&targetServerType=any&loadBalanceHosts=false&hostRecheckSeconds=10&preferQueryMode=extended&autosave=never&reWriteBatchedInserts=false │ OK karaf@root()> jdbc:query jdbc/postgresql 'select * from incident'; date │ summary │ name │ details │ id │ email ────────────────────┼────────────┼────────┼───────────────────────────────┼────┼───────────────── 2018-02-20 08:00:00 │ Incident 1 │ User 1 │ This is a report incident 001 │ 1 │ user1@redhat.com 2018-02-20 08:10:00 │ Incident 2 │ User 2 │ This is a report incident 002 │ 2 │ user2@redhat.com 2018-02-20 08:20:00 │ Incident 3 │ User 3 │ This is a report incident 003 │ 3 │ user3@redhat.com 2018-02-20 08:30:00 │ Incident 4 │ User 4 │ This is a report incident 004 │ 4 │ user4@redhat.com
위 목록에 표시된 것처럼 블루프린트 번은 일반적인 데이터베이스 별 연결 풀인 javax.sql.DataSource
서비스를 내보냅니다. 블루프린트 XML에는 명시적인 <service ref="postgresql"
> 선언이 없기 때문에 데이터베이스별 javax.sql.XADataSource
번들은 OSGi 서비스로 등록되지 않습니다.
6.8.2. 데이터 소스 팩토리 배포
데이터 소스의 팩토리 배포는 표준 방식으로 pax-jdbc-config
번들을 사용합니다. Fuse 6.x에서 권장되는 방법과 약간 다릅니다. 이 방법은 풀링 구성을 서비스 속성으로 지정해야 합니다.
블루프린트 XML 예제는 다음과 같습니다.
<!-- A database-specific org.osgi.service.jdbc.DataSourceFactory that can create DataSource/XADataSource/ /ConnectionPoolDataSource/Driver using properties. It is registered by pax-jdbc-* or for example mvn:org.postgresql/postgresql/42.2.5 bundle natively. --> <reference id="dataSourceFactory" interface="org.osgi.service.jdbc.DataSourceFactory" filter="(osgi.jdbc.driver.class=org.postgresql.Driver)" /> <!-- Non database-specific org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory that can create pooled data sources using some org.osgi.service.jdbc.DataSourceFactory. dbcp2 pool is registered by pax-jdbc-pool-dbcp2 bundle. --> <reference id="pooledDataSourceFactory" interface="org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory" filter="(&(pool=dbcp2)(xa=true))" /> <!-- Finally, use both factories to expose pooled, xa-aware data source. --> <bean id="pool" factory-ref="pooledDataSourceFactory" factory-method="create"> <argument ref="dataSourceFactory" /> <argument> <props> <!-- Properties needed by postgresql-specific org.osgi.service.jdbc.DataSourceFactory. Cannot prepend them with 'jdbc.' prefix as the DataSourceFactory is implemented directly by PostgreSQL driver, not by pax-jdbc-* bundle. --> <prop key="url" value="jdbc:postgresql://localhost:5432/reportdb" /> <prop key="user" value="fuse" /> <prop key="password" value="fuse" /> <prop key="currentSchema" value="report" /> <prop key="connectTimeout" value="5" /> <!-- Properties needed by dbcp2-specific org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory --> <prop key="pool.minIdle" value="2" /> <prop key="pool.maxTotal" value="10" /> <prop key="pool.blockWhenExhausted" value="true" /> <prop key="pool.maxWaitMillis" value="2000" /> <prop key="pool.testOnBorrow" value="true" /> <prop key="pool.testWhileIdle" value="false" /> <prop key="factory.validationQuery" value="select schema_name from information_schema.schemata" /> <prop key="factory.validationQueryTimeout" value="2" /> </props> </argument> </bean> <!-- Expose data source for use by application code (such as Camel, Spring, ...). --> <service interface="javax.sql.DataSource" ref="pool"> <service-properties> <entry key="osgi.jndi.service.name" value="jdbc/postgresql" /> </service-properties> </service>
이 예에서는 데이터 소스 팩토리 를 사용하여 데이터 소스를 생성하는 팩토리 빈을 사용합니다. XA 인식 PooledDataSourceFactory
에서 내부적으로 추적하므로 javax. Cryostat.TransactionManager
서비스를 명시적으로 참조할 필요가 없습니다.
다음은 동일한 예이지만 Fuse/Karaf 쉘에서는 다음과 같습니다.
네이티브 org.osgi.service.jdbc.DataSourcFactory
번들을 등록하려면 mvn:org.osgi/org.osgi.service.jdbc/1.0.0
을 설치한 다음 PostgreSQL 드라이버를 설치합니다.
karaf@root()> feature:install jdbc pax-jdbc-config pax-jdbc-pool-dbcp2 karaf@root()> install -s mvn:org.postgresql/postgresql/42.2.5 Bundle ID: 232 karaf@root()> install -s blueprint:file://$PQ_HOME/databases/blueprints/postgresql-pax-jdbc-factory-dbcp2.xml Bundle ID: 233 karaf@root()> bundle:services -p 233 Bundle 233 provides: -------------------- objectClass = [javax.sql.DataSource] osgi.jndi.service.name = jdbc/postgresql osgi.service.blueprint.compname = pool service.bundleid = 233 service.id = 336 service.scope = bundle ----- objectClass = [org.osgi.service.blueprint.container.BlueprintContainer] osgi.blueprint.container.symbolicname = postgresql-pax-jdbc-factory-dbcp2.xml osgi.blueprint.container.version = 0.0.0 service.bundleid = 233 service.id = 337 service.scope = singleton karaf@root()> jdbc:ds-list Name │ Product │ Version │ URL │ Status ────────────────┼────────────┼───────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────── jdbc/postgresql │ PostgreSQL │ 10.3 (Debian 10.3-1.pgdg90+1) │ jdbc:postgresql://localhost:5432/reportdb?prepareThreshold=5&preparedStatementCacheQueries=256&preparedStatementCacheSizeMiB=5&databaseMetadataCacheFields=65536&databaseMetadataCacheFieldsMiB=5&defaultRowFetchSize=0&binaryTransfer=true&readOnly=false&binaryTransferEnable=&binaryTransferDisable=&unknownLength=2147483647&logUnclosedConnections=false&disableColumnSanitiser=false&tcpKeepAlive=false&loginTimeout=0&connectTimeout=5&socketTimeout=0&cancelSignalTimeout=10&receiveBufferSize=-1&sendBufferSize=-1&ApplicationName=PostgreSQL JDBC Driver&jaasLogin=true&useSpnego=false&gsslib=auto&sspiServiceClass=POSTGRES&allowEncodingChanges=false¤tSchema=report&targetServerType=any&loadBalanceHosts=false&hostRecheckSeconds=10&preferQueryMode=extended&autosave=never&reWriteBatchedInserts=false │ OK karaf@root()> jdbc:query jdbc/postgresql 'select * from incident'; date │ summary │ name │ details │ id │ email ────────────────────┼────────────┼────────┼───────────────────────────────┼────┼───────────────── 2018-02-20 08:00:00 │ Incident 1 │ User 1 │ This is a report incident 001 │ 1 │ user1@redhat.com 2018-02-20 08:10:00 │ Incident 2 │ User 2 │ This is a report incident 002 │ 2 │ user2@redhat.com 2018-02-20 08:20:00 │ Incident 3 │ User 3 │ This is a report incident 003 │ 3 │ user3@redhat.com 2018-02-20 08:30:00 │ Incident 4 │ User 4 │ This is a report incident 004 │ 4 │ user4@redhat.com
위 목록에 표시된 것처럼 블루프린트 번은 일반적인 데이터베이스 별 연결 풀인 javax.sql.DataSource
서비스를 내보냅니다. 블루프린트 XML에는 명시적인 <service ref="postgresql"
> 선언이 없기 때문에 데이터베이스별 javax.sql.XADataSource
는 OSGi 서비스로 등록되지 않습니다.
6.8.3. 데이터 소스 혼합 배포
데이터 소스 혼합 배포에서 pax-jdbc-config
1.3.0 번들은 서비스 속성을 사용하여 데이터베이스별 데이터 소스를 풀링 데이터 소스 내에 래핑 하는 또 다른 방법을 추가합니다. 이 방법은 Fuse 6.x에서 작동하는 방식과 일치합니다.
블루프린트 XML 예제는 다음과 같습니다.
<!-- Database-specific, non-pooling, non-enlisting javax.sql.XADataSource --> <bean id="postgresql" class="org.postgresql.xa.PGXADataSource"> <property name="url" value="jdbc:postgresql://localhost:5432/reportdb" /> <property name="user" value="fuse" /> <property name="password" value="fuse" /> <property name="currentSchema" value="report" /> <property name="connectTimeout" value="5" /> </bean> <!-- Expose database-specific data source with service properties. No need to expose pooling, enlisting, non database-specific javax.sql.DataSource. It is registered automatically by pax-jdbc-config with the same properties as this <service>, but with higher service.ranking. --> <service id="pool" ref="postgresql" interface="javax.sql.XADataSource"> <service-properties> <!-- "pool" key is needed for pax-jdbc-config to wrap database-specific data source inside connection pool --> <entry key="pool" value="dbcp2" /> <entry key="osgi.jndi.service.name" value="jdbc/postgresql" /> <!-- Other properties that configure given connection pool, as indicated by pool=dbcp2 --> <entry key="pool.minIdle" value="2" /> <entry key="pool.maxTotal" value="10" /> <entry key="pool.blockWhenExhausted" value="true" /> <entry key="pool.maxWaitMillis" value="2000" /> <entry key="pool.testOnBorrow" value="true" /> <entry key="pool.testWhileIdle" value="false" /> <entry key="factory.validationQuery" value="select schema_name from information_schema.schemata" /> <entry key="factory.validationQueryTimeout" value="2" /> </service-properties> </service>
위의 예에서는 데이터베이스별 데이터 소스만 수동으로 등록됩니다. pool=dbcp2
service 속성은 pax-jdbc-config
번들에서 관리하는 데이터 소스 추적기에 대한 힌트입니다. 이 서비스 속성이 있는 데이터 소스 서비스는 풀링 데이터 소스(이 예에서는 pax-jdbc-pool-dbcp2
) 내에서 래핑됩니다.
Fuse/Karaf 쉘의 예는 다음과 같습니다.
karaf@root()> feature:install jdbc pax-jdbc-config pax-jdbc-pool-dbcp2 karaf@root()> install -s mvn:org.postgresql/postgresql/42.2.5 Bundle ID: 232 karaf@root()> install -s blueprint:file://$PQ_HOME/databases/blueprints/postgresql-pax-jdbc-discovery.xml Bundle ID: 233 karaf@root()> bundle:services -p 233 Bundle 233 provides: -------------------- factory.validationQuery = select schema_name from information_schema.schemata factory.validationQueryTimeout = 2 objectClass = [javax.sql.XADataSource] osgi.jndi.service.name = jdbc/postgresql osgi.service.blueprint.compname = postgresql pool = dbcp2 pool.blockWhenExhausted = true pool.maxTotal = 10 pool.maxWaitMillis = 2000 pool.minIdle = 2 pool.testOnBorrow = true pool.testWhileIdle = false service.bundleid = 233 service.id = 336 service.scope = bundle ----- objectClass = [org.osgi.service.blueprint.container.BlueprintContainer] osgi.blueprint.container.symbolicname = postgresql-pax-jdbc-discovery.xml osgi.blueprint.container.version = 0.0.0 service.bundleid = 233 service.id = 338 service.scope = singleton karaf@root()> service:list javax.sql.XADataSource [javax.sql.XADataSource] ------------------------ factory.validationQuery = select schema_name from information_schema.schemata factory.validationQueryTimeout = 2 osgi.jndi.service.name = jdbc/postgresql osgi.service.blueprint.compname = postgresql pool = dbcp2 pool.blockWhenExhausted = true pool.maxTotal = 10 pool.maxWaitMillis = 2000 pool.minIdle = 2 pool.testOnBorrow = true pool.testWhileIdle = false service.bundleid = 233 service.id = 336 service.scope = bundle Provided by : Bundle 233 Used by: OPS4J Pax JDBC Config (224) karaf@root()> service:list javax.sql.DataSource [javax.sql.DataSource] ---------------------- factory.validationQuery = select schema_name from information_schema.schemata factory.validationQueryTimeout = 2 osgi.jndi.service.name = jdbc/postgresql osgi.service.blueprint.compname = postgresql pax.jdbc.managed = true pax.jdbc.service.id.ref = 336 pool.blockWhenExhausted = true pool.maxTotal = 10 pool.maxWaitMillis = 2000 pool.minIdle = 2 pool.testOnBorrow = true pool.testWhileIdle = false service.bundleid = 224 service.id = 337 service.ranking = 1000 service.scope = singleton Provided by : OPS4J Pax JDBC Config (224) karaf@root()> jdbc:ds-list Name │ Product │ Version │ URL │ Status ────────────────┼────────────┼───────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────── jdbc/postgresql │ PostgreSQL │ 10.3 (Debian 10.3-1.pgdg90+1) │ jdbc:postgresql://localhost:5432/reportdb?prepareThreshold=5&preparedStatementCacheQueries=256&preparedStatementCacheSizeMiB=5&databaseMetadataCacheFields=65536&databaseMetadataCacheFieldsMiB=5&defaultRowFetchSize=0&binaryTransfer=true&readOnly=false&binaryTransferEnable=&binaryTransferDisable=&unknownLength=2147483647&logUnclosedConnections=false&disableColumnSanitiser=false&tcpKeepAlive=false&loginTimeout=0&connectTimeout=5&socketTimeout=0&cancelSignalTimeout=10&receiveBufferSize=-1&sendBufferSize=-1&ApplicationName=PostgreSQL JDBC Driver&jaasLogin=true&useSpnego=false&gsslib=auto&sspiServiceClass=POSTGRES&allowEncodingChanges=false¤tSchema=report&targetServerType=any&loadBalanceHosts=false&hostRecheckSeconds=10&preferQueryMode=extended&autosave=never&reWriteBatchedInserts=false │ OK jdbc/postgresql │ PostgreSQL │ 10.3 (Debian 10.3-1.pgdg90+1) │ jdbc:postgresql://localhost:5432/reportdb?prepareThreshold=5&preparedStatementCacheQueries=256&preparedStatementCacheSizeMiB=5&databaseMetadataCacheFields=65536&databaseMetadataCacheFieldsMiB=5&defaultRowFetchSize=0&binaryTransfer=true&readOnly=false&binaryTransferEnable=&binaryTransferDisable=&unknownLength=2147483647&logUnclosedConnections=false&disableColumnSanitiser=false&tcpKeepAlive=false&loginTimeout=0&connectTimeout=5&socketTimeout=0&cancelSignalTimeout=10&receiveBufferSize=-1&sendBufferSize=-1&ApplicationName=PostgreSQL JDBC Driver&jaasLogin=true&useSpnego=false&gsslib=auto&sspiServiceClass=POSTGRES&allowEncodingChanges=false¤tSchema=report&targetServerType=any&loadBalanceHosts=false&hostRecheckSeconds=10&preferQueryMode=extended&autosave=never&reWriteBatchedInserts=false │ OK karaf@root()> jdbc:query jdbc/postgresql 'select * from incident' date │ summary │ name │ details │ id │ email ────────────────────┼────────────┼────────┼───────────────────────────────┼────┼───────────────── 2018-02-20 08:00:00 │ Incident 1 │ User 1 │ This is a report incident 001 │ 1 │ user1@redhat.com 2018-02-20 08:10:00 │ Incident 2 │ User 2 │ This is a report incident 002 │ 2 │ user2@redhat.com 2018-02-20 08:20:00 │ Incident 3 │ User 3 │ This is a report incident 003 │ 3 │ user3@redhat.com 2018-02-20 08:30:00 │ Incident 4 │ User 4 │ This is a report incident 004 │ 4 │ user4@redhat.com
이 목록에는 jdbc:ds-list
출력에서 볼 수 있듯이 두 개의 데이터 소스, 원래 데이터 소스 및 래퍼 데이터 소스가 있습니다.
javax.sql.XADataSource
는 블루프린트 번들에서 등록되며 pool = dbcp2
속성이 선언되어 있습니다.
javax.sql.DataSource
는 pax-jdbc-config
번들에서 등록되어 있습니다.
-
pool = dbcp2
속성이 없습니다( 래퍼 데이터 소스를 등록할 때 제거됨). -
service.ranking = 1000
속성이 있으므로 예를 들어 이름으로 데이터 소스를 찾을 때 기본 설정 버전입니다. -
pax.jdbc.managed = true
속성이 있으므로 다시 래핑하려고 시도하지 않습니다. -
연결 풀 내에서 래핑된 원래 데이터 소스 서비스를 표시하기 위해
pax.jdbc.service.id.ref = 336
속성이 있습니다.
6.9. Java™ 지속성 API로 데이터 소스 사용
트랜잭션 관리 관점에서 JPA(Java™ Persistence API)와 함께 데이터 소스를 사용하는 방법을 이해하는 것이 중요합니다. 이 섹션에서는 JPA 사양 자체의 세부 정보 또는 가장 알려진 JPA 구현인 Hibernate에 대한 세부 정보를 설명하지 않습니다. 대신 이 섹션에서는 JPA 영구 단위를 데이터 소스에 가리키는 방법을 보여줍니다.
6.9.1. 데이터 소스 참조 정보
META-INF/persistence.xml
설명자( JPA 2.1 사양 참조, 8.2.1.5 jta-data-source, non-jta-data-source)는 다음 두 가지 종류의 데이터 소스 참조를 정의합니다.
-
<JTA-data-source
> -JTA
트랜잭션과 함께 사용할 JTA 사용 데이터 소스에 대한 JNDI 참조입니다. -
<non-jta-data-source
> - JTA 트랜잭션 외부에서 사용할JTA
사용 데이터 소스에 대한 JNDI 참조입니다. 이 데이터 소스는 일반적으로 초기화 단계에서도 사용됩니다. 예를 들어, Hibernate를 자동 생성 데이터베이스 스키마로 구성하는hibernate.hbm2ddl.auto
속성도 사용됩니다.
이 두 데이터 소스는 javax.sql.DataSource
또는 javax.sql.XADataSource
와 관련이 없습니다! 이는 JPA 애플리케이션을 개발할 때 일반적으로 잘못된 오류입니다. 두 JNDI 이름은 모두 JNDI 바인딩된 javax.sql.DataSource
서비스를 참조해야 합니다.
6.9.2. JNDI 이름 참조
osgi.jndi.service.name
속성에 OSGi 서비스를 등록하면 OSGi JNDI 서비스에 바인딩 됩니다. OSGi 런타임(예: Fuse/Karaf)에서 JNDI는 이름 → 값 쌍으로 구성된 간단한 사전이 아닙니다. OSGi의 JNDI 이름을 사용하여 오브젝트를 참조하려면 서비스 조회 및 서비스 후크와 같은 기타 더 복잡한 OSGi 메커니즘이 포함됩니다.
다음 목록에서는 새로운 Fuse 설치에서 JNDI에 데이터 소스를 등록하는 방법을 보여줍니다.
karaf@root()> install -s mvn:mysql/mysql-connector-java/5.1.34 Bundle ID: 223 karaf@root()> install -s mvn:org.osgi/org.osgi.service.jdbc/1.0.0 Bundle ID: 224 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-mysql/1.3.0 Bundle ID: 225 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc/1.3.0 Bundle ID: 226 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-pool-common/1.3.0 Bundle ID: 227 karaf@root()> install -s mvn:org.ops4j.pax.jdbc/pax-jdbc-config/1.3.0 Bundle ID: 228 karaf@root()> config:edit --factory --alias mysql org.ops4j.datasource karaf@root()> config:property-set osgi.jdbc.driver.name mysql karaf@root()> config:property-set dataSourceName mysqlds karaf@root()> config:property-set osgi.jndi.service.name jdbc/mysqlds karaf@root()> config:property-set dataSourceType DataSource karaf@root()> config:property-set jdbc.url jdbc:mysql://localhost:3306/reportdb karaf@root()> config:property-set jdbc.user fuse karaf@root()> config:property-set jdbc.password fuse karaf@root()> config:property-set jdbc.useSSL false karaf@root()> config:update karaf@root()> feature:install jndi karaf@root()> jndi:names JNDI Name │ Class Name ──────────────────────────┼─────────────────────────────────────────────── osgi:service/jndi │ org.apache.karaf.jndi.internal.JndiServiceImpl osgi:service/jdbc/mysqlds │ com.mysql.jdbc.jdbc2.optional.MysqlDataSource
표시된 대로 데이터 소스는 osgi:service/jdbc/mysqlds
JNDI 이름에서 사용할 수 있습니다.
그러나 OSGi에서 JPA의 경우 전체 JNDI 이름을 사용해야 합니다. 다음은 데이터 소스 참조를 지정하는 샘플 META-INF/persistence.xml
조각입니다.
<jta-data-source> osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/mysqlds) </jta-data-source> <non-jta-data-source> osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/mysqlds) </non-jta-data-source>
위의 구성이 없으면 다음과 같은 오류가 발생할 수 있습니다.
Persistence unit "pu-name" refers to a non OSGi service DataSource
7장. JMS 연결 팩토리 사용
이 장에서는 OSGi에서 JMS 연결 팩토리를 사용하는 방법을 설명합니다. 기본적으로 다음을 사용하여 수행합니다.
org.osgi.framework.BundleContext.registerService(javax.jms.ConnectionFactory.class, connectionFactoryObject, properties); org.osgi.framework.BundleContext.registerService(javax.jms.XAConnectionFactory.class, xaConnectionFactoryObject, properties);
이러한 서비스를 등록하는 방법은 다음 두 가지가 있습니다.
-
jms:create
Karaf console 명령을 사용하여 연결 팩토리 게시. 구성 방법입니다. -
블루프린트, OSGi 선언 서비스(SCR) 또는
BundleContext.registerService()
API 호출과 같은 방법을 사용하여 연결 팩토리 게시. 이 메서드에는 코드 및/또는 메타데이터가 포함된 전용 OSGi 번들이 필요합니다. 배포 방법입니다.
자세한 내용은 다음 항목에 있습니다.
7.1. OSGi JMS 서비스 정보
JDBC 데이터 소스를 처리하는 OSGi 방법은 다음 두 인터페이스와 관련이 있습니다.
-
standard
org.osgi.service.jdbc.DataSourceFactory
-
proprietary
org.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory
JMS의 경우 다음 유추를 고려하십시오.
-
표준 OSGi JDBC
org.
osgi.service.jdbc.DataSourcefactory와 동일한 목적을 가진 전용 org.ops4j.pax.jms.service.ConnectionFactory
factory -
독점
org.ops4j.pax.jms.service.PooledConnectionFactory
factory 전용 pax-jdbcorg.ops4j.pax.jdbc.pool.common.PooledDataSourceFactory
와 동일한 용도
전용 브로커별 org.ops4j.pax.jms.service.ConnectionFactoryFactory
구현의 경우 다음과 같은 번들이 있습니다.
-
mvn:org.ops4j.pax.jms/pax-jms-artemis/1.0.0
-
mvn:org.ops4j.pax.jms/pax-jms-ibmmq/1.0.0
-
mvn:org.ops4j.pax.jms/pax-jms-activemq/1.0.0
이러한 번들은 javax.
.ConnectionFactoryfactory 서비스를 등록합니다. 예를 들면 다음과 같습니다.
jms.ConnectionFactory
Factory 및 javax.jms.XAConnectionFactory
와 같은 JMS 팩토리 를 반환할 수 있는 브로커별 org.ops4j.pax.jms.service
karaf@root()> feature:install pax-jms-artemis karaf@root()> bundle:services -p org.ops4j.pax.jms.pax-jms-config OPS4J Pax JMS Config (248) provides: ------------------------------------ objectClass = [org.osgi.service.cm.ManagedServiceFactory] service.bundleid = 248 service.id = 328 service.pid = org.ops4j.connectionfactory service.scope = singleton karaf@root()> bundle:services -p org.ops4j.pax.jms.pax-jms-artemis OPS4J Pax JMS Artemis Support (247) provides: --------------------------------------------- objectClass = [org.ops4j.pax.jms.service.ConnectionFactoryFactory] service.bundleid = 247 service.id = 327 service.scope = singleton type = artemis
7.2. PAX-JMS 구성 서비스 정보
mvn:org.ops4j.pax.jms/pax-jms-config/1.0.0
번들에서는 다음 세 가지 작업을 수행하는 관리형 서비스 Cryostat를 제공합니다.
org.ops4j.pax.jms.service.ConnectionFactoryFactory
OSGi 서비스를 추적하여 해당 메서드를 호출합니다.public ConnectionFactory createConnectionFactory(Map<String, Object> properties); public XAConnectionFactory createXAConnectionFactory(Map<String, Object> properties);
-
위의 방법에 필요한 속성을 수집하기 위해
org.ops4j.connection factory 팩토리 PID
를 추적합니다. 예를 들어${karaf.etc}/org.ops4j.connectionfactory-artemis.cfg
파일을 생성하여 구성 관리 서비스에 사용할 수 있는 방법을 사용하여 팩토리 구성을 생성하는 경우 최종 단계를 수행하여 브로커별 연결 팩토리를 노출할 수 있습니다. -
javax.jms.ConnectionFactory
및javax.jms.XAConnectionFactory
서비스를 추적하여 JMS 연결 팩토리 풀링 내에서 래핑합니다.
자세한 내용은 다음 항목에 있습니다.
7.2.1. AMQ 7.1용 연결 팩토리 생성
다음은 Artemis 브로커에 대한 연결 요소를 만들기 위한 세부적이고 표준 적인 단계별 가이드입니다.
pax-jms-artemis
기능 및pax-jms-config
기능을 사용하여 Artemis 드라이버를 설치합니다.karaf@root()> feature:install pax-jms-artemis karaf@root()> bundle:services -p org.ops4j.pax.jms.pax-jms-config OPS4J Pax JMS Config (248) provides: ------------------------------------ objectClass = [org.osgi.service.cm.ManagedServiceFactory] service.bundleid = 248 service.id = 328 service.pid = org.ops4j.connectionfactory service.scope = singleton karaf@root()> bundle:services -p org.ops4j.pax.jms.pax-jms-artemis OPS4J Pax JMS Artemis Support (247) provides: --------------------------------------------- objectClass = [org.ops4j.pax.jms.service.ConnectionFactoryFactory] service.bundleid = 247 service.id = 327 service.scope = singleton type = artemis
팩토리 구성 을 생성합니다.
karaf@root()> config:edit --factory --alias artemis org.ops4j.connectionfactory karaf@root()> config:property-set type artemis karaf@root()> config:property-set osgi.jndi.service.name jms/artemis # "name" property may be used too karaf@root()> config:property-set connectionFactoryType ConnectionFactory # or XAConnectionFactory karaf@root()> config:property-set jms.url tcp://localhost:61616 karaf@root()> config:property-set jms.user admin karaf@root()> config:property-set jms.password admin karaf@root()> config:property-set jms.consumerMaxRate 1234 karaf@root()> config:update karaf@root()> config:list '(service.factoryPid=org.ops4j.connectionfactory)' ---------------------------------------------------------------- Pid: org.ops4j.connectionfactory.965d4eac-f5a7-4f65-ba1a-15caa4c72703 FactoryPid: org.ops4j.connectionfactory BundleLocation: ? Properties: connectionFactoryType = ConnectionFactory felix.fileinstall.filename = file:${karar.etc}/org.ops4j.connectionfactory-artemis.cfg jms.consumerMaxRate = 1234 jms.password = admin jms.url = tcp://localhost:61616 jms.user = admin osgi.jndi.service.name = jms/artemis service.factoryPid = org.ops4j.connectionfactory service.pid = org.ops4j.connectionfactory.965d4eac-f5a7-4f65-ba1a-15caa4c72703 type = artemis
pax-jms-config
가javax.jms.ConnectionFactory
서비스로 구성을 처리했는지 확인합니다.karaf@root()> service:list javax.jms.ConnectionFactory [javax.jms.ConnectionFactory] ----------------------------- connectionFactoryType = ConnectionFactory felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.connectionfactory-artemis.cfg jms.consumerMaxRate = 1234 jms.password = admin jms.url = tcp://localhost:61616 jms.user = admin osgi.jndi.service.name = jms/artemis pax.jms.managed = true service.bundleid = 248 service.factoryPid = org.ops4j.connectionfactory service.id = 342 service.pid = org.ops4j.connectionfactory.965d4eac-f5a7-4f65-ba1a-15caa4c72703 service.scope = singleton type = artemis Provided by : OPS4J Pax JMS Config (248)
참고추가 Artemis 구성(특히
protocol=amqp
)을 지정하는 경우 Artemis JMS 클라이언트 대신 QPID JMS 라이브러리가 사용됩니다. 그런 다음amqp://
프로토콜을jms.url
속성에 사용해야 합니다.- 연결을 테스트합니다.
이제 필요한 경우 삽입할 수 있는 브로커별(아직 풀링 없음) 연결 팩토리가 있습니다. 예를 들어 jms
기능의 Karaf 명령을 사용할 수 있습니다.
karaf@root()> feature:install -v jms Adding features: jms/[4.2.0.fuse-000237-redhat-1,4.2.0.fuse-000237-redhat-1] ... karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/artemis karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1 karaf@root()> jms:send -u admin -p admin jms/artemis DEV.QUEUE.1 "Hello Artemis" karaf@root()> jms:browse -u admin -p admin jms/artemis DEV.QUEUE.1 Message ID │ Content │ Charset │ Type │ Correlation ID │ Delivery Mode │ Destination │ Expiration │ Priority │ Redelivered │ ReplyTo │ Timestamp ────────────────────────────────────────┼───────────────┼─────────┼──────┼────────────────┼───────────────┼────────────────────────────┼────────────┼──────────┼─────────────┼─────────┼────────────────────────────── ID:2b6ea56d-574d-11e8-971a-7ee9ecc029d4 │ Hello Artemis │ UTF-8 │ │ │ Persistent │ ActiveMQQueue[DEV.QUEUE.1] │ Never │ 4 │ false │ │ Mon May 14 10:02:38 CEST 2018
다음 목록은 프로토콜을 전환할 때 발생하는 상황을 보여줍니다.
karaf@root()> config:list '(service.factoryPid=org.ops4j.connectionfactory)' ---------------------------------------------------------------- Pid: org.ops4j.connectionfactory.965d4eac-f5a7-4f65-ba1a-15caa4c72703 FactoryPid: org.ops4j.connectionfactory BundleLocation: ? Properties: connectionFactoryType = ConnectionFactory felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.connectionfactory-artemis.cfg jms.consumerMaxRate = 1234 jms.password = fuse jms.url = tcp://localhost:61616 jms.user = fuse osgi.jndi.service.name = jms/artemis service.factoryPid = org.ops4j.connectionfactory service.pid = org.ops4j.connectionfactory.965d4eac-f5a7-4f65-ba1a-15caa4c72703 type = artemis karaf@root()> config:edit org.ops4j.connectionfactory.312eb09a-d686-4229-b7e1-2ea38a77bb0f karaf@root()> config:property-set protocol amqp karaf@root()> config:property-delete user karaf@root()> config:property-set username admin # mind the difference between artemis-jms-client and qpid-jms-client karaf@root()> config:property-set jms.url amqp://localhost:61616 karaf@root()> config:update karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼──────────────── product │ QpidJMS version │ 0.30.0.redhat-1 karaf@root()> jms:browse -u admin -p admin jms/artemis DEV.QUEUE.1 Message ID │ Content │ Charset │ Type │ Correlation ID │ Delivery Mode │ Destination │ Expiration │ Priority │ Redelivered │ ReplyTo │ Timestamp ───────────┼───────────────┼─────────┼──────┼────────────────┼───────────────┼─────────────┼────────────┼──────────┼─────────────┼─────────┼────────────────────────────── │ Hello Artemis │ UTF-8 │ │ │ Persistent │ DEV.QUEUE.1 │ Never │ 4 │ false │ │ Mon May 14 10:02:38 CEST 2018
7.2.2. IBM MQ 8 또는 IBM MQ 9용 연결 팩토리 생성
이 섹션에서는 IBM MQ 8 및 IBM MQ 9에 연결하는 방법을 설명합니다. pax-jms-ibmmq
가 관련 pax-jms
번들을 설치하더라도 라이센스로 인해 IBM MQ 드라이버가 설치되지 않습니다.
- https://developer.ibm.com/messaging/mq-downloads/으로 이동합니다.
- 로그인합니다.
- 설치할 버전을 클릭합니다(예: IBM MQ 8.0 Client 또는 IBM MQ 9.0 Client ).
- 표시되는 페이지의 다운로드 버전 표에서 원하는 버전을 클릭합니다.
-
다음 페이지에서 접미사
IBM-MQ-Install-Java-All
이 있는 최신 버전을 선택합니다. 예를 들어8.0.0.10-WS-MQ-Install-Java-All
또는9.0.0.4-IBM-Install-Java-All를 다운로드합니다
. - 다운로드한 JAR 파일의 내용을 추출합니다.
bundle:install
명령을 실행합니다. 예를 들어/home/Downloads
디렉터리에 콘텐츠를 추출한 경우 다음과 같은 명령을 입력합니다.`bundle:install -s wrap:file:////home/Downloads/9.0.0.4-IBM-MQ-Install-Java-All/ibmmq9/wmq/JavaSE/com.ibm.mq.allclient.jar`.
다음과 같이 연결 팩토리를 생성합니다.
pax-jms-ibmmq
를 설치합니다.karaf@root()> feature:install pax-jms-ibmmq karaf@root()> bundle:services -p org.ops4j.pax.jms.pax-jms-ibmmq OPS4J Pax JMS IBM MQ Support (239) provides: -------------------------------------------- objectClass = [org.ops4j.pax.jms.service.ConnectionFactoryFactory] service.bundleid = 239 service.id = 346 service.scope = singleton type = ibmmq
팩토리 구성 생성:
karaf@root()> config:edit --factory --alias ibmmq org.ops4j.connectionfactory karaf@root()> config:property-set type ibmmq karaf@root()> config:property-set osgi.jndi.service.name jms/mq9 # "name" property may be used too karaf@root()> config:property-set connectionFactoryType ConnectionFactory # or XAConnectionFactory karaf@root()> config:property-set jms.queueManager FUSEQM karaf@root()> config:property-set jms.hostName localhost karaf@root()> config:property-set jms.port 1414 karaf@root()> config:property-set jms.transportType 1 # com.ibm.msg.client.wmq.WMQConstants.WMQ_CM_CLIENT karaf@root()> config:property-set jms.channel DEV.APP.SVRCONN karaf@root()> config:property-set jms.CCSID 1208 # com.ibm.msg.client.jms.JmsConstants.CCSID_UTF8 karaf@root()> config:update karaf@root()> config:list '(service.factoryPid=org.ops4j.connectionfactory)' ---------------------------------------------------------------- Pid: org.ops4j.connectionfactory.eee4a757-a95d-46b8-b8b6-19aa3977d863 FactoryPid: org.ops4j.connectionfactory BundleLocation: ? Properties: connectionFactoryType = ConnectionFactory felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.connectionfactory-ibmmq.cfg jms.CCSID = 1208 jms.channel = DEV.APP.SVRCONN jms.hostName = localhost jms.port = 1414 jms.queueManager = FUSEQM jms.transportType = 1 osgi.jndi.service.name = jms/mq9 service.factoryPid = org.ops4j.connectionfactory service.pid = org.ops4j.connectionfactory.eee4a757-a95d-46b8-b8b6-19aa3977d863 type = ibmmq
pax-jms-config
가javax.jms.ConnectionFactory
서비스로 구성을 처리했는지 확인합니다.karaf@root()> service:list javax.jms.ConnectionFactory [javax.jms.ConnectionFactory] ----------------------------- connectionFactoryType = ConnectionFactory felix.fileinstall.filename = file:/data/servers/7.8.0.fuse-780038-redhat-00001/etc/org.ops4j.connectionfactory-ibmmq.cfg jms.CCSID = 1208 jms.channel = DEV.APP.SVRCONN jms.hostName = localhost jms.port = 1414 jms.queueManager = FUSEQM jms.transportType = 1 osgi.jndi.service.name = jms/mq9 pax.jms.managed = true service.bundleid = 237 service.factoryPid = org.ops4j.connectionfactory service.id = 347 service.pid = org.ops4j.connectionfactory.eee4a757-a95d-46b8-b8b6-19aa3977d863 service.scope = singleton type = ibmmq Provided by : OPS4J Pax JMS Config (237)
연결을 테스트합니다.
karaf@root()> feature:install -v jms Adding features: jms/[4.2.0.fuse-000237-redhat-1,4.2.0.fuse-000237-redhat-1] ... karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/mq9 karaf@root()> jms:info -u app -p fuse jms/mq9 Property │ Value ─────────┼──────────────────── product │ IBM MQ JMS Provider version │ 8.0.0.0 karaf@root()> jms:send -u app -p fuse jms/mq9 DEV.QUEUE.1 "Hello IBM MQ 9" karaf@root()> jms:browse -u app -p fuse jms/mq9 DEV.QUEUE.1 Message ID │ Content │ Charset │ Type │ Correlation ID │ Delivery Mode │ Destination │ Expiration │ Priority │ Redelivered │ ReplyTo │ Timestamp ────────────────────────────────────────────────────┼─────────────────────────────┼─────────┼──────┼────────────────┼───────────────┼──────────────────────┼────────────┼──────────┼─────────────┼─────────┼────────────────────────────── ID:414d512046555345514d202020202020c940f95a038b3220 │ Hello IBM MQ 9 │ UTF-8 │ │ │ Persistent │ queue:///DEV.QUEUE.1 │ Never │ 4 │ false │ │ Mon May 14 10:17:01 CEST 2018
IBM MQ Explorer 또는 웹 콘솔에서 메시지가 전송되었는지 확인할 수도 있습니다.
7.2.3. Apache Karaf에서 Fuse A-MQ 6.3 Client 사용
Fuse 소프트웨어 다운로드 페이지에서 Fuse 빠른 시작을
다운로드할 수 있습니다.
빠른 시작 zip 파일의 내용을 로컬 폴더(예: quickstarts
라는 폴더 )로 추출합니다.
OSGi 번들로 퀵스타트/camel/camel-jms
예제를 빌드하고 설치할 수 있습니다. 이 번들에는 JBoss A-MQ 6.3 JMS 큐로 메시지를 전송하는 Camel 경로에 대한 블루프린트 XML 정의가 포함되어 있습니다. JBoss A-MQ 6.3 브로커를 위한 연결 팩토리를 생성하는 절차는 다음과 같습니다.
7.2.3.1. 사전 요구 사항
- Maven 3.3.1 이상을 설치했습니다.
- 시스템에 Red Hat Fuse가 설치되어 있어야 합니다.
- 시스템에 JBoss A-MQ Broker 6.3이 설치되어 있어야 합니다.
- 고객 포털에서 Karaf 빠른 시작 zip 파일을 다운로드하여 추출했습니다.
7.2.3.2. 절차
-
quickstarts/camel/camel-jms/src/main/resources/OSGI-INF/blueprint/
디렉터리로 이동합니다. camel-context.xml
파일의 id="jms"로 다음 8080을 바꿉니다.<bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory"> <reference interface="javax.jms.ConnectionFactory" /> </property> <property name="transactionManager" ref="transactionManager"/> </bean>
다음 섹션에서는 JBoss A-MQ 6.3 연결 팩토리를 인스턴스화합니다.
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent"> <property name="connectionFactory" ref="activemqConnectionFactory"/> <property name="transactionManager" ref="transactionManager"/> </bean> <bean id="activemqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616"/> <property name="userName" value="admin"/> <property name="password" value="admin"/> </bean>
JBoss A-MQ 6.3 연결 팩토리는
tcp://localhost:61616
에서 수신 대기하는 브로커에 연결하도록 구성되어 있습니다. 기본적으로 JBoss A-MQ는 IP 포트 값61616
을 사용합니다. 연결 팩토리도 userName/password 인증 정보 admin/admin을 사용하도록 구성되어 있습니다. 이 사용자가 브로커 구도에서 활성화되어 있는지 확인하십시오 (또는 브로커 구성과 일치하도록 여기에서 이러한 설정을 사용자 지정할 수 있습니다).-
camel-context.xml
파일을 저장합니다. camel-jms
빠른 시작을 빌드합니다.$ cd quickstarts/camel/camel-jms $ mvn install
빠른 시작이 성공적으로 설치되면
$FUSE_HOME/
디렉터리로 이동하여 다음 명령을 실행하여 Apache Karaf 서버에서 Fuse를 시작합니다.$ ./bin/fuse
Fuse on Apache Karaf 인스턴스에서
activemq-client
기능 및camel-jms
기능을 설치합니다.karaf@root()> feature:install activemq-client karaf@root()> feature:install camel-jms
camel-jms
빠른 시작 번들을 설치합니다.karaf@root()> install -s mvn:org.jboss.fuse.quickstarts/camel-jms/{$fuseversion}
여기서
{$fuseversion}
을 방금 빌드한 Maven 아티팩트의 실제 버전으로 바꿉니다( camel-jms quickstart README 파일을 구성).JBoss A-MQ 6.3
브로커를 시작합니다(이 작업을 위해 JBoss A-MQ 6.3 설치 필요). 다른 터미널 창을 열고 JBOSS_AMQ_63_INSTALLDIR 디렉터리로 이동합니다.$ cd JBOSS_AMQ_63_INSTALLDIR $ ./bin/amq
-
Camel 경로가 시작된 즉시 Fuse 설치 시
work/jms/input
디렉터리가 표시됩니다. 이 빠른 시작의src/main/data 디렉토리에서
찾은 파일을 새로 생성된work/jms/input
디렉터리에 복사합니다. 잠시 기다렸다가 국가별로 구성된 동일한 파일이
work/jms/output
디렉토리 아래에 있습니다.order1.xml, order2.xml and order4.xml in work/jms/output/others order3.xml and order5.xml in work/jms/output/us order6.xml in work/jms/output/fr
log:display
를 사용하여 비즈니스 로깅을 확인합니다.Receiving order order1.xml Sending order order1.xml to another country Done processing order1.xml
7.2.4. 처리된 속성 요약
구성 관리 팩토리 PID 의 속성은 관련 org.ops4j.pax.jms.service.ConnectionFactoryFactory
구현으로 전달됩니다.
ActiveMQ
org.ops4j.pax.jms.activemq.ActiveMQConnectionFactoryFactory
(JMS 1.1만 해당)org.apache.activemq.ActiveMQConnectionFactory.buildFromMap()
메서드에 전달되는 속성Artemis
org.ops4j.pax.jms.artemis.ArtemisConnectionFactoryFactory
protocol=amqp
인 경우 속성은org.apache.qpid.jms.jms.jms.jms.
메서드로 전달됩니다.jms.JmsConnectionFactory 인스턴스를 구성하기 위해 org.apache.qpid.util.PropertyUtil.
setProperties()그렇지 않으면
org.apache.activemq.artemis.utils.uri.BeanSupport.setData()
는org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory
인스턴스에 대해 호출됩니다.IBM MQ
org.ops4j.pax.jms.ibmmq.MQConnectionFactoryFactory
com.ibm.mq.jms.MQConnectionFactory
또는com.ibm.mq.jms.MQXAConnectionFactory
의 Cryostat 속성이 처리됩니다.
7.3. JMS 콘솔 명령 사용
Apache Karaf는
범위에 쉘 명령을 포함하는 jms 기능을 제공합니다. 수동으로 구성된 연결 팩토리를 확인하기 위해 이러한 명령을 사용하는 몇 가지 예를 이미 확인했습니다. 구성 관리 구성을 생성할 필요성을 숨기는 명령도 있습니다.
jms
:*
새로운 Fuse 인스턴스부터 브로커별 연결 팩토리를 등록할 수 있습니다. 다음 목록에서는 Karaf에서 jms
기능 설치 및
의 설치를 보여줍니다.
pax-jms
-artemis
karaf@root()> feature:install jms pax-jms-artemis karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── karaf@root()> service:list javax.jms.ConnectionFactory # should be empty karaf@root()> service:list org.ops4j.pax.jms.service.ConnectionFactoryFactory [org.ops4j.pax.jms.service.ConnectionFactoryFactory] ---------------------------------------------------- service.bundleid = 250 service.id = 326 service.scope = singleton type = artemis Provided by : OPS4J Pax JMS Artemis Support (250)
다음 목록은 Artemis 연결 팩토리를 생성하고 확인하는 방법을 보여줍니다.
karaf@root()> jms:create -t artemis -u admin -p admin --url tcp://localhost:61616 artemis karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/artemis karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1 karaf@root()> jms:send -u admin -p admin jms/artemis DEV.QUEUE.1 "Hello Artemis" karaf@root()> jms:browse -u admin -p admin jms/artemis DEV.QUEUE.1 Message ID │ Content │ Charset │ Type │ Correlation ID │ Delivery Mode │ Destination │ Expiration │ Priority │ Redelivered │ ReplyTo │ Timestamp ────────────────────────────────────────┼───────────────┼─────────┼──────┼────────────────┼───────────────┼────────────────────────────┼────────────┼──────────┼─────────────┼─────────┼────────────────────────────── ID:7a944470-574f-11e8-918e-7ee9ecc029d4 │ Hello Artemis │ UTF-8 │ │ │ Persistent │ ActiveMQQueue[DEV.QUEUE.1] │ Never │ 4 │ false │ │ Mon May 14 10:19:10 CEST 2018 karaf@root()> config:list '(service.factoryPid=org.ops4j.connectionfactory)' ---------------------------------------------------------------- Pid: org.ops4j.connectionfactory.9184db6f-cb5f-4fd7-b5d7-a217090473ad FactoryPid: org.ops4j.connectionfactory BundleLocation: mvn:org.ops4j.pax.jms/pax-jms-config/1.0.0 Properties: name = artemis osgi.jndi.service.name = jms/artemis password = admin service.factoryPid = org.ops4j.connectionfactory service.pid = org.ops4j.connectionfactory.9184db6f-cb5f-4fd7-b5d7-a217090473ad type = artemis url = tcp://localhost:61616 user = admin
위 화면과 같이 org.ops4j.connectionfactory
팩토리 PID가 생성됩니다. 그러나 config:update
를 사용하면 ${karaf.etc}
에 자동으로 저장되지 않습니다. 다른 속성을 지정할 수는 없지만 나중에 추가할 수 있습니다.
7.4. 암호화된 구성 값 사용
pax-jdbc-config
번들과 마찬가지로 Jasypt를 사용하여 속성을 암호화할 수 있습니다.
별칭
서비스 속성으로 OSGi에 등록된 org.jasypt.encryption.StringEncryptor
서비스가 있는 경우 연결 팩토리 PID 에서 참조하고 암호화된 암호를 사용할 수 있습니다. 다음은 예제입니다.
felix.fileinstall.filename = */etc/org.ops4j.connectionfactory-artemis.cfg name = artemis type = artemis decryptor = my-jasypt-decryptor url = tcp://localhost:61616 user = fuse password = ENC(<encrypted-password>)
암호 해독기 서비스를 찾는 데 사용되는 서비스 필터는 (&(objectClass=org.jasypt.encryption.StringEncryptor)(alias=<alias>)
입니다. 여기서 < alias
>는 연결 팩토리 구성 팩토리 PID 의 암호 해독
속성 값입니다.
7.5. JMS 연결 풀 사용
이 섹션에서는 JMS 연결/세션 풀링 옵션에 대해 설명합니다. JDBC에 대한 선택 사항보다 적은 선택 사항이 있습니다. 정보는 다음 주제로 구성됩니다.
XA 복구를 사용하려면 pax-jms-pool-transx
또는 pax-jms-pool-narayana
연결 풀 모듈을 사용해야 합니다.
7.5.1. JMS 연결 풀 사용 소개
지금까지 브로커별 연결 팩토리 를 등록했습니다. 연결 팩토리 자체는 연결 팩토리 의 팩토리이기 때문에 org.ops4j.pax.jms.service.ConnectionFactoryFactory
서비스는 메타 팩토리 로 취급될 수 있습니다. 두 종류의 연결 팩토리를 생성할 수 있어야 합니다.
-
javax.jms.ConnectionFactory
-
javax.jms.XAConnectionFactory
pax-jms-pool-*
번들은 org.ops4j.pax.jms.service.ConnectionFactoryFactory
서비스와 원활하게 작동합니다. 이러한 번들은 속성 세트와 원래 org.ops4j.pax.service.ConnectionFactoryfactory를 사용하여 풀링된 연결 팩토리를 생성하는 데 사용할 수 있는
factory의 구현을 제공합니다. 예를 들면 다음과 같습니다.
org.ops4j.pax.pax.jms.service.service.service.service.service.Pooled
ConnectionFactory
public interface PooledConnectionFactoryFactory { ConnectionFactory create(ConnectionFactoryFactory cff, Map<String, Object> props); }
다음 표에서는 풀링된 연결 팩토리 팩토리 팩토리를 등록하는 번들을 보여줍니다. 표에서 o.o.p.j.p
는 org.ops4j.pax.jms.pool
을 나타냅니다.
번들 | PooledConnectionFactoryFactory | 풀 키 |
---|---|---|
|
|
|
|
|
|
|
|
|
pax-jms-pool-narayana
팩토리를 pooled-jms
라이브러리를 기반으로 하므로 PooledJms(XA)PooledConnectionFactoryFactory
라고 합니다. XA 복구를 위한 Narayana 트랜잭션 관리자와의 통합을 추가합니다.
위의 번들은 연결 팩토리만 설치합니다. 연결 팩토리를 직접 설치하지 않는 번들입니다. 결과적으로 javax.jms.ConnectionFactory org.ops4j.pax.jms.service.PooledConnectionFactoryFactory.create()
메서드를 호출하는 데 필요한 것이 있습니다.
7.5.2. pax-jms-pool-pooledjms 연결 풀 모듈 사용
pax-jms-pooledjms 번들을 사용하는 방법을 이해하면
번들뿐만 아니라 pax-jms-pool-pooledjms
pax-jms-pool-pool
번들도 사용할 수 있습니다.
-
narayna
pax-jms-config 번들은 다음을 추적합니다.
-
org.ops4j.pax.jms.service.ConnectionFactoryFactory
services -
org.ops4j.connection factory팩토리 PID
-
pax-jms-pool-*
번들 중 하나로 등록된 org.ops4j.pax.jms.service.PooledConnectionFactory
팩토리 구성에 pool
속성이 포함된 경우 pax-jms-config
번들에 의해 등록된 궁극적인 연결 팩토리는 브로커별 연결 팩토리입니다. pool=pooledjms
인 경우 연결 팩토리는 다음 중 하나로 래핑됩니다.
-
org.messaginghub.pooled.jms.JmsPoolConnectionFactory
(xa=false
) -
org.messaginghub.pooled.jms.JmsPoolXAConnectionFactory
(xa=true
)
pool
속성(및 비xa/xa 연결 팩토리 중 하나를 선택하는 부울 xa
속성 외에도 org.ops4j.connectionfactory
factory PID 에는 풀 접두사가 있는 속성이 포함될 수 있습니다. .
pooled-jms
라이브러리의 경우 다음과 같은 접두사가 지정된 속성이 ( 접두사를 제거한 후) 사용하여 인스턴스를 구성합니다.
-
org.messaginghub.pooled.jms.JmsPoolConnectionFactory
, or -
org.messaginghub.pooled.jms.JmsPoolXAConnectionFactory
다음 목록은 jms와 함께 편리한 구문을 사용하는
-prefixed properties:
pooled-jms
풀(org.ops4j.connectionfactory-artemis
factory PID)의 비현실적 구성입니다.
# configuration for pax-jms-config to choose and configure specific org.ops4j.pax.jms.service.ConnectionFactoryFactory name = jms/artemis connectionFactoryType = ConnectionFactory jms.url = tcp://localhost:61616 jms.user = fuse jms.password = fuse # org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory specific coniguration jms.callTimeout = 12000 # ... # hints for pax-jms-config to use selected org.ops4j.pax.jms.service.PooledConnectionFactoryFactory pool = pooledjms xa = false # pooled-jms specific configuration of org.messaginghub.pooled.jms.JmsPoolConnectionFactory pool.idleTimeout = 10 pool.maxConnections = 100 pool.blockIfSessionPoolIsFull = true # ...
위의 구성에서 pool
및 xa
키는 등록된 org.ops4j.pax.jms.service.PooledConnectionFactoryfactory 서비스
중 하나를 선택하는 힌트 (서비스 필터 속성)입니다. pooled-jms
라이브러리의 경우 다음과 같습니다.
karaf@root()> feature:install pax-jms-pool-pooledjms karaf@root()> bundle:services -p org.ops4j.pax.jms.pax-jms-pool-pooledjms OPS4J Pax JMS MessagingHub JMS Pool implementation (252) provides: ------------------------------------------------------------------ objectClass = [org.ops4j.pax.jms.service.PooledConnectionFactoryFactory] pool = pooledjms service.bundleid = 252 service.id = 331 service.scope = singleton xa = false ----- objectClass = [org.ops4j.pax.jms.service.PooledConnectionFactoryFactory] pool = pooledjms service.bundleid = 252 service.id = 335 service.scope = singleton xa = true
다음은 연결 풀을 생성하고 구성하는 단계의 전체 예입니다.
필요한 기능을 설치합니다.
karaf@root()> feature:install -v pax-jms-pool-pooledjms pax-jms-artemis Adding features: pax-jms-pool-pooledjms/[1.0.0,1.0.0] ...
jms
기능을 설치합니다.karaf@root()> feature:install jms karaf@root()> service:list org.ops4j.pax.jms.service.ConnectionFactoryFactory [org.ops4j.pax.jms.service.ConnectionFactoryFactory] ---------------------------------------------------- service.bundleid = 249 service.id = 327 service.scope = singleton type = artemis Provided by : OPS4J Pax JMS Artemis Support (249) karaf@root()> service:list org.ops4j.pax.jms.service.PooledConnectionFactoryFactory [org.ops4j.pax.jms.service.PooledConnectionFactoryFactory] ---------------------------------------------------------- pool = pooledjms service.bundleid = 251 service.id = 328 service.scope = singleton xa = false Provided by : OPS4J Pax JMS MessagingHub JMS Pool implementation (251) [org.ops4j.pax.jms.service.PooledConnectionFactoryFactory] ---------------------------------------------------------- pool = pooledjms service.bundleid = 251 service.id = 333 service.scope = singleton xa = true Provided by : OPS4J Pax JMS MessagingHub JMS Pool implementation (251)
팩토리 구성 을 생성합니다.
karaf@root()> config:edit --factory --alias artemis org.ops4j.connectionfactory karaf@root()> config:property-set connectionFactoryType ConnectionFactory karaf@root()> config:property-set osgi.jndi.service.name jms/artemis karaf@root()> config:property-set type artemis karaf@root()> config:property-set protocol amqp # so we switch to org.apache.qpid.jms.JmsConnectionFactory karaf@root()> config:property-set jms.url amqp://localhost:61616 karaf@root()> config:property-set jms.username admin karaf@root()> config:property-set jms.password admin karaf@root()> config:property-set pool pooledjms karaf@root()> config:property-set xa false karaf@root()> config:property-set pool.idleTimeout 10 karaf@root()> config:property-set pool.maxConnections 123 karaf@root()> config:property-set pool.blockIfSessionPoolIsFull true karaf@root()> config:update
pax-jms-config
가javax.jms.ConnectionFactory
서비스로 구성을 처리했는지 확인합니다.karaf@root()> service:list javax.jms.ConnectionFactory [javax.jms.ConnectionFactory] ----------------------------- connectionFactoryType = ConnectionFactory felix.fileinstall.filename = file:${karaf.etc}/org.ops4j.connectionfactory-artemis.cfg jms.password = admin jms.url = amqp://localhost:61616 jms.username = admin osgi.jndi.service.name = jms/artemis pax.jms.managed = true pool.blockIfSessionPoolIsFull = true pool.idleTimeout = 10 pool.maxConnections = 123 protocol = amqp service.bundleid = 250 service.factoryPid = org.ops4j.connectionfactory service.id = 347 service.pid = org.ops4j.connectionfactory.fc1b9e85-91b4-421b-aa16-1151b0f836f9 service.scope = singleton type = artemis Provided by : OPS4J Pax JMS Config (250)
연결 팩토리를 사용합니다.
karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/artemis karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼──────────────── product │ QpidJMS version │ 0.30.0.redhat-1 karaf@root()> jms:send -u admin -p admin jms/artemis DEV.QUEUE.1 "Hello Artemis" karaf@root()> jms:browse -u admin -p admin jms/artemis DEV.QUEUE.1 Message ID │ Content │ Charset │ Type │ Correlation ID │ Delivery Mode │ Destination │ Expiration │ Priority │ Redelivered │ ReplyTo │ Timestamp ────────────────────────────────────────────────┼───────────────┼─────────┼──────┼────────────────┼───────────────┼─────────────┼────────────┼──────────┼─────────────┼─────────┼────────────────────────────── ID:64842f99-5cb2-4850-9e88-f50506d49d20:1:1:1-1 │ Hello Artemis │ UTF-8 │ │ │ Persistent │ DEV.QUEUE.1 │ Never │ 4 │ false │ │ Mon May 14 12:47:13 CEST 2018
7.5.3. pax-jms-pool-narayana 연결 풀 모듈 사용
pax-jms-pool-narayna
모듈은 pax-jms-pool-pooledjms
로 거의 모든 작업을 수행합니다. XA 및 비 XA 시나리오에 대해 pooled-jms-specific org.ops4j.pax.jms.service.PooledConnectionFactoryFactory
를 설치합니다. 유일한 차이점은 XA 시나리오에서는 추가 통합 포인트가 있다는 것입니다. org.jboss.tm.XAResourceRecovery
OSGi 서비스는 com.arjuna.ats.arjuna.recovery.Recovery.RecoveryManager
에서 선택할 수 있도록 등록되었습니다.
7.5.4. pax-jms-pool-transx 연결 풀 모듈 사용
pax-jms-pool-transx
모듈은
서비스의 구현을 제공합니다. pax-transx-jms
번들을 기반으로 하는 org.ops4j.pax.service.PooledConnectionFactoryFactorypax-transx-jms
번들은 org.ops4j.pax.transx.jms.ManagedConnectionFactoryBuilder
기능을 사용하여 javax.jms.ConnectionFactory
풀을 생성합니다. 이는 8.3절. “pax-transx 프로젝트 정보” 에서 설명하는 JCA(Java™ Connector Architecture) 솔루션입니다.
7.6. 연결 팩토리를 아티팩트로 배포
이 주제에서는 실제 권장 사항에 대해 설명합니다.
배포 방법 에서는javax.jms.ConnectionFactory
서비스는 애플리케이션 코드로 직접 등록합니다. 일반적으로 이 코드는 블루프린트 컨테이너 내에 있습니다. 블루프린트 XML은 일반 OSGi 번들의 일부일 수 있으며 mvn:
URI를 사용하여 설치하고 Maven 리포지토리(로컬 또는 원격)에 저장할 수 있습니다. 구성 관리 구성에 비해 번들과 같은 버전 제어를 더 쉽게 수행할 수 있습니다.
pax-jms-config
버전 1.0.0 번들은 연결 팩토리 구성을 위한 배포 방법을 추가합니다. 애플리케이션 개발자는 javax.jms.(XA)ConnectionFactory
서비스(일반적으로 Bluerpint XML를 사용하여)를 등록하고 서비스 속성을 지정합니다. 그런 다음 pax-jms-config
는 등록된 브로커별 연결 팩토리를 감지하고 (서비스 속성 사용) 일반 비 브로커별 연결 풀 내에서 서비스를 래핑합니다.
블루프린트 XML을 사용하는 세 가지 배포 방법은 다음과 같습니다.
7.6.1. 연결 팩토리의 수동 배포
이 방법에서는 pax-jms-config
번들이 필요하지 않습니다. 애플리케이션 코드는 브로커별 및 일반 연결 풀을 모두 등록합니다.
<!-- Broker-specific, non-pooling, non-enlisting javax.jms.XAConnectionFactory --> <bean id="artemis" class="org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory"> <argument value="tcp://localhost:61616" /> <property name="callTimeout" value="2000" /> <property name="initialConnectAttempts" value="3" /> </bean> <!-- Fuse exports this service from fuse-pax-transx-tm-narayana bundle. --> <reference id="tm" interface="javax.transaction.TransactionManager" /> <!-- Non broker-specific, generic, pooling, enlisting javax.jms.ConnectionFactory --> <bean id="pool" class="org.messaginghub.pooled.jms.JmsPoolXAConnectionFactory"> <property name="connectionFactory" ref="artemis" /> <property name="transactionManager" ref="tm" /> <property name="maxConnections" value="10" /> <property name="idleTimeout" value="10000" /> </bean> <!-- Expose connection factory for use by application code (such as Camel, Spring, ...) --> <service interface="javax.jms.ConnectionFactory" ref="pool"> <service-properties> <!-- Giving connection factory a name using one of these properties makes identification easier in jms:connectionfactories: --> <entry key="osgi.jndi.service.name" value="jms/artemis" /> <!--<entry key="name" value="jms/artemis" />--> <!-- Without any of the above, name will fall back to "service.id" --> </service-properties> </service>
다음은 사용 방법을 보여주는 쉘 명령은 다음과 같습니다.
karaf@root()> feature:install artemis-core-client artemis-jms-client karaf@root()> install -s mvn:org.apache.commons/commons-pool2/2.5.0 Bundle ID: 244 karaf@root()> install -s mvn:org.messaginghub/pooled-jms/0.3.0 Bundle ID: 245 karaf@root()> install -s blueprint:file://$PQ_HOME/message-brokers/blueprints/artemis-manual.xml Bundle ID: 246 karaf@root()> bundle:services -p 246 Bundle 246 provides: -------------------- objectClass = [javax.jms.ConnectionFactory] osgi.jndi.service.name = jms/artemis osgi.service.blueprint.compname = pool service.bundleid = 246 service.id = 340 service.scope = bundle ----- objectClass = [org.osgi.service.blueprint.container.BlueprintContainer] osgi.blueprint.container.symbolicname = artemis-manual.xml osgi.blueprint.container.version = 0.0.0 service.bundleid = 246 service.id = 341 service.scope = singleton karaf@root()> feature:install jms karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/artemis karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1
위 목록에 표시된 것처럼 블루프린트 번은 일반적인 브로커별 연결 풀인 javax.jms.ConnectionFactory
서비스를 내보냅니다. 블루프린트 XML에는 명시적인 <service ref="artemis"
> 선언이 없기 때문에 브로커별 javax.jms.XAConnectionFactory
는 OSGi 서비스로 등록되지 않습니다.
7.6.2. 연결 팩토리 배포
이 방법은 pax-jms-config
를 표준 방식으로 사용하는 방법을 보여줍니다. 이는 Fuse 6.x에 권장되는 방법과 약간 다릅니다. 여기서 풀링 구성을 서비스 속성으로 지정해야 했습니다.
블루프린트 XML 예제는 다음과 같습니다.
<!-- A broker-specific org.ops4j.pax.jms.service.ConnectionFactoryFactory that can create (XA)ConnectionFactory using properties. It is registered by pax-jms-* bundles --> <reference id="connectionFactoryFactory" interface="org.ops4j.pax.jms.service.ConnectionFactoryFactory" filter="(type=artemis)" /> <!-- Non broker-specific org.ops4j.pax.jms.service.PooledConnectionFactoryFactory that can create pooled connection factories with the help of org.ops4j.pax.jms.service.ConnectionFactoryFactory For example, pax-jms-pool-pooledjms bundle registers org.ops4j.pax.jms.service.PooledConnectionFactoryFactory with these properties: - pool = pooledjms - xa = true|false (both are registered) --> <reference id="pooledConnectionFactoryFactory" interface="org.ops4j.pax.jms.service.PooledConnectionFactoryFactory" filter="(&(pool=pooledjms)(xa=true))" /> <!-- When using XA connection factories, javax.transaction.TransactionManager service is not needed here. It is used internally by xa-aware pooledConnectionFactoryFactory. --> <!--<reference id="tm" interface="javax.transaction.TransactionManager" />--> <!-- Finally, use both factories to expose the pooled, xa-aware, connection factory. --> <bean id="pool" factory-ref="pooledConnectionFactoryFactory" factory-method="create"> <argument ref="connectionFactoryFactory" /> <argument> <props> <!-- Properties needed by artemis-specific org.ops4j.pax.jms.service.ConnectionFactoryFactory --> <prop key="jms.url" value="tcp://localhost:61616" /> <prop key="jms.callTimeout" value="2000" /> <prop key="jms.initialConnectAttempts" value="3" /> <!-- Properties needed by pooled-jms-specific org.ops4j.pax.jms.service.PooledConnectionFactoryFactory --> <prop key="pool.maxConnections" value="10" /> <prop key="pool.idleTimeout" value="10000" /> </props> </argument> </bean> <!-- Expose connection factory for use by application code (such as Camel, Spring, ...) --> <service interface="javax.jms.ConnectionFactory" ref="pool"> <service-properties> <!-- Giving connection factory a name using one of these properties makes identification easier in jms:connectionfactories: --> <entry key="osgi.jndi.service.name" value="jms/artemis" /> <!--<entry key="name" value="jms/artemis" />--> <!-- Without any of the above, name will fall back to "service.id" --> </service-properties> </service>
이전 예제에서는 연결 팩토리 (…)를 사용하여 연결 팩토리를 생성하는 팩토리 빈을 사용합니다. XA 인식 PooledConnectionFactoryFactory
에서 내부적으로 추적하므로 javax. Cryostat.TransactionManager
서비스에 대한 명시적 참조가 필요하지 않습니다.
Fuse/Karaf 쉘의 예는 다음과 같습니다.
karaf@root()> feature:install jms pax-jms-artemis pax-jms-pool-pooledjms karaf@root()> install -s blueprint:file://$PQ_HOME/message-brokers/blueprints/artemis-pax-jms-factory-pooledjms.xml Bundle ID: 253 karaf@root()> bundle:services -p 253 Bundle 253 provides: -------------------- objectClass = [javax.jms.ConnectionFactory] osgi.jndi.service.name = jms/artemis osgi.service.blueprint.compname = pool service.bundleid = 253 service.id = 347 service.scope = bundle ----- objectClass = [org.osgi.service.blueprint.container.BlueprintContainer] osgi.blueprint.container.symbolicname = artemis-pax-jms-factory-pooledjms.xml osgi.blueprint.container.version = 0.0.0 service.bundleid = 253 service.id = 348 service.scope = singleton karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/artemis karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1
위 목록에 표시된 것처럼 블루프린트 번은 일반적인 브로커별 연결 풀인 javax.jms.ConnectionFactory
서비스를 내보냅니다. 블루프린트 XML에는 명시적인 <service ref="artemis"
> 선언이 없기 때문에 브로커별 javax.jms.XAConnectionFactory
는 OSGi 서비스로 등록되지 않습니다.
7.6.3. 연결 팩토리의 혼합 배포
pax-jms-config
1.0.0 번에서는 서비스 속성을 사용하여 풀링 연결 팩토리 내의 브로커별 연결 팩토리를 래핑 하는 다른 방법을 추가합니다. 이 방법은 Fuse 6.x에서 작업하는 방식과 일치합니다.
블루프린트 XML 예제는 다음과 같습니다.
<!-- Broker-specific, non-pooling, non-enlisting javax.jms.XAConnectionFactory --> <bean id="artemis" class="org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory"> <argument value="tcp://localhost:61616" /> <property name="callTimeout" value="2000" /> <property name="initialConnectAttempts" value="3" /> </bean> <!-- Expose broker-specific connection factory with service properties. No need to expose pooling, enlisting, non broker-specific javax.jms.XAConnectionFactory. It will be registered automatically by pax-jms-config with the same properties as this <service>, but with a higher service.ranking --> <service id="pool" ref="artemis" interface="javax.jms.XAConnectionFactory"> <service-properties> <!-- "pool" key is needed for pax-jms-config to wrap broker-specific connection factory inside connection pool --> <entry key="pool" value="pooledjms" /> <!-- <service>/@id attribute does not propagate, but name of the connection factory is required using one of: --> <entry key="osgi.jndi.service.name" value="jms/artemis" /> <!-- or: --> <!--<entry key="name" value="jms/artemis" />--> <!-- Other properties, that normally by e.g., pax-jms-pool-pooledjms --> <entry key="pool.maxConnections" value="10" /> <entry key="pool.idleTimeout" value="10000" /> </service-properties> </service>
위의 예에서는 브로커별 연결 팩토리의 수동 레지스터만 볼 수 있습니다. pool=pooledjms
service 속성은 pax-jms-config
번들에서 관리하는 연결 팩토리 추적기에 대한 힌트입니다. 이 서비스 속성을 사용하는 연결 팩토리 서비스는 풀링 연결 팩토리(이 예에서는 pax-jms-pool-pooledjms
) 내에서 래핑됩니다.
Fuse/Karaf 쉘의 예는 다음과 같습니다.
karaf@root()> feature:install jms pax-jms-config pax-jms-artemis pax-jms-pool-pooledjms karaf@root()> install -s blueprint:file://$PQ_HOME/message-brokers/blueprints/artemis-pax-jms-discovery.xml Bundle ID: 254 karaf@root()> bundle:services -p 254 Bundle 254 provides: -------------------- objectClass = [javax.jms.XAConnectionFactory] osgi.jndi.service.name = jms/artemis osgi.service.blueprint.compname = artemis pool = pooledjms pool.idleTimeout = 10000 pool.maxConnections = 10 service.bundleid = 254 service.id = 349 service.scope = bundle ----- objectClass = [org.osgi.service.blueprint.container.BlueprintContainer] osgi.blueprint.container.symbolicname = artemis-pax-jms-discovery.xml osgi.blueprint.container.version = 0.0.0 service.bundleid = 254 service.id = 351 service.scope = singleton karaf@root()> service:list javax.jms.XAConnectionFactory [javax.jms.XAConnectionFactory] ------------------------------- osgi.jndi.service.name = jms/artemis osgi.service.blueprint.compname = artemis pool = pooledjms pool.idleTimeout = 10000 pool.maxConnections = 10 service.bundleid = 254 service.id = 349 service.scope = bundle Provided by : Bundle 254 Used by: OPS4J Pax JMS Config (251) karaf@root()> service:list javax.jms.ConnectionFactory [javax.jms.ConnectionFactory] ----------------------------- osgi.jndi.service.name = jms/artemis osgi.service.blueprint.compname = artemis pax.jms.managed = true pax.jms.service.id.ref = 349 pool.idleTimeout = 10000 pool.maxConnections = 10 service.bundleid = 251 service.id = 350 service.ranking = 1000 service.scope = singleton Provided by : OPS4J Pax JMS Config (251) karaf@root()> jms:connectionfactories JMS Connection Factory ────────────────────── jms/artemis karaf@root()> jms:info -u admin -p admin jms/artemis Property │ Value ─────────┼────────────────────────── product │ ActiveMQ version │ 2.4.0.amq-711002-redhat-1
이전 예에서 jms:connectionfactories
는 하나의 서비스만 표시합니다. 이 명령은 중복 이름을 제거하기 때문입니다. 데이터 소스의 혼합 배포에 두 가지 서비스가 jdbc:ds-list
에서 제공되었습니다.
javax.jms.XAConnectionFactory
는 블루프린트 번들에서 등록되며, 선언된 pool = pooledjms
속성이 있습니다.
javax.jms.ConnectionFactory
는 pax-jms-config
번들 및에서 등록됩니다.
-
pool = pooledjms
속성이 없습니다. 래퍼 연결 팩토리를 등록할 때 제거되었습니다. -
service.ranking = 1000
속성이 있으므로 예를 들어 이름으로 연결 팩토리를 찾을 때 기본 설정 버전입니다. -
pax.jms.managed = true
속성이 있으므로 다시 래핑하려고 시도하지 않습니다. -
연결 풀 내에서 래핑된 원래 연결 팩토리 서비스를 나타내는
pax.jms.service.id.ref = 349
속성이 있습니다.
8장. Java 커넥터 아키텍처 정보
JCA 사양은 다음과 같은 세 가지 참가자가 있는 시나리오를 일반화 하기 위해 생성되었습니다.
- 데이터베이스 또는 일반적으로 EIS 시스템과 같은 외부 시스템
- Cryostat 애플리케이션 서버
- 배포된 애플리케이션
8.1. 간단한 JDBC 유추
애플리케이션 및 데이터베이스만 있는 가장 간단한 시나리오에서는 다음과 같습니다.

javax.sql.DataSource
를 노출하는 애플리케이션 서버를 추가하면 XA와 같은 데이터 소스의 다양한 측면을 호출하지 않고 다음과 같습니다.

8.2. JCA 사용 개요
JCA는 드라이버와 애플리케이션 서버 간에 양방향 통신을 추가하여 데이터베이스 드라이버 의 개념을 일반화합니다. 드라이버는 javax. resource.spi.ResourceAdapter 로 표시되는 리소스 어댑터
가 됩니다.
두 가지 중요한 인터페이스가 있습니다.
-
리소스 어댑터에서 구현하는
javax.resource.spi.ManagedConnectionFactory
-
애플리케이션 서버에서 구현하는
javax.resource.spi.ConnectionManager
.
ManagedConnectionFactory
인터페이스는 다음 두 가지 용도로 사용됩니다.
Object createConnectionFactory(ConnectionManager cxManager)
메서드는 애플리케이션 코드에서 사용할 수 있는 지정된 EIS(또는 데이터베이스 또는 메시지 브로커)에 대한 연결 팩토리 를 생성하는 데 사용할 수 있습니다. 반환된오브젝트
는 다음과 같습니다.-
일반적인
javax.resource.cci.ConnectionFactory
(자세한 내용은 JCA 1.6, Chapter 17: Common Client Interface)를 참조하십시오. -
잘 알려진
javax.sql.DataSource
또는javax.jms.ConnectionFactory
와 같은 EIS 특정 연결 팩토리 이는pax-transx-jdbc
및pax-transx-jms
번들에서 사용하는 연결 팩토리 유형입니다.
-
일반적인
-
애플리케이션 서버에서 사용하는
javax.resource.spi.ManagedConnection ManagedConnectionFactory.createManagedConnection()
메서드는 EIS/database/broker에 대한 실제 물리적 연결을 생성합니다.
ConnectionManager
는 애플리케이션 서버에서 구현하고 리소스 어댑터 에서 사용합니다. 먼저 QoS 작업(풀링, 보안, 트랜잭션 관리)을 수행하고 마지막으로 ManagedConnection
인스턴스를 생성하기 위해 리소스 어댑터 의 ManagedConnectionFactory
에 위임하는 애플리케이션 서버 입니다. 흐름은 다음과 같습니다.
-
애플리케이션 코드는
ManagedConnectionFactory.createConnectionFactory()
에서 반환된 오브젝트를 사용하여 애플리케이션 서버에서 생성 및 노출된 연결 팩토리 를 사용합니다. 일반 CCI 인터페이스 또는javax.sql.DataSource
일 수 있습니다. -
이 연결 팩토리 에서는 자체적으로 연결을 생성하지 않고
ConnectionManager.allocateConnection()
에 위임하는 대신 리소스 어댑터(특정ManagedConnectionFactory
)를 전달합니다. -
애플리케이션 서버에서 구현된
ConnectionManager
는 지원 개체 를 생성하고, 트랜잭션, 풀링 등을 관리하며 결국 전달된ManagedConnectionFactory
에서 물리적(관리) 연결을 가져옵니다. - 애플리케이션 코드는 결국 리소스 어댑터 의 특정 물리적 연결에 위임하는 애플리케이션 서버에서 생성한 래퍼/proxy인 연결을 가져옵니다.
다음은 애플리케이션 서버 가 EIS별로 연결된 비CCI 연결 팩토리 를 생성한 다이어그램입니다. 간단히 - EIS(here: database)에 대한 액세스는 javax.sql.DataSource
인터페이스를 사용하여 수행되며 드라이버의 작업은 물리적 연결을 제공하는 것입니다. 애플리케이션 서버는 풀링/거부/보안을 수행하는 프록시 내부(일반적으로) 내부로 래핑됩니다.

8.3. pax-transx 프로젝트 정보
pax-transx
프로젝트는 OSGi의 JTA/JTS 트랜잭션 관리와 JDBC 및 JMS에 대한 리소스 풀링을 지원합니다. pax-jdbc
와 pax-jms
간의 격차를 닫습니다.
-
pax-jdbc
는 구성 옵션 및javax.sql.(XA)ConnectionFactory
서비스에 대한 검색 기능을 추가하고 일부 JDBC 풀링 구현을 제공합니다. -
pax-jms
는javax.jms.(XA)ConnectionFactory
서비스에 대해 동일한 작업을 수행하고 일부 JMS 풀링 구현을 제공합니다. -
pax-transx
는javax. Cryostat.TransactionManager
구현에 대한 구성 옵션 및 검색을 추가하며 (finally) 풀링 및 tranasction 지원을 통해 JCA 기반 JDBC/JMS 연결 관리를 제공합니다.
JDBC 연결 풀 및 JMS 연결 풀에 대한 섹션은 여전히 유효합니다. JCA 기반 풀을 사용하는 데 필요한 유일한 변경 사항은 JDBC 데이터 소스 및 JMS 연결 팩토리를 등록할 때 pool=transx
속성을 사용하는 것입니다.
-
pax-jdbc-pool-transx
는org.ops4j.pax.transx.jdbc.ManagedDataSourceBuilder
에서pax-transx-jdbc
를 사용합니다. -
pax-jms-pool-transx
는org.ops4j.pax.transx.jms.ManagedConnectionFactoryBuilder
에서pax-transx-jms
를 사용합니다.
풀링된 데이터 소스/연결 팩토리는 빌더 스타일 (Java™ans 속성 없음)에서 생성되는 반면, 이러한 속성은 JDBC에서 지원됩니다.
-
name
-
userName
-
암호
-
commitBeforeAutocommit
-
preparedStatementCacheSize
-
transactionIsolationLevel
-
minIdle
-
maxPoolSize
-
aliveBypassWindow
-
houseKeepingPeriod
-
connectionTimeout
-
idleTimeout
-
maxLifetime
이러한 속성은 JMS에서 지원됩니다.
-
name
-
userName
-
암호
-
clientID
-
minIdle
-
maxPoolSize
-
aliveBypassWindow
-
houseKeepingPeriod
-
connectionTimeout
-
idleTimeout
-
maxLifetime
XA 복구를 위해서는 사용자 이름과
암호
속성이 필요합니다( Fuse 6.x의 aries.xa.username
및 aries.xa.password
속성과 마찬가지로).
블루프린트에서 이 JDBC 구성을 사용하여 (mind pool=transx
)
<!-- Database-specific, non-pooling, non-enlisting javax.sql.XADataSource --> <bean id="postgresql" class="org.postgresql.xa.PGXADataSource"> <property name="url" value="jdbc:postgresql://localhost:5432/reportdb" /> <property name="user" value="fuse" /> <property name="password" value="fuse" /> <property name="currentSchema" value="report" /> <property name="connectTimeout" value="5" /> </bean> <!-- Expose database-specific data source with service properties No need to expose pooling, enlisting, non database-specific javax.sql.DataSource - it'll be registered automatically by pax-jdbc-config with the same properties as this <service>, but with higher service.ranking --> <service id="pool" ref="postgresql" interface="javax.sql.XADataSource"> <service-properties> <!-- "pool" key is needed for pax-jdbc-config to wrap database-specific data source inside connection pool --> <entry key="pool" value="transx" /> <!-- <service>/@id attribute doesn't propagate, but name of the datasource is required using one of: --> <entry key="osgi.jndi.service.name" value="jdbc/postgresql" /> <!-- or: --> <!--<entry key="dataSourceName" value="jdbc/postgresql" />--> <!-- Other properties, that normally are needed by e.g., pax-jdbc-pool-transx --> <entry key="pool.maxPoolSize" value="13" /> <entry key="pool.userName" value="fuse" /> <entry key="pool.password" value="fuse" /> </service-properties> </service>
블루프린트의 이 JMS 구성으로 (mind pool=transx
)
<!-- Broker-specific, non-pooling, non-enlisting javax.jms.XAConnectionFactory --> <bean id="artemis" class="org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory"> <argument index="0" value="tcp://localhost:61616" /> <!-- credentials needed for JCA-based XA-recovery --> <argument index="1" value="admin" /> <argument index="2" value="admin" /> <property name="callTimeout" value="2000" /> <property name="initialConnectAttempts" value="3" /> </bean> <!-- Expose broker-specific connection factory with service properties No need to expose pooling, enlisting, non broker-specific javax.jms.XAConnectionFactory - it'll be registered automatically by pax-jms-config with the same properties as this <service>, but with higher service.ranking --> <service id="pool" ref="artemis" interface="javax.jms.XAConnectionFactory"> <service-properties> <!-- "pool" key is needed for pax-jms-config to wrap broker-specific connection factory inside connection pool --> <entry key="pool" value="transx" /> <!-- <service>/@id attribute doesn't propagate, but name of the connection factory is required using one of: --> <entry key="osgi.jndi.service.name" value="jms/artemis" /> <!-- or: --> <!--<entry key="name" value="jms/artemis" />--> <!-- Other properties, that normally are needed e.g., pax-jms-pool-transx --> <entry key="pool.maxPoolSize" value="13" /> <entry key="pool.userName" value="admin" /> <entry key="pool.password" value="admin" /> </service-properties> </service>
JCA 기반 리소스 관리를 활용하는 JDBC 데이터 소스 및 JMS 연결 팩토리가 있습니다. Transx 기반 풀은 XA 복구와 관련하여 pax-transx-tm-narayana
와 적절하게 통합됩니다.
필요한 기능은 다음과 같습니다.
-
pax-jdbc-pool-tranx
-
pax-jms-pool-tranx
-
pax-transx-jdbc
-
pax-transx-jms
-
pax-jms-artemis
(A-MQ 7 사용 시)
9장. 트랜잭션을 사용하는 Camel 애플리케이션 작성
available-to-be-referenced 서비스 유형을 구성한 후 애플리케이션을 작성할 준비가 된 것입니다. 세 가지 유형의 서비스는 다음과 같습니다.
다음 인터페이스 중 하나를 구현하는 트랜잭션 관리자 한 개:
-
javax.transaction.UserTransaction
-
javax.transaction.TransactionManager
-
org.springframework.transaction.PlatformTransactionManager
-
-
javax.sql.DataSource
. 인터페이스를 구현하는 하나 이상의 JDBC 데이터 소스입니다. 종종 둘 이상의 데이터 소스가 있습니다. -
javax.jms.ConnectionFactory
인터페이스를 구현하는 하나 이상의 JMS 연결 팩토리입니다. 종종 하나 이상의 것이 있습니다.
이 섹션에서는 트랜잭션, 데이터 소스 및 연결 팩토리 관리와 관련된 Camel 관련 구성에 대해 설명합니다.
이 섹션에서는 SpringTransactionPolicy
와 같은 여러 가지 Spring 관련 개념에 대해 설명합니다. Camel 컨텍스트를 정의하는 XML 언어인 Spring XML DSL 과 블루프린트 XML DSL 사이에는 명확한 차이점이 있습니다. Spring XML DSL은 Fuse에서 더 이상 사용되지 않습니다. 그러나 Camel 트랜잭션 메커니즘은 내부적으로 Spring 라이브러리를 계속 사용합니다.
여기에 있는 대부분의 정보는 사용되는 PlatformTransactionManager
유형에 의존하지 않습니다. PlatformTransactionManager
가 Narayana 트랜잭션 관리자인 경우 전체 JTA 트랜잭션이 사용됩니다. PlatformTransactionManager
가 로컬 블루프린트 < bean
>로 정의된 경우 (예: org.springframework.jms.connection.JmsTransactionManager
) 로컬 트랜잭션이 사용됩니다.
트랜잭션 분리는 트랜잭션을 시작, 커밋, 롤백하는 절차를 나타냅니다. 이 섹션에서는 프로그래밍 및 구성에 의해 트랜잭션 분리를 제어하는 데 사용할 수 있는 메커니즘에 대해 설명합니다.
9.1. 경로를 표시하여 트랜잭션 분리
Apache Camel은 경로에서 트랜잭션을 시작하는 간단한 메커니즘을 제공합니다. transacted()
명령을 Java DSL에 삽입하거나 XML DSL에 < transacted/
> 태그를 삽입합니다.
그림 9.1. 경로를 표시하여 분리

트랜잭션된 프로세서는 다음과 같이 트랜잭션을 분류합니다.
- 교환이 트랜잭션된 프로세서에 들어가면 트랜잭션된 프로세서는 기본 트랜잭션 관리자를 호출하여 트랜잭션을 시작하고 현재 스레드에 트랜잭션을 연결합니다.
- 교환이 나머지 경로의 끝에 도달하면, 트랜잭션된 프로세서는 트랜잭션 관리자를 호출하여 현재 트랜잭션을 커밋합니다.
9.1.1. JDBC 리소스가 포함된 샘플 경로
그림 9.1. “경로를 표시하여 분리” 경로에 transacted()
DSL 명령을 추가하여 트랜잭션되는 경로의 예를 보여줍니다. transacted()
노드를 따르는 모든 경로 노드는 트랜잭션 범위에 포함됩니다. 이 예에서 다음 두 노드는 JDBC 리소스에 액세스합니다.
9.1.2. Java DSL의 경로 정의
다음 Java DSL 예제에서는 transacted()
DSL 명령으로 경로를 표시하여 트랜잭션 경로를 정의하는 방법을 보여줍니다.
import org.apache.camel.builder.RouteBuilder; class MyRouteBuilder extends RouteBuilder { public void configure() { from("file:src/data?noop=true") .transacted() .bean("accountService","credit") .bean("accountService","debit"); } }
이 예에서 파일 끝점은 한 계정에서 다른 계정으로 수신자 전송을 설명하는 일부 XML 형식 파일을 읽습니다. 첫 번째 Cryostat ()
호출 크레딧은 수혜자의 계정에 지정된 합계를 제공한 다음 두 번째 blank ()
호출에서 지정된 양의 비용을 보낸 사람의 계정에서 뺀 값입니다. 둘 다 useful()
호출을 수행하면 데이터베이스 리소스에 대한 업데이트가 수행됩니다. 데이터베이스 리소스가 트랜잭션 관리자를 통해 트랜잭션에 바인딩되는 것으로 가정합니다(예: 6장. JDBC 데이터 소스 사용 ).
9.1.3. 블루프린트 XML의 경로 정의
이전 경로는 블루프린트 XML로 표시될 수도 있습니다. & lt;transacted /
> 태그는 다음 XML과 같이 경로를 트랜잭션으로 표시합니다.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route> <from uri="file:src/data?noop=true" /> <transacted /> <bean ref="accountService" method="credit" /> <bean ref="accountService" method="debit" /> </route> </camelContext> </blueprint>
9.1.4. 기본 트랜잭션 관리자 및 트랜잭션 정책
트랜잭션을 분리하려면 트랜잭션된 프로세서가 특정 트랜잭션 관리자 인스턴스와 연결되어야 합니다. Transact ed()
를 호출할 때마다 트랜잭션 관리자를 지정해야 합니다. 변환된 프로세서는 합리적인 기본값을 자동으로 선택합니다. 예를 들어 구성에 트랜잭션 관리자 인스턴스가 하나만 있는 경우 거래된 프로세서는 암시적으로 이 트랜잭션 관리자를 선택하여 트랜잭션을 위임합니다.
트랜잭션된 프로세서는 전파 정책 및 트랜잭션 관리자를 캡슐화하는 TransactedPolicy
유형의 트랜잭션 정책으로 구성할 수도 있습니다(자세한 내용은 9.4절. “트랜잭션 전파 정책” 참조). 다음 규칙은 기본 트랜잭션 관리자 또는 트랜잭션 정책을 선택하는 데 사용됩니다.
org.apache.camel.spi.#159edPolicy
유형에 대해 하나의 8080만 있는 경우 이 8080을 사용합니다.참고CryostatedPolicy
유형은 9.4절. “트랜잭션 전파 정책” 에 설명된SpringTransactionPolicy
유형의 기본 유형입니다. 따라서 여기에 언급된 빈은SpringTransactionPolicy
8080이 될 수 있습니다.-
유형의 빈이 있는 경우
org.apache.camel.spi.#159edPolicy
ID
가 ,PROPAGATION_REQUIRED
인 경우 이 Cryostat를 사용합니다. -
org.springframework. Cryostat.PlatformTransactionManager
유형의 Cryostat가 하나뿐인 경우 이 8080을 사용하십시오.
또한 빈 ID를 transacted()
의 인수로 제공하여 8080을 명시적으로 지정하는 옵션도 있습니다. 9.4.4절. “Java DSL의 PROPAGATION_NEVER
정책이 포함된 샘플 경로”을 참조하십시오.
9.1.5. 트랜잭션 범위
트랜잭션 프로세서를 경로에 삽입하면 트랜잭션 관리자는 교환이 이 노드를 통과할 때마다 새 트랜잭션을 생성합니다. 트랜잭션 범위는 다음과 같이 정의됩니다.
- 트랜잭션은 현재 스레드와만 연결됩니다.
- 트랜잭션 범위는 트랜잭션된 프로세서를 따르는 모든 경로 노드를 포함합니다.
트랜잭션된 프로세서 앞에 있는 경로 노드는 트랜잭션에 없습니다. 그러나 경로가 트랜잭션 끝점으로 시작되면 경로의 모든 노드가 트랜잭션에 있습니다. 9.2.5절. “경로 시작 시 트랜잭션 끝점”을 참조하십시오.
다음 경로를 고려하십시오. transacted()
DSL 명령이 데이터베이스 리소스에 액세스하는 첫 번째 8080 () 호출
뒤에 실수로 표시되기 때문에 올바르지 않습니다.
// Java import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { ... public void configure() { from("file:src/data?noop=true") .bean("accountService", "credit") .transacted() // <-- WARNING: Transaction started in the wrong place! .bean("accountService", "debit"); } }
9.1.6. 트랜잭션 경로에 스레드 풀 없음
지정된 트랜잭션이 현재 스레드와만 연결되어 있음을 이해하는 것이 중요합니다. 새 스레드의 처리는 현재 트랜잭션 트랜잭션에 참여하지 않으므로 트랜잭션 경로 중간에 스레드 풀을 만들지 않아야 합니다. 예를 들어 다음 경로는 문제를 유발하도록 바인딩됩니다.
// Java import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { ... public void configure() { from("file:src/data?noop=true") .transacted() .threads(3) // WARNING: Subthreads are not in transaction scope! .bean("accountService", "credit") .bean("accountService", "debit"); } }
이전과 같은 경로는 threads()
DSL 명령이 트랜잭션된 경로와 호환되지 않기 때문에 데이터베이스가 손상될 수 있습니다. threads()
호출이 transacted()
호출보다 우선하더라도 경로가 예상대로 작동하지 않습니다.
9.1.7. 경로를 조각으로 분할
경로를 조각으로 분할하고 각 경로 조각이 현재 트랜잭션에 참여하도록 하려면 직접
엔드포인트를 사용할 수 있습니다. 예를 들어, 전송 양이 큰지(100보다) 작는지(100 미만) 작는지 여부에 따라 라우터 조각을 분리하기 위해 다음과 같이 choice()
DSL 명령 및 직접 끝점을 사용할 수 있습니다.
// Java import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { ... public void configure() { from("file:src/data?noop=true") .transacted() .bean("accountService", "credit") .choice().when(xpath("/transaction/transfer[amount > 100]")) .to("direct:txbig") .otherwise() .to("direct:txsmall"); from("direct:txbig") .bean("accountService", "debit") .bean("accountService", "dumpTable") .to("file:target/messages/big"); from("direct:txsmall") .bean("accountService", "debit") .bean("accountService", "dumpTable") .to("file:target/messages/small"); } }
직접 끝점이 동기이므로 direct:txbig
와 direct:tx
windows로 시작하는 조각과 현재 트랜잭션에 모두 참여합니다. 즉, 조각은 첫 번째 경로 조각과 동일한 스레드에서 실행되므로 동일한 트랜잭션 범위에 포함됩니다.
seda
끝점을 사용하여 경로 조각에 참여해서는 안 됩니다. Seda
소비자 끝점은 경로 조각(동기화 처리)을 실행하기 위한 새 스레드(또는 스레드)를 생성합니다. 따라서 조각은 원래 트랜잭션에 참여하지 않습니다.
9.1.8. 리소스 끝점
다음 Apache Camel 구성 요소는 경로의 대상으로 표시될 때 리소스 끝점 역할을 합니다(예: to()
DSL 명령에 표시되는 경우). 즉, 이러한 끝점은 데이터베이스 또는 영구 큐와 같은 트랜잭션 리소스에 액세스할 수 있습니다. 리소스 끝점은 현재 트랜잭션을 시작한 트랜잭션 프로세서와 동일한 트랜잭션 관리자와 연결된 경우 현재 트랜잭션에 참여할 수 있습니다.
- ActiveMQ
- AMQP
- Hibernate
- iBATIS
- JavaSpace
- JBI
- JCR
- JDBC
- JMS
- JPA
- LDAP
9.1.9. 리소스 끝점이 있는 샘플 경로
다음 예제에서는 리소스 끝점이 있는 경로를 보여줍니다. 이렇게 하면 두 개의 다른 JMS 큐로 금전 전송 순서를 보냅니다. 크레딧
대기열은 주문을 처리하여 수신자의 계정을 계산합니다. 직불 큐는
발신자의 계정을 끌기 위해 주문을 처리합니다. 해당 직불이 있는 경우에만 크레딧이 있어야 합니다. 결과적으로 큐에 있는 작업을 단일 트랜잭션으로 묶어야 합니다. 트랜잭션이 성공하면 신용 주문과 직불 순서가 모두 큐에 추가됩니다. 오류가 발생하면 주문이 큐에 추가되지 않습니다.
from("file:src/data?noop=true") .transacted() .to("jmstx:queue:credits") .to("jmstx:queue:debits");
9.2. 트랜잭션 끝점의 분리
경로 시작 시 소비자 끝점이 리소스에 액세스하면 교환을 폴링한 후 트랜잭션을 시작하기 때문에 transacted()
명령은 사용되지 않습니다. 즉, 트랜잭션은 너무 늦기 때문에 트랜잭션 범위 내에 소비자 끝점을 포함합니다. 이 경우 올바른 접근 방식은 끝점 자체를 트랜잭션 시작을 담당하도록 하는 것입니다. 트랜잭션을 관리할 수 있는 끝점을 트랜잭션 끝점이라고 합니다.

다음과 같이 트랜잭션 끝점의 두 가지 혼동 모델이 있습니다.
일반적인 경우(일반적으로 트랜잭션 끝점에서 트랜잭션은 다음과 같이 트랜잭션을 위임합니다.General case - normally, a transactional endpoint demarcates transactions as follows:
- 교환이 엔드포인트에 도착하거나 끝점이 교환을 성공적으로 폴링하면 끝점은 연결된 트랜잭션 관리자를 호출하여 트랜잭션을 시작합니다.
- 끝점은 새 트랜잭션을 현재 스레드에 연결합니다.
- 교환이 경로 끝에 도달하면 트랜잭션 끝점은 트랜잭션 관리자를 호출하여 현재 트랜잭션을 커밋합니다.
- InOut 교환이 있는 JMS 끝점 - JMS 소비자 끝점이 InOut 교환을 수신하고 이 교환은 다른 JMS 엔드포인트로 라우팅되는 경우 특수 케이스로 처리되어야 합니다. 문제는 경로가 전체 요청/반복을 단일 트랜잭션으로 묶는 경우 교착 상태가 될 수 있다는 것입니다.
9.2.1. JMS 엔드 포인트가 있는 샘플 경로
9.2절. “트랜잭션 끝점의 분리” 경로 시작 시 트랜잭션 엔드포인트가 있는 경로의 예( from()
명령)를 보여줍니다. 모든 경로 노드는 트랜잭션 범위에 포함됩니다. 이 예에서 경로의 모든 엔드포인트는 JMS 리소스에 액세스합니다.
9.2.2. Java DSL의 경로 정의
다음 Java DSL 예제에서는 트랜잭션 끝점으로 경로를 시작하여 트랜잭션 경로를 정의하는 방법을 보여줍니다.
from("jmstx:queue:giro") .to("jmstx:queue:credits") .to("jmstx:queue:debits");
이전 예에서 트랜잭션 범위는 엔드포인트, jmstx:queue:giro
,jmstx:queue:credits
, jmstx:queue:debits
를 포함합니다. 트랜잭션이 성공하면 기프트 큐에서 교환이 영구적으로 제거되고 신용
큐 및 직불
. 트랜잭션이 실패하면 교환이 큐
로 푸시됩니다신용 및 직불 큐에 배치되지 않고 교환이 기가
큐로 다시 푸시 됩니다
. 기본적으로 JMS는 메시지를 자동으로 다시 전달하려고 시도합니다.
jmstx
인 JMS 구성 요소 빈은 다음과 같이 트랜잭션을 사용하도록 명시적으로 구성해야 합니다.
<blueprint ...> <bean id="jmstx" class="org.apache.camel.component.jms.JmsComponent"> <property name="configuration" ref="jmsConfig" /> </bean> <bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration"> <property name="connectionFactory" ref="jmsConnectionFactory" /> <property name="transactionManager" ref="jmsTransactionManager" /> <property name="transacted" value="true" /> </bean> ... </blueprint>
이전 예에서 트랜잭션 관리자 인스턴스 jmsTransactionManager
는 JMS 구성 요소와 연결되고 트랜잭션 된
속성이 true
로 설정되어 InOnly 교환에 대한 트랜잭션 요약을 활성화합니다.
9.2.3. 블루프린트 XML의 경로 정의
앞의 경로는 다음과 같이 블루프린트 XML로 나타낼 수 있습니다.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route> <from uri="jmstx:queue:giro" /> <to uri="jmstx:queue:credits" /> <to uri="jmstx:queue:debits" /> </route> </camelContext> </blueprint>
9.2.4. DSL transacted()
명령이 필요하지 않음
Transacted()
DSL 명령은 트랜잭션 끝점으로 시작하는 경로에 필요하지 않습니다. 그러나 기본 트랜잭션 정책은 PROPAGATION_REQUIRED
( 9.4절. “트랜잭션 전파 정책”참조)라고 가정하면 일반적으로 다음 예제와 같이 Transact ed()
명령을 포함하는 것은 무해합니다.
from("jmstx:queue:giro") .transacted() .to("jmstx:queue:credits") .to("jmstx:queue:debits");
그러나 이 경로는 예기치 않은 방식으로 작동할 수 있습니다(예: 블루프린트 XML에서 기본이 아닌 전파 정책이 있는 single Cryostated Policy
VLAN). 9.1.4절. “기본 트랜잭션 관리자 및 트랜잭션 정책”을 참조하십시오. 따라서 일반적으로 트랜잭션 끝점으로 시작하는 경로에 transacted()
DSL 명령을 포함하지 않는 것이 좋습니다.
9.2.5. 경로 시작 시 트랜잭션 끝점
다음 Apache Camel 구성 요소는 경로 시작 시 표시되는 경우 트랜잭션 끝점 역할을 합니다(예: from()
DSL 명령에 표시되는 경우). 즉, 이러한 끝점은 트랜잭션 클라이언트로 작동하도록 구성할 수 있으며 트랜잭션 리소스에도 액세스할 수 있습니다.
- ActiveMQ
- AMQP
- JavaSpace
- JMS
- JPA
9.3. 선언적 트랜잭션의 분리
블루프린트 XML을 사용할 때 블루프린트 XML 파일에 트랜잭션 정책을 선언하여 트랜잭션을 위임할 수도 있습니다. Required
정책과 같이 빈 또는 8080 메서드에 적절한 트랜잭션 정책을 적용하면 특정 Quarkus 또는 Cryostat 메서드가 호출될 때마다 트랜잭션이 시작되도록 할 수 있습니다. Quarkus 메서드 종료 시 트랜잭션이 커밋됩니다. 이 접근 방식은 Enterprise Java Cryostat에서 트랜잭션이 적용되는 방식과 유사합니다.
OSGi 선언적 트랜잭션을 사용하면 블루프린트 파일의 다음 범위에서 트랜잭션 정책을 정의할 수 있습니다.
9.3.3절. “tx에 대한 설명: Cryostat
속성” 도 참조하십시오.
9.3.1. Cryostat 수준 선언
8080 수준에서 트랜잭션 정책을 선언하려면 다음과 같이 tx:
Cryostat 요소를^2 요소의
자식으로 삽입합니다.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.1.0"> <bean id="accountFoo" class="org.jboss.fuse.example.Account"> <tx:transaction method="*" value="Required" /> <property name="accountName" value="Foo" /> </bean> <bean id="accountBar" class="org.jboss.fuse.example.Account"> <tx:transaction method="*" value="Required" /> <property name="accountName" value="Bar" /> </bean> </blueprint>
이전 예에서 필수 트랜잭션 정책은 accountFoo
콩 및 accountBar
8080의 모든 메서드에 적용됩니다. 여기서 메서드 속성은 모든 Cryostat 메서드를 일치시키기 위해 와일드카드 *
를 지정합니다.
9.3.2. 최상위 수준 선언
최상위 수준에서 트랜잭션 정책을 선언하려면 다음과 같이 tx:
Cryostat 요소를 블루프린트
요소의 자식으로 삽입합니다.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.1.0"> <tx:transaction bean="account*" value="Required" /> <bean id="accountFoo" class="org.jboss.fuse.example.Account"> <property name="accountName" value="Foo" /> </bean> <bean id="accountBar" class="org.jboss.fuse.example.Account"> <property name="accountName" value="Bar" /> </bean> </blueprint>
이전 예에서 Required
트랜잭션 정책은 ID
가 패턴인 account*
와 일치하는 모든 빈의 모든 메서드에 적용됩니다.
9.3.3. tx에 대한 설명: Cryostat
속성
tx: Cryostat
요소는 다음 특성을 지원합니다.
Cryostat
(상위 수준만 해당) 트랜잭션 정책이 적용되는 빈 ID(콤마 또는 공백으로 구분된) 목록을 지정합니다. 예를 들면 다음과 같습니다.
<blueprint ...> <tx:transaction bean="accountFoo,accountBar" value="..." /> </blueprint>
와일드카드 문자
*
를 사용할 수도 있습니다. 이 문자는 각 목록 항목에서 최대 한 번 표시될 수 있습니다. 예를 들면 다음과 같습니다.<blueprint ...> <tx:transaction bean="account*,jms*" value="..." /> </blueprint>
8080 속성을 생략하면 기본값은
*
입니다( 블루프린트 파일의 모든 비-synthetic 빈과 일치).method
(최상 및 빈 수준) 트랜잭션 정책이 적용되는 메서드 이름(콤마 또는 공백으로 구분된) 목록을 지정합니다. 예를 들면 다음과 같습니다.
<bean id="accountFoo" class="org.jboss.fuse.example.Account"> <tx:transaction method="debit,credit,transfer" value="Required" /> <property name="accountName" value="Foo" /> </bean>
와일드카드 문자
*
를 사용할 수도 있습니다. 이 문자는 각 목록 항목에서 최대 한 번 표시될 수 있습니다.메서드 속성을 생략하면 기본값은
*
(해당 빈의 모든 메서드와 일치)입니다.- value
(상위 수준 및 8080 수준) 트랜잭션 정책을 지정합니다. 정책 값은 다음과 같이 EventListener 3.0 사양에 정의된 정책과 동일한 의미가 있습니다.
-
필수
- 현재 트랜잭션을 지원하고, 존재하지 않는 경우 새 트랜잭션을 만듭니다. -
mandatory
- 현재 트랜잭션을 지원합니다. 현재 트랜잭션이 없는 경우 예외가 발생합니다. -
RequiresNew
- 새 트랜잭션을 생성하여 현재 트랜잭션이 있는 경우 일시 중지합니다. -
지원
- 현재 트랜잭션을 지원하며, 존재하지 않는 경우 비- applications를 실행합니다. -
NotSupported
- 현재 트랜잭션을 지원하지 않습니다. 대신 항상 비 applications를 실행합니다. -
never
- 현재 트랜잭션이 있는 경우 예외를 throw합니다.
-
9.4. 트랜잭션 전파 정책
트랜잭션 클라이언트가 새 트랜잭션을 생성하는 방식에 영향을 미치려면 JmsTransactionManager
를 사용하고 트랜잭션 정책을 지정할 수 있습니다. 특히 Spring 트랜잭션 정책을 사용하면 트랜잭션에 대한 전파 동작을 지정할 수 있습니다. 예를 들어 트랜잭션 클라이언트가 새 트랜잭션을 만들고 트랜잭션이 현재 스레드와 이미 연결되어 있음을 감지하는 경우 새 트랜잭션을 만들고 새 트랜잭션을 생성해야 합니까? 아니면 기존 트랜잭션이 적용되도록 해야 합니까? 이러한 종류의 동작은 트랜잭션 정책에 전파 동작을 지정하여 규제됩니다.
트랜잭션 정책은 블루프린트 XML에서 빈으로 인스턴스화됩니다. 그런 다음 tradeact ed()
DSL 명령에 인수로ans ID
를 제공하여 트랜잭션 정책을 참조할 수 있습니다. 예를 들어 동작에 따라 트랜잭션을 시작하려면 PROPAGATION_REQUIRES_NEW
에서는 다음 경로를 사용할 수 있습니다.
from("file:src/data?noop=true") .transacted("PROPAGATION_REQUIRES_NEW") .bean("accountService","credit") .bean("accountService","debit") .to("file:target/messages");
여기서 PROPAGATION_REQUIRES_NEW
인수는 PROPAGATION_REQUIRES_NEW
동작으로 구성된 트랜잭션 정책의 빈 ID
를 지정합니다. 9.4.3절. “블루프린트 XML에서 정책 빈 정의”을 참조하십시오.
9.4.1. Spring 트랜잭션 정책 정보
Apache Camel을 사용하면 org.apache.camel.spring.spi.SpringTransactionPolicy
클래스를 사용하여 Spring 트랜잭션 정책을 정의할 수 있습니다. 이 정책은 기본적으로 네이티브 Spring 클래스와 관련된 래퍼입니다. SpringTransactionPolicy
클래스는 다음 두 가지 데이터를 캡슐화합니다.
-
PlatformTransactionManager
유형의 트랜잭션 관리자에 대한 참조 - 전파 동작
예를 들어 다음과 같이 PROPAGATION_MANDATORY
동작을 사용하여 Spring 트랜잭션 정책 metrics을 인스턴스화할 수 있습니다.
<blueprint ...> <bean id="PROPAGATION_MANDATORY "class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_MANDATORY" /> </bean> ... </blueprint>
9.4.2. 전파 동작 설명
다음 전파 동작은 Spring에서 지원합니다. 이러한 값은 원래 JavaeEE에서 지원하는 전파 동작에 따라 모델링되었습니다.
- PROPAGATION_MANDATORY
- 현재 트랜잭션을 지원합니다. 현재 트랜잭션이 없는 경우 예외를 throw합니다.
- PROPAGATION_NESTED
현재 트랜잭션이 있는 경우 중첩된 트랜잭션 내에서 실행되며
PROPAGATION_REQUIRED
.참고중첩된 트랜잭션은 모든 트랜잭션 관리자가 지원하지 않습니다.
- PROPAGATION_NEVER
- 현재 트랜잭션을 지원하지 않습니다. 현재 트랜잭션이 있는 경우 예외를 throw합니다.
- PROPAGATION_NOT_SUPPORTED
현재 트랜잭션을 지원하지 않습니다. 항상 비-SQL을 실행합니다.
참고이 정책을 사용하려면 모든 트랜잭션 관리자가 지원하지 않는 기능인 현재 트랜잭션을 일시 중단해야 합니다.
- PROPAGATION_REQUIRED
- (기본값) 현재 트랜잭션을 지원합니다. 존재하지 않는 경우 새 항목을 만듭니다.
- PROPAGATION_REQUIRES_NEW
새 트랜잭션을 생성하여 현재 트랜잭션이 있는 경우 일시 중지합니다.
참고트랜잭션 일시 중단은 모든 트랜잭션 관리자가 지원하지 않습니다.
- PROPAGATION_SUPPORTS
- 현재 트랜잭션을 지원합니다. 존재하지 않는 경우 기본적으로 실행합니다.
9.4.3. 블루프린트 XML에서 정책 빈 정의
다음 예제에서는 지원되는 모든 전파 동작에 대해 트랜잭션 정책 빈을 정의하는 방법을 보여줍니다. 편의를 위해 각 빈 ID는 전파 동작 값의 지정된 값과 일치하지만 실제로는 빈 ID에 원하는 값을 사용할 수 있습니다.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <bean id="PROPAGATION_MANDATORY " class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_MANDATORY" /> </bean> <bean id="PROPAGATION_NESTED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_NESTED" /> </bean> <bean id="PROPAGATION_NEVER" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_NEVER" /> </bean> <bean id="PROPAGATION_NOT_SUPPORTED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_NOT_SUPPORTED" /> </bean> <!-- This is the default behavior. --> <bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> </bean> <bean id="PROPAGATION_REQUIRES_NEW" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW" /> </bean> <bean id="PROPAGATION_SUPPORTS" class="org.apache.camel.spring.spi.SpringTransactionPolicy"> <property name="transactionManager" ref="txManager" /> <property name="propagationBehaviorName" value="PROPAGATION_SUPPORTS" /> </bean> </blueprint>
이러한 Quarkus 정의를 자체 블루프린트 XML 구성에 붙여넣려면 트랜잭션 관리자에 대한 참조를 사용자 지정해야 합니다. 즉, txManager
에 대한 참조를 트랜잭션 관리자 metrics의 실제 ID
로 바꿉니다.
9.4.4. Java DSL의 PROPAGATION_NEVER
정책이 포함된 샘플 경로
트랜잭션 정책이 트랜잭션에 영향을 미치는 간단한 방법은 다음 경로에 표시된 것처럼 기존 트랜잭션 중간에 PROPAGATION_NEVER
정책을 삽입하는 것입니다.
from("file:src/data?noop=true") .transacted() .bean("accountService","credit") .transacted("PROPAGATION_NEVER") .bean("accountService","debit");
이러한 방식으로 사용되는 PROPAGATION_NEVER
정책은 모든 트랜잭션을 필연적으로 중단하여 트랜잭션 롤백을 생성합니다. 애플리케이션에 미치는 영향을 쉽게 확인할 수 있습니다.
Transact ed()
에 전달된 문자열 값은 전파 동작 이름이 아니라 빈 ID
입니다. 이 예에서 빈 ID
는 전파 동작 이름과 동일하게 선택되지만 항상 그런 것은 아닙니다. 예를 들어 애플리케이션이 두 개 이상의 트랜잭션 관리자를 사용하는 경우 특정 전파 동작이 있는 정책VLAN을 두 개 이상 사용할 수 있습니다. 이 경우 전파 동작 후 빈의 이름을 지정할 수 없었습니다.
9.4.5. 블루프린트 XML에서 PROPAGATION_NEVER
정책이 포함된 샘플 경로
이전 경로는 블루프린트 XML에서 다음과 같이 정의할 수 있습니다.
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route> <from uri="file:src/data?noop=true" /> <transacted /> <bean ref="accountService" method="credit" /> <transacted ref="PROPAGATION_NEVER" /> <bean ref="accountService" method="debit" /> </route> </camelContext> </blueprint>
9.5. 오류 처리 및 롤백
트랜잭션 경로에서 표준 Apache Camel 오류 처리 기술을 사용할 수 있지만 예외와 트랜잭션 요약 간의 상호 작용을 이해하는 것이 중요합니다. 특히 throw된 예외로 인해 일반적으로 트랜잭션 롤백이 발생하는 것을 고려해야 합니다. 다음 항목을 참조하십시오.
9.5.1. 트랜잭션을 롤백하는 방법
다음 방법 중 하나를 사용하여 트랜잭션을 롤백할 수 있습니다.
9.5.1.1. 런타임 예외를 사용하여 롤백 트리거
Spring 트랜잭션을 롤백하는 가장 일반적인 방법은 런타임(확인되지 않음) 예외를 throw하는 것입니다. 즉, 예외는 java.lang.RuntimeException
의 인스턴스 또는 하위 클래스입니다. java.lang.Error
유형의 Java 오류도 트랜잭션 롤백을 트리거합니다. 반면 검사된 예외는 롤백을 트리거하지 않습니다.
다음 그림은 Java 오류 및 예외가 트랜잭션에 미치는 영향을 요약한 것으로, 롤백을 트리거하는 클래스는 회색으로 표시됩니다.

Spring 프레임워크는 롤백을 트리거하거나 트리거하지 않아야 하는 예외를 지정할 수 있는 XML 주석 시스템도 제공합니다. 자세한 내용은 Spring Reference Guide의 "Rolling back"를 참조하십시오.
트랜잭션 내에서 런타임 예외가 처리되는 경우, 즉 예외가 트랜잭션 분리를 수행하는 코드로 대체될 가능성이 있기 전에 트랜잭션이 롤백되지 않습니다. 자세한 내용은 9.5.2절. “dead letter queue를 정의하는 방법”의 내용을 참조하십시오.
9.5.1.2. rollback()
DSL 명령 사용
트랜잭션된 경로의 중간에서 롤백을 트리거하려면 org.apache.camel.RollbackExchangeException
예외를 throw하는 rollback()
DSL 명령을 호출하여 이 작업을 수행할 수 있습니다. 즉, rollback()
명령은 런타임 예외를 발생시켜 롤백을 트리거하는 표준 접근 방식을 사용합니다.
예를 들어 계정 서비스 애플리케이션에서 수익 이전 크기에 대한 절대 제한이 있어야 한다고 가정합니다. 다음 예제의 코드를 사용하여 양이 100을 초과하면 롤백을 트리거할 수 있습니다.
from("file:src/data?noop=true") .transacted() .bean("accountService","credit") .choice().when(xpath("/transaction/transfer[amount > 100]")) .rollback() .otherwise() .to("direct:txsmall"); from("direct:txsmall") .bean("accountService","debit") .bean("accountService","dumpTable") .to("file:target/messages/small");
이전 경로에서 롤백을 트리거하면 무한 루프에 갇히게 됩니다. 그 이유는 rollback()
에서 throw한 RollbackExchangeException
예외가 경로 시작 시 파일
끝점으로 다시 전파되기 때문입니다. File 구성 요소에는 예외가 throw된 모든 교환을 다시 보낼 수 있는 기본 제공 안정성 기능이 있습니다. 물론 다시 전송하면 교환이 다른 롤백을 트리거하여 무한 루프가 발생합니다. 다음 예제에서는 무한 루프를 방지하는 방법을 보여줍니다.
9.5.1.3. markRollbackOnly()
DSL 명령 사용
markRollbackOnly()
DSL 명령을 사용하면 예외를 발생하지 않고 현재 트랜잭션이 롤백되도록 할 수 있습니다. 이 기능은 예외에 9.5.1.2절. “rollback()
DSL 명령 사용” 의 예와 같이 원하지 않는 부작용을 발생시킬 때 유용할 수 있습니다.
다음 예제에서는 rollback()
명령을 markRollbackOnly()
명령으로 교체하여 9.5.1.2절. “rollback()
DSL 명령 사용” 의 예제를 수정하는 방법을 보여줍니다. 이 버전의 경로는 무한 루프의 문제를 해결합니다. 이 경우 수익 이전 양이 100을 초과하면 현재 트랜잭션이 롤백되지만 예외는 발생하지 않습니다. 파일 끝점에서 예외를 수신하지 않으므로 교환을 재시도하지 않고 실패한 트랜잭션이 자동으로 삭제됩니다.
다음 코드는 markRollbackOnly()
명령을 사용하여 예외를 롤백합니다.
from("file:src/data?noop=true") .transacted() .bean("accountService","credit") .choice().when(xpath("/transaction/transfer[amount > 100]")) .markRollbackOnly() .otherwise() .to("direct:txsmall"); ...
그러나 앞의 경로 구현에는 적합하지 않습니다. 경로가 트랜잭션을 깔끔하게 롤백하고 일관된 상태의 데이터베이스를 그대로 롤백하고 무한 루프 처리 문제를 방지하지만 실패한 트랜잭션에 대한 레코드를 유지하지 않습니다. 실제 애플리케이션에서는 일반적으로 실패한 트랜잭션을 추적하려고 합니다. 예를 들어 트랜잭션이 성공하지 못한 이유를 설명하기 위해 관련 고객에게 문자를 작성하고자 할 수 있습니다. 실패한 트랜잭션을 추적하는 편리한 방법은 경로에 dead-letter queue를 추가하는 것입니다.
9.5.2. dead letter queue를 정의하는 방법
실패한 트랜잭션을 추적하기 위해 관련 교환 개체를 dead-letter queue로 전환할 수 있는 onException()
절을 정의할 수 있습니다. 그러나 트랜잭션 컨텍스트에서 사용하는 경우 예외 처리와 트랜잭션 처리 간의 잠재적인 상호 작용으로 인해 onException()
절을 정의하는 방법에 대해 주의해야 합니다. 다음 예제에서는 rethrown 예외를 억제해야 한다고 가정하면 onException()
절을 정의하는 올바른 방법을 보여줍니다.
// Java import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { ... public void configure() { onException(IllegalArgumentException.class) .maximumRedeliveries(1) .handled(true) .to("file:target/messages?fileName=deadLetters.xml&fileExist=Append") .markRollbackOnly(); // NB: Must come *after* the dead letter endpoint. from("file:src/data?noop=true") .transacted() .bean("accountService","credit") .bean("accountService","debit") .bean("accountService","dumpTable") .to("file:target/messages"); } }
이전 예에서 onException()
은 IllegalArgumentException
예외를 catch하고 잘못된 교환을 dead letter file dead letter file, deadLet Cryostat.xml
로 전송하도록 구성되어 있습니다. 물론 이 정의를 변경하여 애플리케이션에서 발생하는 모든 종류의 예외를 파악할 수 있습니다. 예외 다시 화살표 동작 및 트랜잭션 롤백 동작은 onException()
절의 다음과 같은 특수 설정으로 제어됩니다.
-
handled(true)
- rethrown 예외를 비활성화합니다. 이 특정 예에서 rethrown 예외는 파일 엔드포인트로 다시 전파될 때 무한 루프를 트리거하기 때문에 바람직하지 않습니다. 9.5.1.3절. “markRollbackOnly()
DSL 명령 사용”을 참조하십시오. 그러나 경로 시작 시 끝점이 재시도 기능을 구현하지 않는 경우 예외를 다시 시작하는 것이 허용되는 경우도 있습니다. -
markRollbackOnly()
- 예외를 throw하지 않고 롤백의 현재 트랜잭션을 표시합니다. 교환을 dead letter queue로 라우팅하는to()
명령 뒤에 이 DSL 명령을 삽입하는 것이 중요합니다. 그렇지 않으면markRollbackOnly()
가 처리 체인을 중단하기 때문에 교환은 dead letter 큐에 도달하지 않습니다.
9.5.3. 트랜잭션 관련 예외 처리
onException()
을 사용하는 대신 트랜잭션 경로에서 예외를 처리하는 간단한 방법은 경로 주위에 doTry()
및 doCatch()
절을 사용하는 것입니다. 예를 들어 다음 코드는 무한 루프에 갇혀 있을 위험 없이 트랜잭션 경로에서 IllegalArgumentException
을 catch하고 처리하는 방법을 보여줍니다.
// Java import org.apache.camel.builder.RouteBuilder; public class MyRouteBuilder extends RouteBuilder { ... public void configure() { from("file:src/data?noop=true") .doTry() .to("direct:split") .doCatch(IllegalArgumentException.class) .to("file:target/messages?fileName=deadLetters.xml&fileExist=Append") .end(); from("direct:split") .transacted() .bean("accountService","credit") .bean("accountService","debit") .bean("accountService","dumpTable") .to("file:target/messages"); } }
이 예에서 경로는 두 세그먼트로 나뉩니다. 첫 번째 세그먼트( 파일:src/data
끝점)는 들어오는 교환을 수신하고 doTry()
및 doCatch()
를 사용하여 예외 처리를 수행합니다. 두 번째 세그먼트( 직접:split
끝점)는 모든 트랜잭션 작업을 수행합니다. 이 트랜잭션 세그먼트 내에서 예외가 발생하면 먼저 transacted()
명령으로 전파되므로 현재 트랜잭션이 롤백되고 첫 번째 경로 세그먼트의 doCatch()
절에 의해 catch됩니다. doCatch()
절은 예외를 다시 가져오지 않으므로 파일 끝점에서 재시도를 수행하지 않고 무한 루프를 방지할 수 있습니다.