티스토리 뷰
반응형
스프링 AOP: 프록시 기반 AOP
스프링 AOP 특징
- 프록시 기반의 AOP 구현체이다.
- 스프링 Bean에만 AOP를 적용할 수 있다.
- 모든 AOP의 기능을 제공하는 것이 목적이 아니라, 스프링 IoC와 엔터프라이즈 애플리케이션에서 가장 흔한 문제에 대한 해결책을 제공하는 것이 목적이다.
프록시 패턴
- Real Subject : 원래 해야할 일
- Proxy : 원래 해야할 일을 참조
- 즉, Subject의 타입은 Proxy를 사용하고 Proxy는 Real Subject를 감싸서 실제 클라이언트의 요청을 처리하게 된다.
- 이렇게 하는 이유는? 접근 제어 혹은 유연한 부가 기능 추가 때문이다.
예제를 통해 살펴보자
EventService : Subject
SimpleEventService : Real Subject
//Subject
public interface EventService {
void createEvent();
void publishEvent();
}
//Real Subject
@Service
public class SimpleEventService implements EventService {
@Override
public void createEvent() {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Created an event");
}
@Override
public void publishEvent() {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Published an event");
}
}
단순히 EventService의 구현체로 SimpleEventService를 구현한 것이다.
이제 Proxy 패턴을 사용해보자
현재 시스템에서 Client(AppRunner.java) 코드와 Real Subject의 코드를 수정하지 않고 기능(Real Subject의 메소드를 실행하는 시간을 측정하는 기능)을 추가해보자
//Real Subject
@Service
public class SimpleEventService implements EventService {
@Override
public void createEvent() {
long begin = System.currentTimeMillis();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Created an event");
System.out.println(System.currentTimeMillis() - begin);
}
@Override
public void publishEvent() {
long begin = System.currentTimeMillis();
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Published an event");
System.out.println(System.currentTimeMillis() - begin);
}
@Override
public void deleteEvent() {
System.out.println("Delete an event");
}
}
단순히 이런 식으로 각 메소드의 실행 시간을 측정할 수 있는데, 이런 코드는 각 메소드마다 중복적인 소스가 나타나므로 이런 현상이 Crosscutting Conserns 이다.
즉, 메소드를 추가할 때마다 실행 시간을 측정하는 명령어가 모두 들어가게 되는 것이다. 이런 부분을 proxy 패턴을 활용해서 해결해보자.
Proxy 패턴 및 AOP
ProxySImpleEventService에서 메소드에 직접적으로 접근하지 않고 부가적인 기능을 추가하고 있다.
@Primary
@Service
public class ProxySimpleEventService implements EventService{
//보통 인터페이스의 Bean을 주입받아 사용해야 하지만, proxy의 경우는 Real Subject의 Bean을 주입받아 사용해야 한다.
@Autowired
SimpleEventService simpleEventService;
@Override
public void createEvent() {
long begin = System.currentTimeMillis();
simpleEventService.createEvent();
System.out.println(System.currentTimeMillis() - begin);
}
@Override
public void publishEvent() {
long begin = System.currentTimeMillis();
simpleEventService.publishEvent();
System.out.println(System.currentTimeMillis() - begin);
}
@Override
public void deleteEvent() {
simpleEventService.deleteEvent();
}
}
하지만 이 부분에도 중복되는 코드는 존재한다. 또한, SimpleEventService(Real Subject)뿐만 아니라 다른 클래스에도 proxy가 필요하다면 모두 일일이 추가해야하는 경우가 발생한다.
proxy 단점 해결 -> Spring AOP
단점을 해결하기 위해 우리는 두가지 관점을 활용한 Spring AOP를 사용할 수 있다.
- 동적으로 proxy 객체를 만들자 -> 런타임 시에 동적으로 어떤 객체에 proxy 객체를 만들자.
- Spring IOC를 활용하자
Spring AOP
Spring AOP 구성
- SimpleEventService(Real Subject)가 Bean으로 등록된다
- BeanPostProcessor(Bean을 가공할 수 있는 LifeCycle 인터페이스)를 구현한 AbstractAutoProxyCreator로 Real Subject Bean을 감싸는 Proxy Bean을 만든다.
- 해당 Proxy Bean을 Real Subject Bean 대신에 등록을 해준다.
참고
토비의 스프링 3
반응형
'Spring > Spring 핵심' 카테고리의 다른 글
[스프링 핵심] 스프링 AOP: @AOP (0) | 2020.02.03 |
---|---|
[스프링 핵심] 스프링 AOP: 개념 소개 (0) | 2020.01.30 |
[스프링 핵심] Validation 추상화 (0) | 2020.01.17 |
[스프링 핵심] Resource 추상화 (0) | 2020.01.17 |
[스프링 핵심] ResourceLoader (0) | 2019.12.29 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 빌더 패턴
- junit
- flatMap
- springboot
- 자바8
- 이펙티브 자바
- 정적팩터리메서드
- java8
- 스프링부트
- try catch finally
- 복사 팩토리
- Spring
- 인프런
- try with resources
- jdk버전
- java
- ifPresent
- 이펙티브자바
- 생성자
- @Lazy
- effectivejava
- mustache
- 빈 순환 참조
- 팩토리 메소드 패턴
- JPA
- 점층적 생성 패턴
- Effective Java
- 김영한
- 연관관계
- package-private
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함