AOP는 IoC/DI, 서비스 추상화와 더불어 스프링의 3대 기반기술중 하나다.
AOP는 스프링의 기술 중에서 가장 이해하기 힘든 난해한 용어와 개념을 가진 기술로 악명이 높다.
AOP를 바르게 이용하려면 OOP를 대체하려고 하는 것처럼 보이는 AOP라는 이름 뒤에 감춰진, 그 필연적인 등장배경과 스프링이 그것을 도입한 이유, 그 적용을 통해 얻을 수 있는 장점이 무엇인지에 대한 충분한 이해가 필요하다.
스프링에 적용된 가장 인기 있는 AOP의 적용 대상은 바로 선언적 트랜잭션 기능이다. 서비스 추상화를 통해 많은 근본적인 문제를 해결했던 트랜잭션 경계설정 기능을 AOP를 이용해 더욱 세련되고 깔끔한 방식으로 바꿔보자.
트랜잭션 코드의 분리
스프링이 제공하는 깔끔한 트랜잭션 인터페스를 썻음에도 비즈니스 로직이 주인이어여 할 메소드 안에 이름도 길고 무시무시하게 생긴 트랜잭션 코드가 더 많은 자리를 차지하고 있는 모습이 못마땅 하다.
메소드 분리
public void upgradeLevels() throws Exception {
TransactionStatus status = this.transactionManager .getTransaction(new DefaultTransactionDefinition()); // 트랜잭션 경계설정 시작
try {
upgradeLevelsInternal(); // 비즈니스 로직
this.transactionManager.commit(status); // 트랜잭션 경계설정 종료
} catch (Exception e) {
this.transactionManager.rollback(status);
throw e;
}
}
public void upgradeLevelsInterval() {
List<User> users = userDao.getAll();
for (User user : users) {
if (canUpgradeLevel(user)) {
upgradeLevel(user);
}
}
}
Java
복사
•
두 가지의 코드가 분리되어 있음을 알 수 있다.
•
비즈니스 로직을 사이에 두고 트랜잭션의 시작과 종료를 담당하는 코드가 앞 뒤에 있다.
•
트랜잭션 경계설정의 코드와 비즈니스 로직 코드 간에 서로 주고받는 정보가 없다.
•
따라서 두 코드는 성격이 다르고, 완전히 독립적인 코드다.
DI를 이용한 클래스의 분리
•
비즈니스 로직을 담당하는 코드는 깔끔하게 분리되어 보기 좋긴 하다.
•
하지만 여전히 트랜잭션을 담당하는 기술적 코드가 UserService 안에 자리잡고 있다.
•
간단하게 트랜잭션 코드를 밖으로 뽑아내면 된다.
DI 적용을 이용한 트랜잭션 분리
•
ㅇㅇ
프록시
프록시와 프록시 패턴, 데코레이터 패턴
•
단순히 확장성을 고려해서 한 가지 기능을 분리한다면 전형적인 전략 패턴을 사용하면 된다.
•
트랜잭션 기능에는 추상화 작업을 통해 이미 전략 패턴이 적용되어 있다.
◦
데코리에터 패턴
•
데코레이터 패턴은 타깃에 부가적인 기능을 런타임 시에 다이내믹하게 부여해주기 위해 프록시를 사용하는 패턴을 말한다.
•
다이내믹하게 기능을 부여한다는 의미는 컴파일 시점, 즉 코드상에서는 어떤 방법과 순서로 프록시와 타깃이 연결되어 사용되는지 정해져 있지 않다는 뜻이다.
•
데코레이터 패턴에서는 프록시가 꼭 한 개로 제한되지 않는다. 데코레이터 패턴에서는 같은 인터페이스를 구현한 타겟과 여러 개의 프록시를 사용할 수 있다.