[Spring] 프록시 기반 AOP

2022. 10. 30. 17:24JAVA/Spring

1. 스프링 AOP 특징

  • 프록시 기반 AOP 구현체
  • 스프링 빈에만 AOP를 적용할 수 있음
  • 모든 AOP 기능을 제공하는 것이 목적이 아니라, 스프링 IoC와 연동하여 엔터프라이즈 애플리케이션에서 가장 흔한 문제에 대한 해결책을 제공하는 것이 목적

 

2. 프록시 패턴

  • 프록시 패턴은 기존 코드 변경 없이 접근을 제어(멤버에 접근, 메서드에 접근)하거나 부가적인 기능(속도 측정, 트랜잭션, 입력값 범위 검사, 유효성 검사 등)을 추가하는데 사용됨
  • 예를 들어 기존 코드를 건드리지 않고 메서드의 성능 측정을 하는데 사용할 수 있음

 

3. 수동적인 프록시 패턴의 문제점

  • 매번 프록시 클래스를 작성하는 문제
  • 여러 클래스 여러 메서드에 적용할 때 문제
  • 객체들의 관계가 복잡할때 어려움

 

4. 수동적인 프록시 패턴의 해결안 : 스프링 AOP

  • 스프링 IoC 컨테이너가 제공하는 기반 시설과 동적 프록시를 사용하여 여러 복잡한 문제를 해결함
  • 동적 프록시 : 동적으로 프록시 객체를 생성하는 방법
    • 자바가 제공하는 방법은 인터페이스 기반 프록시 생성
    • CGlib은 클래스 기반 프록시도 지원
  • 스프링 IoC : 기존 빈을 대체하는 동적 프록시 빈을 만들어 등록시켜줌

 

5. 수동적인 프록시 패턴 구현 실습

실습의 배경은 어떤한 EventService의 createEvent 메서드와 publishEvent 메서드의 속도를 측정하기 위해서 프록시 패턴을 사용하여 EventService 인터페이스의 구현 클래스인 SimpleEventService의 프록시를 생성한다음 실행을 위임하는 방식입니다.

 

1. Subject 인터페이스인 EventService 인터페이스 정의

public interface EventService {
    void createEvent();
    void publishEvent();
    void deleteEvent();
}

 

2. Real Subject 클래스인 SimpleEventService 클래스를 정의

@Service
public class SimpleEventService implements EventService {
    @Override
    public void createEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Created an Event");
    }

    @Override
    public void publishEvent() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Published an event");
    }

    @Override
    public void deleteEvent() {
        System.out.print("Deleted an Event");
    }
}
  • createEvent 메서드는 수행하는데 1초 소요 가정
  • publishEvent 메서드는 수행하는데 2초 소요 가정

 

3. SimpleEventService 클래스의 프록시 클래스 정의

@Primary
@Component
@AllArgsConstructor
public class ProxySimpleEventService implements EventService{
    @Qualifier("simpleEventService")
    private final EventService eventService;

    @Override
    public void createEvent() {
        long begin = System.currentTimeMillis();
        eventService.createEvent();
        long end = System.currentTimeMillis() - begin;
        System.out.println(Math.round(end));
    }

    @Override
    public void publishEvent() {
        long begin = System.currentTimeMillis();
        eventService.publishEvent();
        long end = System.currentTimeMillis() - begin;
        System.out.println(Math.round(end));
    }

    @Override
    public void deleteEvent() {
        eventService.deleteEvent();
    }
}
  1. 테스트 코드 작성후 실행결과 확인
@SpringBootTest
public class SimpleEventServiceTest {
    @Autowired
    private EventService eventService;

    @Test
    public void testCreatedEvent(){
        eventService.createEvent();
    }

    @Test
    public void testPublishedEvent(){
        eventService.publishEvent();
    }
}

실행결과는 다음과 같습니다.

Created an Event
1007
Published an event
2015

 

수동적인 프록시 패턴의 문제점

만약 SimpleEventService 외의 다른 서비스 클래스의 메서드 성능측정을 하고 싶다면 새로운 프록시 클래스를 생성할 수 밖에 없습니다.

 

References

source code : https://github.com/yonghwankim-dev/spring_study/tree/master/spring_aop/src/main/java/kr/yh
[인프런] 스프링 프레임워크 핵심 기술