개발 기록

> [AOP] 2. Aspect 생성과 지시자 사용 본문

Spring

> [AOP] 2. Aspect 생성과 지시자 사용

1z 2022. 10. 6. 17:58

 

 

1. 사용법  

(1) 의존성 추가 

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

 

 

(2) Aspect 구현 

: 여러 클래스에 적용되는 관심사의 모듈화 구현 (ex. logging)

1. Aspect 만들기

@Aspect Annotation을 부착하여 해당 Class가 횡단관심사(부가기능) Class임을 알려준다. 

 

@Aspect Annotation이 부여되었다고 해서 자동으로 Bean으로 등록되는것이 아니므로 @Component등 을 이용하여 Bean으로 등록을 해준다.

이유 : Spring AOP의 경우 AOP를 제공받을 Bean를 IOC Container에 의해 생성될 때 ProxyBean을 만들어서 AOP를 제공하기 때문이다. 

 

2. Pointcut 과 Advice 만들기

@Around("Pointcut") 

2-1. Advice 생성 : @Around => 핵심관심사의 실패여부와 상관없이 전 후로 실행되도록 하는 Advice

2-2. Pointcut 설정 : @Around 의 속성값으로 PointCut 을 전달

@Around("execution(* com.java.ex.Car.accelerate(..))")
public Object logging(ProceedingJoinPoint joinPoint) throws Throwable {
    String methodName = joinPoint.getSignature().toShortString();
    System.out.println(methodName + "is Start.");
    Object obj = joinPoint.proceed();
    return obj;
}

 

1. 첫번째  기호는 접근제어자, 반환형을 상관하지 않는다는 의미

2. com.java.ex.Car.accelerate() 해당 Class의 파라미터가 없는  accelerate() 메소드가 호출될 때 실행

 

 


 

2. Spring JointPoint 메서드

method name return 설명
getSignature() Signature  대상 메서드의 정보 (리턴타입, 이름, 매개변수)가 저장된 Signature 객체 
getSignature().getName()
String  대상 메서드명
getSignature().toLongString() String  대상 메서드의 패키지 경로, 리턴타입, 이름, 매개변수
getSignature().toShortString()  String  대상 메서드의 시그니처를 축약한 문자열로 리턴
getTarget() Object  대상 메서드의 해당 클래스 객체
getArgs() Object[] 대상 메서드를 호출할 때 넘겨준 인자 목록

 


 

3. 지시자 

(1) excution 

// FooDao 클래스 의 findById 메소드 실행
@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")

 

(2) 패키지 타입으로 매칭 - within 과 @within  

: 타입이 매칭되면 그 안에 모든 메서드가 매칭된다.

// 아래 두개는 의미가 같다.
@Pointcut("@within(org.springframework.stereotype.Repository)")
@Pointcut("within(@org.springframework.stereotype.Repository *)")

 

 

(3) 파라미터 타입으로 매칭 -  @args 와 args

☞ args – 인수가 특정 유형인 메서드와 일치

@args – 인수에 특정 주석이 달린 메서드와 일치

* 상위 타입으로도 매칭이 가능하다. (ex. args(String)은 args(Object) 로도 매칭 가능)

// 단일 매개변수를 사용하고, @Entity 주석이 달린 Bean을 파라미터로 받는 모든 메소드
@Pointcut("@args(com.baeldung.pointcutadvice.annotations.Entity)")

// 파라미터 타입을 String 으로 받는 모든 메서드
@Pointcut("args(String)")

 

(4)어노테이션 매칭 - @annotation

지정된 annotation 이 있는 조인 포인트에 대한 일치 

// @Loggable 어노테이션이 있는 메서드
@Pointcut("@annotation(com.baeldung.pointcutadvice.annotations.Loggable)")
public void loggableMethods() {}

 

(5) this, target, @target 

   this : 스프링 빈 개체(AOP 프록시)를 대상으로 하는 조인 포인트

   target : Target 객체(프록시가 가르키는 실제 대상)을 대상으로 하는 조인 포인트

  @target : 실행 객체의 클래스에 주어진 타입의 어노테이션이 있는 조인 포인트

//  대상 개체가 AccountService 인터페이스를 구현하는 모든 조인 포인트
"target(com.jbd.service.AccountService)"

// 대상 개체에 @Transactional 주석이 있는 조인 포인트
"@target(org.springframework.transaction.annotation.Transactional)"

// 프록시가 AccountService 인터페이스를 구현하는 조인 포인트와 일치
"this(com.jbd.service.AccountService)"

 

ex. A class 가 B interface 의 메서드를 구현한다고 했을 때

Spring AOP는 JDK 기반 프록시를 사용하며,  프록시된 객체는 Proxy 클래스 의 인스턴스가 되고 B 인터페이스를 구현하므로 아래 포인트 컷을 사용해야한다. 

@Pointcut("target(com.baeldung.pointcutadvice.dao.B)")

 

반면에 A class 가 인터페이스를 구현하지 않거나 ProxyTargetClass 속성이 true로 설정된 경우 프록시된 개체는 A class 의 하위 클래스가 되며 아래 포인트컷을 사용한다.

@Pointcut("this(com.baeldung.pointcutadvice.dao.A)")

 

 

 

 

 

 

 

참고

https://backtony.github.io/spring/2021-12-29-spring-aop-2/#args

https://www.baeldung.com/spring-aop-advice-tutorial

https://galid1.tistory.com/498

https://backtony.github.io/spring/2021-12-29-spring-aop-2/#cglib%EA%B3%BC-jdk-%EB%8F%99%EC%A0%81-%ED%94%84%EB%A1%9D%EC%8B%9C-%EC%A4%91-spring%EC%9D%98-%EC%84%A0%ED%83%9D