배경
오늘도 어김없이 private 메서드에 @Transactional 애너테이션을 적용했는데 오늘따라 SonarLint가 눈에 띄었다.
@Transactional
private void createRoles(Member member) {
List<String> roles = authorityUtils.createRoles(member.getEmail());
if (roles.isEmpty()) {
throw new BusinessLogicException(ExceptionCode.MEMBER_ROLE_DOES_NOT_EXISTS);
}
member.setRoles(roles);
}
Non-public methods should not be "@Transactional"
Bug
Major
java:S2230
Marking a non-public method @Transactional is both useless and misleading because Spring doesn’t "see" non-public methods, and so makes no provision for their proper invocation. Nor does Spring make provision for the methods invoked by the method it called.
Therefore marking a private method, for instance, @Transactional can only result in a runtime error or exception if the method is actually written to be @Transactional.
Noncompliant Code Example
@Transactional // Noncompliant
private void doTheThing(ArgClass arg) {
// ...
}
해석해 보면 Spring은 private 메서드를 인식하지 않고 적절한 호출을 하지 않기 때문에 @Transactional 애너테이션을 적용하는 것은 권장하지 않는다고 한다.
Why?
@Transactional 애너테이션은 private 메서드에 적용할 수 없다. 그 이유는 AOP가 프로시 패턴을 사용하기 때문이다.
Spring은 AOP를 사용해서 @Transactional 애너테이션을 처리하고, 이 과정에서 동적으로 프록시 객체를 생성한다. 생성된 프록시 객체는 원래의 Bean 객체를 대신해서 호출된다.
private 메서드나 private 필드는 해당 클래스에서만 접근 가능하기 때문에 외부에서 접근해서 프록시 객체를 생성할 수 없게 되는 것이다. 그래서 @Transactional 애너테이션을 가지고 있는 private 메서드에 접근하려고 해도 프록시 객체를 생성할 수 없기 때문에 해당 애너테이션을 무시하게 된다.
하지만 @Transactional 애너테이션이 적용된 public 메서드에서 private 메서드가를 호출하면 해당 private 메서드에도 Transaction이 적용된다.
@Service
@RequiredArgsConstructor
public class ExampleService {
private final ExampleRepository exampleRepository;
@Transactional
public void publicMethod() {
...
privateMethod();
...
}
private void privateMethod() {
...
exampleRepository.save(example);
...
}
}
@Transactional
Spring에서 @Transactional 애너테이션은 메서드 호출 시 트랜잭션을 적용해 준다. 해당 메서드 실행 도중 예외가 발생하면 그동안 수행되었던 작업을 롤백해 준다. @Transactional 애너테이션을 사용해서 리소스를 안전하게 처리할 수 있다.
AOP(Aspect-Oriented Programming)
AOP는 객체 지향 프로그래밍을 보완하기 위한 프로그래밍 기법이다. AOP의 핵심은 관심사를 분리하는 것이다. 공통으로 사용되는 기능(로깅, 보안, 트랜잭션, 캐싱 등)을 모듈화하고 캡슐화해서 핵심 비즈니스 로직과 분리시킨다.
마무리
- private 메서드에는 @Transactional 애너테이션이 적용되지 않는다.
- @Transactional 애너테이션이 적용된 publica 메서드가 호출한 private 메서드에는 Transaction이 적용된다.
'Why?' 카테고리의 다른 글
Java - clazz 변수명은 왜 사용할까? (3) | 2024.11.01 |
---|---|
Java - @Override는 왜 사용할까? (0) | 2023.05.10 |