공식문서로 트랜잭션을 배워볼까요?
이번글은 공식 문서에서 소개하는 Transaction Management에 대해 정리했습니다.
범위 : Declarative Transaction Management(Advising Transactional Operations ~Using @Transactional with AspectJ)
Advising Transactional Operations
트랜잭션 작업에 어드바이스 적용
Suppose you want to run both transactional operations and some basic profiling advice. How do you effect this in the context of <tx:annotation-driven/>?
만약 트랜잭션 작업과 몇 가지 기본적인 프로파일링 어드바이스를 모두 실행하고자 한다면, tx:annotation-driven/의 문맥에서 이를 어떻게 구현합니까?
When you invoke the updateFoo(Foo) method, you want to see the following actions:
- The configured profiling aspect starts.
- The transactional advice runs.
- The method on the advised object runs.
- The transaction commits.
- The profiling aspect reports the exact duration of the whole transactional method invocation.
updateFoo(Foo) 메서드를 호출하면, 다음과 같은 작업들이 수행되길 원합니다:
- 구성된 프로파일링 어스펙트가 시작됩니다.
- 트랜잭션 어드바이스가 실행됩니다.
- 어드바이스된 객체의 메서드가 실행됩니다.
- 트랜잭션이 커밋됩니다.
- 프로파일링 어스펙트가 전체 트랜잭션 메서드 호출의 정확한 지속 시간을 보고합니다.
프로파일링 어스펙트란?
프로파일링 어스펙트는 AOP(관점 지향 프로그래밍)를 이용해, 특정 메서드의 실행 시간을 측정하거나 호출 횟수를 기록하는 등 성능 정보를 수집하는 역할을 하는 모듈입니다.
즉, 코드의 핵심 로직에 손대지 않고도, 별도의 감시자(어스펙트)를 통해 성능 데이터를 자동으로 측정하고 보고해주는 도구라고 할 수 있습니다.
The following code shows the simple profiling aspect discussed earlier:
아래 코드는 앞서 논의된 간단한 프로파일링 어스펙트를 보여줍니다:
package x.y;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.core.Ordered;
public class SimpleProfiler implements Ordered {
private int order;
// allows us to control the ordering of advice
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
// this method is the around advice
public Object profile(ProceedingJoinPoint call) throws Throwable {
Object returnValue;
StopWatch clock = new StopWatch(getClass().getName());
try {
clock.start(call.toShortString());
returnValue = call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
return returnValue;
}
}
The ordering of advice is controlled through the Ordered interface. For full details on advice ordering, see Advice ordering.
어드바이스의 순서는 Ordered 인터페이스를 통해 제어됩니다. 어드바이스 순서에 대한 자세한 내용은 Advice ordering을 참조하세요.
The following configuration creates a fooService bean that has profiling and transactional aspects applied to it in the desired order:
다음 구성은 원하는 순서로 프로파일링과 트랜잭션 어스펙트가 적용된 fooService 빈을 생성합니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- this is the aspect -->
<bean id="profiler" class="x.y.SimpleProfiler">
<!-- run before the transactional advice (hence the lower order number) -->
<property name="order" value="1"/>
</bean>
<tx:annotation-driven transaction-manager="txManager" order="200"/>
<aop:config>
<!-- this advice runs around the transactional advice -->
<aop:aspect id="profilingAspect" ref="profiler">
<aop:pointcut id="serviceMethodWithReturnValue"
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
</aop:aspect>
</aop:config>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
You can configure any number of additional aspects in similar fashion.
유사한 방식으로 추가적인 어스펙트를 원하는 만큼 구성할 수 있습니다.
The following example creates the same setup as the previous two examples but uses the purely XML declarative approach:
다음 예제는 앞의 두 예제와 동일한 구성을 생성하지만 순수한 XML 선언적 방식을 사용합니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- the profiling advice -->
<bean id="profiler" class="x.y.SimpleProfiler">
<!-- run before the transactional advice (hence the lower order number) -->
<property name="order" value="1"/>
</bean>
<aop:config>
<aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>
<!-- runs after the profiling advice (cf. the order attribute) -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="entryPointMethod" order="2"/>
<!-- order value is higher than the profiling aspect -->
<aop:aspect id="profilingAspect" ref="profiler">
<aop:pointcut id="serviceMethodWithReturnValue"
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>
</aop:aspect>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- other <bean/> definitions such as a DataSource and a TransactionManager here -->
</beans>
The result of the preceding configuration is a fooService bean that has profiling and transactional aspects applied to it in that order. If you want the profiling advice to run after the transactional advice on the way in and before the transactional advice on the way out, you can swap the value of the profiling aspect bean’s order property so that it is higher than the transactional advice’s order value.
앞서 구성한 설정의 결과는 fooService 빈에 프로파일링과 트랜잭션 어스펙트가 해당 순서대로 적용된 것입니다. 만약 진입 시에는 트랜잭션 어드바이스 이후에, 종료 시에는 트랜잭션 어드바이스 이전에 프로파일링 어드바이스가 실행되길 원한다면, 프로파일링 어스펙트 빈의 order 속성 값을 트랜잭션 어드바이스의 order 값보다 높게 변경할 수 있습니다
이 말은 AOP 어드바이스의 실행 순서를 조정하는 방법을 설명하는 것입니다.
현재 설정에서는 fooService 빈에 두 가지 어드바이스—프로파일링과 트랜잭션—가 적용되며, order 값에 따라 실행 순서가 결정됩니다. 예를 들어, 프로파일링 어드바이스의 order 값이 트랜잭션 어드바이스보다 낮다면(숫자가 작으면 먼저 실행됨), 메서드 호출 시 프로파일링 어드바이스가 먼저 실행되고 그 다음에 트랜잭션 어드바이스가 실행됩니다.
만약 메서드 실행 전에는 트랜잭션 어드바이스가 먼저 실행되고, 메서드 실행 후에는 트랜잭션 어드바이스가 끝나기 전에 프로파일링 어드바이스가 실행되길 원한다면, 프로파일링 어드바이스의 order 값을 트랜잭션 어드바이스의 order 값보다 높게 설정하면 됩니다. 즉, order 값이 높으면 해당 어드바이스는 실행 순서 상에서 뒤쪽으로 밀리게 됩니다.
간단히 말하면, order 속성의 값만 조정해서 두 어드바이스가 언제 실행될지를 바꿀 수 있다는 의미입니다.
Advising Transactional Operations 핵심 요약
- 어드바이스의 실행 순서는 Ordered 인터페이스의 order 속성으로 제어됩니다. 숫자가 낮은 값일수록 먼저 실행됩니다.
- 기본 구성에서는 프로파일링 어드바이스의 order 값이 낮아서, 메서드 호출 시 프로파일링이 먼저 시작되고 그 다음에 트랜잭션 어드바이스가 실행됩니다.
- 만약 메서드 실행 진입 시에는 트랜잭션 어드바이스가 먼저 실행되고, 종료 시에는 트랜잭션 어드바이스의 실행이 끝나기 전에 프로파일링 어드바이스가 실행되도록 순서를 변경하고 싶다면, 프로파일링 어드바이스의 order 값을 트랜잭션 어드바이스의 order 값보다 높게 설정하면 됩니다.
한줄 요약
어드바이스의 실행 순서는 Ordered 인터페이스의 order 값에 따라 결정되며, 낮은 값이 먼저 실행되므로 원하는 순서에 맞게 각 어드바이스의 order 값을 조정하면 됩니다.
Using @Transactional with AspectJ
AspectJ와 함께 @Transactional 사용하기
You can also use the Spring Framework’s @Transactional support outside of a Spring container by means of an AspectJ aspect. To do so, first annotate your classes (and optionally your classes' methods) with the @Transactional annotation, and then link (weave) your application with the org.springframework.transaction.aspectj.AnnotationTransactionAspect defined in the spring-aspects.jar file. You must also configure the aspect with a transaction manager. You can use the Spring Framework’s IoC container to take care of dependency-injecting the aspect. The simplest way to configure the transaction management aspect is to use the <tx:annotation-driven/> element and specify the mode attribute to aspectj as described in Using @Transactional. Because we focus here on applications that run outside of a Spring container, we show you how to do it programmatically.
Spring Framework의 @Transactional 지원은 AspectJ 어스펙트를 통해 Spring 컨테이너 외부에서도 사용할 수 있습니다. 이렇게 하려면, 먼저 클래스(그리고 선택적으로 클래스의 메서드들)에 @Transactional 어노테이션을 지정하고, 그런 다음 spring-aspects.jar 파일에 정의된 org.springframework.transaction.aspectj.AnnotationTransactionAspect와 애플리케이션을 링크(위빙)합니다.
또한, 어스펙트를 트랜잭션 관리자와 함께 구성해야 합니다. 스프링 프레임워크의 IoC 컨테이너를 사용하여 어스펙트의 의존성 주입을 처리할 수 있습니다. 트랜잭션 관리 어스펙트를 구성하는 가장 간단한 방법은 tx:annotation-driven/ 요소를 사용하고, Using @Transactional에 설명된 대로 mode 속성을 aspectj로 지정하는 것입니다. 여기서는 Spring 컨테이너 외부에서 실행되는 애플리케이션에 초점을 맞추었으므로, 이를 프로그래밍 방식으로 수행하는 방법을 보여줍니다.
Spring의 @Transactional 기능을 AspectJ 어스펙트를 통해 Spring 컨테이너 없이도 사용할 수 있는 방법을 설명합니다. 즉, 트랜잭션 처리가 필요한 클래스나 메서드에 @Transactional 어노테이션을 붙이고, spring-aspects.jar에 포함된 AnnotationTransactionAspect를 애플리케이션과 연결(위빙)합니다. 이때 어스펙트가 제대로 동작하려면 트랜잭션 관리자를 설정해 주어야 하는데, 보통은 Spring IoC 컨테이너가 의존성 주입을 처리하지만, 여기서는 컨테이너 없이 프로그래밍 방식으로 설정하는 방법을 다루고 있습니다.
The following example shows how to create a transaction manager and configure the AnnotationTransactionAspect to use it:
다음 예제는 트랜잭션 관리자를 생성하고, AnnotationTransactionAspect가 이를 사용하도록 구성하는 방법을 보여줍니다.
// construct an appropriate transaction manager
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());
// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);
When you use this aspect, you must annotate the implementation class (or the methods within that class or both), not the interface (if any) that the class implements. AspectJ follows Java’s rule that annotations on interfaces are not inherited.
이 어스펙트를 사용할 때는, 클래스가 구현하는 인터페이스(있는 경우)가 아니라 구현 클래스(또는 그 클래스 내의 메서드, 혹은 둘 다)에 어노테이션을 추가해야 합니다. AspectJ는 인터페이스에 있는 어노테이션이 상속되지 않는다는 Java의 규칙을 따릅니다.
The @Transactional annotation on a class specifies the default transaction semantics for the execution of any public method in the class.
클래스에 있는 @Transactional 어노테이션은 해당 클래스 내의 모든 public 메서드 실행에 대한 기본 트랜잭션 의미론을 지정합니다.
The @Transactional annotation on a method within the class overrides the default transaction semantics given by the class annotation (if present). You can annotate any method, regardless of visibility.
클래스 내의 메서드에 있는 @Transactional 어노테이션은 (존재하는 경우) 클래스 어노테이션이 제공하는 기본 트랜잭션 의미론을 재정의합니다. 가시성과 관계없이 모든 메서드에 어노테이션을 붙일 수 있습니다.
To weave your applications with the AnnotationTransactionAspect, you must either build your application with AspectJ (see the AspectJ Development Guide) or use load-time weaving. See Load-time weaving with AspectJ in the Spring Framework for a discussion of load-time weaving with AspectJ.
AnnotationTransactionAspect로 애플리케이션을 위빙하려면, AspectJ로 애플리케이션을 빌드하거나(AspectJ Development Guide를 참조) 또는 로드 타임 위빙을 사용해야 합니다. AspectJ를 사용한 로드 타임 위빙에 대한 논의는 Spring Framework의 'Load-time weaving with AspectJ'를 참조하십시오.
"위빙(weaving)"은 AOP(관점 지향 프로그래밍)에서 어드바이스와 포인트컷 같은 어스펙트를 애플리케이션의 핵심 코드에 통합하는 과정을 의미합니다. 즉, 별도로 정의된 부가 기능(예: 트랜잭션 관리)을 애플리케이션 코드의 적절한 위치에 자동으로 삽입
하여, 코드 수정 없이도 해당 기능이 실행되도록 만드는 작업입니다.
Using @Transactional with AspectJ 핵심 요약
- Spring의 @Transactional 기능은 AspectJ 어스펙트를 사용하여 Spring 컨테이너 없이도 사용할 수 있습니다.
- 트랜잭션 처리가 필요한 클래스나 메서드에 @Transactional 어노테이션을 붙입니다. 단, 인터페이스에는 어노테이션이 상속되지 않으므로 구현 클래스나 그 메서드에 적용해야 합니다.
- spring-aspects.jar에 포함된 AnnotationTransactionAspect를 애플리케이션과 위빙하여 트랜잭션 어드바이스를 적용합니다.
- 어스펙트가 올바르게 동작하려면 트랜잭션 관리자를 생성한 후, AnnotationTransactionAspect에 설정해 주어야 합니다. (예: DataSourceTransactionManager 사용)
- 클래스에 @Transactional 어노테이션을 붙이면 클래스 내 모든 public 메서드에 대한 기본 트랜잭션 의미론이 지정되며, 메서드에 붙이면 클래스 설정을 재정의할 수 있습니다.
- AspectJ를 이용하여 어스펙트를 애플리케이션 코드에 통합하는 과정을 위빙이라고 하며, 이를 위해 AspectJ로 애플리케이션을 빌드하거나 로드 타임 위빙을 사용합니다.
한줄 요약
AspectJ를 사용하면 @Transactional 어노테이션 기반의 트랜잭션 관리를 스프링 컨테이너 외부에서도 자동으로 구현할 수 있습니다.
'공식문서' 카테고리의 다른 글
[Spring Docs] Transaction Managment #5 (0) | 2025.03.21 |
---|---|
[Spring Docs] Programmatic Transaction Management #4 (0) | 2025.03.20 |
[Spring Docs] Transaction Management #2 (0) | 2025.03.18 |
[Spring Docs] DispatcherServlet #3 (0) | 2025.03.17 |
Garbage Collector #2 (0) | 2025.03.17 |