AOP는 어떤 어드바이스를 적용시킬 것인지도 중요하지만 어느 위치에 적용할 것인지도 매우 중요합니다. 생성자, 필드 값 접근, static 메서드, 일반 메서드 등에서 실행가능 하며, AOP를 수행하는 메서드는 JoinPoint
(@Around
는 ProceedingJoinPoint
)를 인자로 받게 됩니다.
조인 포인트는 AOP를 적용할 수 있는(어드바이스가 적용될 수 있는) 지점을 의미합니다.
스프링에서 AOP를 적용하는 방법은 2가지가 있습니다. 첫번째로 AspectJ
를 사용하는 경우 모든 조인포인트에서 어드바이스를 적용시킬 수 있습니다. 반면에 두번째로 프록시
를 사용하는 AOP인 경우 메서드 실행
으로 제한됩니다.
추상 메서드 | 설명 |
---|---|
JoinPoint.getArgs() | JoinPoint에 전달된 인자를 배열로 반환합니다. |
JoinPoint.getThis() | AOP 프록시 객체를 반환합니다. |
JoinPoint.getTarget() | AOP가 적용된 대상 객체를 반환합니다. |
JoinPoint.getSignature() | 조인되는 메서드의 시그니처(반환타입,메서드명,매개변수) 정보가 저장된 시그니처 객체 를 반환합니다. |
JoinPoint.toString() | 조인되는 메서드의 대한 설명을 출력합니다. |
ProceedingJoinPoint.proceed() | 다음 어드바이스나 타겟을 호출합니다. |
Spring에서 AOP는 Ioc를 보완하여 강력한 솔루션을 제공합니다.
@AspectJ는 에너테이션이 있는 일반 자바 클래스로 관점을 선언하는 스타일을 의미합니다.
@AspectJ
는 AspectJ 5 버전 릴리스부터 도입되었습니다.@AspectJ
지원을 활성화 하기 위해선 @EnableAspectJAutoProxy
에너테이션을 @Configuration
에너테이션이 있는 클래스에 추가합니다.
@Configuration
@EnableAspectJAutoProxy
public class AppConfig{
}
애너테이션이 아닌 XML
기반 구성을 @AspectJ
지원을 활성화 할 수 있습니다.
<aop:aspectj-autoproxy/>
@AspectJ 지원이 활성화되면 @AspectJ 관점이 있는 클래스로 애플리케이션 컨텍스트에 정의된 모든 빈이 Spring에서 자동으로 감지되고 SpringAOP를 구성하는데 사용됩니다.
<bean id="myAspect" class="start.aop.MyAspect">
</bean>
@Aspect
public class MyAspect{
}
포인트컷과 어드바이스, 어스팩트는 추상적인 개념으로 스프링 내에서 무엇을 의미하는지 파악하는 것이 중요하다고 생각합니다.
어스팩트
: 어드바이스(메서드)들이 모여있고 @Aspect
에너테이션이 있는 일반 클래스포인트컷
: 핵심 기능에서 어드바이스가 실행되는 위치(전,후,성공,실패,공통,..)어드바이스
: 어스팩트 내에 존재하는 부가기능을 정의하는 메서드스프링에서 AOP는 어떤 형태로 존재하고 사용되는지 알아보도록 하겠습니다.
AspectJ는 외부라이브러리로 사용하기 전에 gradle
에서 import 하여야 사용할 수 있습니다.
build.gradle의 dependency에 추가
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-test'
CompileOnly 'org.projectlombok:lombok'
AnnotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
스프링 컨테이너에 등록할 빈 객체에는 @Slf4j
애너테이션이 추가적으로 필요합니다.
@Slf4j
//@Service
//@Controller
@Repository
public class BeanObject{
}
AspectJ로 테스트를 진행하기 위해선 테스트를 수행할 설정 정보 클래스에 @SpringBootTest
에너테이션을, 테스트를 수행할 메서드엔 @Test
에너테이션이 필요합니다.
@Slf4j
@SpringBootTest
public class 설정정보클래스{
@Test
void 테스트메서드(){
}
}
Junit
을 사용하여 실행합니다.
Aspect를 만들기 위해선 @Slf4j
애너테이션과 @Aspect
애너테이션이 필요합니다.
@Slf4j
@Aspect
public class 어스팩트{
@Around("AspectJ표현식") //포인트컷
public Object 어드바이스(ProceedingJoinPoint joinPoint) throws Throwable{
log.info("",joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Around
는 포이트컷으로 대상의 어느 시점에 적용할지 지정합니다.
어스팩트 클래스내에 어드바이스 메서드로 어떤 부가적인 기능을 수행할지 정의합니다.
@Pointcut
애너테이션을 활용하여 어드바이스에서 포인트컷을 분리할 수도, 두 포인트 컷을 합칠 수도 있습니다
@Slf4j
@Aspect
public class 어스펙트{
@Pointcut("AspectJ표현식")
private void first(){}
@Pointcut("AspectJ표현식")
private void second(){}
@Around("first() && second()")
public Object 어드바이스(ProceedingJoinPoint joinPoint) throws Throwable{
log.info("",joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Around
에너테이션은 @Before
, @AfterReturning
, @AfterThrowing
, @After
을 모두 포함할 수 있습니다.
@Around("AspectJ표현식")
public Object 어드바이스(ProceedingJoinPoint joinPoint) throws Throwable{
try{
//@Befpre
Object result = joinPoint.proceed();
//@AfterReturning
}catch(Exception e){
//@AfterThrowing
}finally{
//@After
}
}
AOP는 어렵게 생각하면 어렵고 쉽게 생각하면 쉬운것인 것 같네요, 특히 프록시와 AspectJ부분이 깊게 파고들면 그만큼 난이도가 많이 어려워지는것 같습니다. 지금 달달 외우기 보단 스프링에 좀더 익숙해지고 아는것이 많아지면 다시 익히는것이 좋을 것 같습니다.
https://github.com/ds02168/CodeStates_Spring/tree/main/section2-week4