스프링 AOP의 특징

  • 프록시 기반으로 AOP를 구현한다.
    • 접근 제어 및 부가 기능을 추가하기 위해 사용
  • 스프링 빈에만 AOP를 적용할 수 있다.
  • 모든 AOP기능을 제공하는 것이 아니라, 스프링 IoC와 연동하여 엔터프라이즈 애플리케이션의 가장 흔한 문제애 대한 해결첵을 지원하는 것이 목적이다.

프록시 패턴

프록시 패턴은 인터페이스가 있다. 클라이언트는 인터페이스를 통해 프록시 객체를 사용하게 된다. 프록시 객체는 타겟 객체를 감싸서 실제 클라이언트의 요청을 처리한다. 기존 코드의 변경 없이 접근 제어와 부가 기능을 추가하기 위해서 주로 사용된다.

아래와 같이 클라이언트가 Service 기능을 사용하는 예제 코드가 있다고 가정해보자.

package me.cjkim.demoSpring51;

public interface EventService {
    void createEvent();
    void publishEvent();
}
package me.cjkim.demoSpring51;

import org.springframework.stereotype.Service;

@Service
public class SimpleEventService implements EventService{

    @Override
    public void createEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Created an event");
    }

    @Override
    public void publishEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("published an event");
    }
}

클라이언트 코드 :

package me.cjkim.demoSpring51;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
import java.util.Arrays;

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    EventService eventService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
       eventService.createEvent();
       eventService.publishEvent();
    }
}

여기서 프록시를 추가하여, 기존 클래스와 클라이언트도 건들이지 않고 메소드가 실행되는 시간을 측정하는 기능을 구현해보자.

package me.cjkim.demoSpring51;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Primary
@Service
public class ProxySimpleEventService implements EventService{

    @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);

    }
}

위와 같이 proxy클래스 객체를 사용하면, 기존 코드를 변경하지 않고 앞뒤에 시간을 측정하는 기능을 구현할 수 있다.

AOP 프록시 객체 생성시 문제점

  • 매번 프록시 클래스를 생성하는데 비용과 수고스러움이 든다.
  • 여러 클래스 여러 메소드에 적용하기 위해서는 결국 중복 코드가 발생한다.
  • 객체들간 관계도 복잡해진다.

이러한 문제를 해결하기 위해 나온 스프링 AOP

  • 스프링 컨테이너가 제공하는 기반 시설과 Dynamic 프록시를 사용하여 복잡한 문제 해결
  • 동적 프록시 : 동적으로 프록시 객체를 생성하는 기법 ( 애플리케이션 구동 시점, 즉 런타임 시점에 생성)
    • 자바가 제공하는 방법은 인터페이스 기반의 프록시 생성 기법
    • CGLiB는 클래스 기반 프록시도 지원한다.
  • 스프링 IoC : 기존 빈을 대체하는 동적 프록시 빈을 생성해준다.
    • AbstractAutoProxyCreator라는 BeanPostProcessor로 실제 객체를 감싸는 프록시 객체로 만들어서 실제 객체의 대체자로 지정을 해준다.

참고 자료

  1. 스프링 프레임워크 핵심 기술

oksusutea's blog

꾸준히 기록하려고 만든 블로그