[Spring] 프록시 패턴 & 스프링 AOP

Junseo Kim·2020년 1월 30일
9

스프링 AOP는 프록시 기반의 AOP 구현체이며, 스프링 Bean에만 AOP 적용 가능하다.

프록시 패턴이란?

프록시 객체는 원래 객체를 감싸고 있는 객체이다. 원래 객체와 타입은 동일하다. 프록시 객체가 원래 객체를 감싸서 client의 요청을 처리하게 하는 패턴이다.

프록시 패턴을 쓰는 이유는 접근을 제어하고 싶거나, 부가 기능을 추가하고 싶을 때 사용한다.

EventService라는 interface가 있고,

EventService를 implements 한 TestEventService 가 있다고 하면,

이 코드를 실행시키는 main이 client라고 볼 수 있고, TestEventService가 원래 객체로 볼 수 있다.

TestEventService의 createEvent 메서드와 publishEvent 메서드에 동일한 기능을 하는 코드를 넣고 싶을 때, 각각 메서드에 넣어주는 것은 효율성이 떨어진다.

이럴 때 프록시패턴을 사용한다.

프록시 객체는 원래 객체와 같은 interface를 구현해줘야한다. 원래 객체를 주입받아서, interface의 메서드들을 위임받아 사용하고, 원하는 추가 코드를 넣어주면 된다.

스프링 AOP

이렇게 해주면, 원래 코드에 손을 쓰지 않고도 기능을 추가 할 수는 있지만, 프록시 객체에 중복코드가 발생할 수 있고, 다른 클래스에서도 동일한 기능을 사용하고자 할 때, 매번 코딩을 해줘야하는 부분에서 효율적이지 못하다.

이런 문제를 해결해주는 게, 런타임시, 동적으로 프록시객체를 만들어주는 것인데, 그것이 스프링 AOP이다.

위의 예제로 살펴보면,
1) TestEventService가 Bean으로 등록이되면,
2) 스프링이 AbstractAutoProxyCreator라는 BeanPostProcessor(어떤 Bean이 등록되면, 그 Bean을 가공할 수 있는 life-cycle interface)로 TestEventService라는 Bean을 감싸는 프록시 Bean을 만들어,
3) 그 프록시 Bean을 TestEventService 대신에 등록해준다.

스프링 AOP를 사용해주기 위해서는 pom.xml에 의존성을 추가해주어야한다.

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.6</version>
        </dependency>
        
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.6</version>
        </dependency>

Aspect 클래스를 만들어준다.

Aspect에는 2가지 정보가 필요하다. pointcut(어디에 적용할 것인지)과 advice(해야할 일, 기능)이다.

public Object logPerf 자체가 하나의 advice이며, 이 advice가 어디에 적용될 것 인지(pointcut) @Around 어노테이션으로 표시해준다.
@Around("execution(* 패키지.interface.메서드)")

execution말고 어노테이션을 만들어서 사용할 수도 있다.

어노테이션 파일을 만들고, @Retention 어노테이션을 CLASS타입으로 설정해준다.

사용할 곳에 만들어준 어노테이션을 붙여준다.

Aspect 클래스의 @Around 어노테이션에 execution대신 @annotation을 사용한다.

execution과 @annotation 대신 bean을 사용할 수도 있다.

@Around 어노테이션은 강력한 편이고, 간단히 사용할 때는 @Before, @AfterReturning, @AfterThrowing 등을 사용해도 된다.

2개의 댓글

comment-user-thumbnail
2021년 12월 14일

좋은 설명 감사합니다!!!

1개의 답글