본문 바로가기
Spring

[Spring] Spring AOP

by BENGGRI 2021. 2. 1.
반응형

1. 스프링 AOP ( Aspect Oriented Programming )

filter, interceptor, AOP 흐름

AOP 는 관점 지향 프로그래밍이라고 불립니다.

관점 지향은 로직의 핵심적인 관점부가적인 관점으로 나누어 관점기준으로 각각 모듈화하겠다는 것입니다.

모듈화 : 공통된 로직이나 기능을 하나의 단위로 묶는 것을 의미합니다.

 

Class A, Class B, Class C 소스 코드에서 A();, C(); 는 계속 반복해서 쓰는 코드를 발견할 수 있습니다.

(흩어진 관심사라고 부릅니다.)

코드 변경이 필요한 경우 일일이 찾아서 바꿔줘야합니다.

AOP 는 여러곳에서 사용되는 중복되는 코드를 분리하고 자신이 해야할 작업만을 갖고 있자는 것입니다.


2. AOP 주요 개념

  1. Aspect : 흩어진 관심사를 모듈화 한 것입니다.(주로 부가기능을 모듈화 합니다.)
  2. Target : Aspect 를 적용하는 곳입니다.(클래스, 메서드 ... )
  3. Advice : 실질적으로 어떤 일(부가기능)을 해야할 지에 대한 구현체 입니다.
  4. JoinPonit : Advice 가 적용될 위치, 끼어들 수 있는 지점, 메서드 진입 지점, 생성자 호출 시점 등 다양한 시점에서 적용 가능합니다. 
  5. PointCut : JoinPonit 의 상세한 스펙을 정의한 것입니다. 

3. 프록시 패턴

Spring AOP 는 프록시 패턴이라는 디자인 패턴을 사용해 AOP 효과를 냅니다.

프록시 패턴을 사용하면 어떤 기능을 추가하려 할 때 기존 코드를 변경하지 않고 기능을 추가할 수 있습니다.

 

어떤 클래스가 Spring AOP 의 대상이라면 기존 클래스의 빈이 만들어질 때 Spring AOP 가 프록시(기능이 추가된 클래스)를 자동으로 만들고 원본 클래스 대신 프록시를 빈으로 등록합니다.

그리고 원본 클래스가 사용되는 지점에서 프록시를 대신 사용합니다.

 

대표적인 예는 @Transactional 입니다.

 

JDBC 에서 트랜잭션 처리 전후에 setAutoCommit() 과 commit()/rollback() 코드가 항상 작성되어야하지만, @Transactional Annotation 이 선언되어 있으면 프록시에 자동으로 setAutoCommit() 과 commit()/rollback() 코드를 넣어 반복, 중복되는 코드를 생략할 수 있게 되는 것입니다.


4. 적용 방법

1. Dependency 추가

<!-- Spring boot -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- Spring -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.3</version>
</dependency>

 

2. 설정

1. xml 

<aop:config>
	<aop:pointcut id="aopPointcut" expression="execution(* com.study.aop.controller.HomeController.getHome(..))" />
	<aop:aspect ref="aopAdvice">
		<aop:before pointcut-ref="aopPointcut" method="beforeAop"/>
		<aop:after-returning pointcut-ref="aopPointcut" method="afterAopReturning"/>
		<aop:after-throwing throwing="ex" pointcut-ref="aopPointcut" method="afterAopThrowing"/>
		<aop:around pointcut-ref="aopPointcut" method="aroundAop"/>
	</aop:aspect>
</aop:config>

<bean id="aopAdvice" class="com.study.aop.AopAdvice" />

 

2. java

@Component
@Aspect
public class AopAspect {

    @PonitCut("execution(* com.study.aop.controller.HomeController.*(..))")
    public void pointCut() {}

    @Before("execution(* com.study.aop.controller.HomeController.*(..))") 
    public void beforeLog(JoinPoint joinPoint) {
        ... logic
    }

    @After("execution(* com.study.aop.controller.HomeController.add(..))") 
    public void afterLog(JoinPoint joinPoint) {
        ... logic
    }

    @AfterReturning("execution(* com.study.aop.controller.add(..) || execution(* com.study.aop.controller.division(..)" )
    public void afterReturning(JoinPoint joinPoint) {
        ... logic
    }

    @AfterThrowing(pointcut = "execution(* com.study.aop.controller.division(..)) ||" 
                            + " execution(* com.study.aop.controller.multiply(..))", throwing="ex")
    public void afterThrowing(JoinPoint joinPoint, ArithmeticException ex) {
        ... logic
    }

    @Around("execution(* com.study.aop.controller.HomeController.getHome(..))")
    public Object aroundAop(ProceedingJoinPoint pjp) throws Throwable{
        ... logic
        return retVal;
    }
}

5. AOP 용어

용어 설명
Before 메소드 실행 전 Adive 실행
After 메소드 실행 후 Advice 실행
After-returning 메소드가 성공 후 (예외 없이) Advice 실행
After-throwing 메소드가 예외 발생 후 Advice 실행
Around 메소드 실행 전과 후 Advice 실행(Before + After)
Pointcut AOP 를 적용할 수 있는 지점

 

 

표현식 설명
execution(public * *(..)) 모든 public 메서드에 실행
execution(* set*(..)) set 으로 시작하는 모든 메서드에 실행
execution(* com.study.service.AopService.*(..)) AopService 안 모든 메서드에 실행
execution(* com.study.service.*.*(..)) service 패키지 안에 모든 메서드에 실행
execution(* com.study.service..*.*(..)) service 서브패키지를 포함한 패키지 안에 모든 메서드에 실행
within(com.study.service.*) service 패키지 안에 모든 joinpoint 에 실행
within(com.study.service.*) service 의 서비패키지를 포함한 패키지 안에 모든 joinponit 에 실행

 

반응형

댓글