Aspect Oriented Programming(관점 지향 프로그래밍)의 약어
어떠한 기준을 정하고, 관점을 나누어서 각 관점 별로 모듈화를 하여 사용하는 방식이다.
일반적인 자바 애플리케이션은 웹 계층, 비즈니스 계층, 데이터 계층 등 여러 계층으로 응용 프로그램을 개발한다.
이때 각 계층의 책임은 다르지만 로깅, 트랜잭션, 보안, 인증, 캐싱 등 공통적인 로직이 필요하다.
이러한 공통적인 로직을 횡단 관심사(cross-cutting concern)이라고 부른다.
공통 로직을 각 계층에서 개별적으로 구현하면, 코드 유지관리가 어려워진다.
이 문제를 극복하기 위해 AOP는 횡단 관심사 구현하는 해결책을 제공한다.
AOP는 횡단 관심사의 분리를 통해 공통 기능을 한 곳에 정의하여 모듈성을 증가시킨다.
스프링은 내부에서 트랜잭션 관리, 캐싱, 보안 등의 선언적인 서비스를 구현하기 위해
Spring AOP
프레임워크를 제공한다.스프링 프레임워크 대신
AspectJ
를 애플리케이션에서 AOP 프레임워크로 사용할 수도 있다.
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.5.5</version>
</dependency>
Gradle
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.5.5'
main
메소드를 갖는Application
클래스에@ Annotation
을 추가
예시
JavaConfig
@Configuration
@EnableAspectJAutoProxy
public class JavaConfig {
// MessengerAspect 를 bean 으로 만들기
@Bean
public MessengerAspect msa() {
return new MessengerAspect();
}
}
Application
@SpringBootApplication
public class Boot02AopApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Boot02AopApplication.class, args);
Messenger m1 = ctx.getBean(Messenger.class);
String msg = m1.getMessage();
System.out.println("Messenger 객체로부터 받은 메세지 : " + msg);
m1.sendGreeting("안녕하세요");
m1.sendGreeting("안녕 바보야");
m1.sendGreeting("또 만났군요!");
}
}
- @Before
Target 메소드 호출 전에 적용- @AfterReturning
Target 메소드 호출 후 적용- @AfterThrowing
Target에서 예외 발생 후 적용- @After
Target 메소드 호출 후 예외 발생에 상관없이 적용- @Around
Target 메소드 호출 전/후 적용
실행순서
사용 예시
@Aspect
public class MessengerAspect {
@Around("execution(void send*(..))")
public void checkGreeting(ProceedingJoinPoint joinPoint) throws Throwable {
// aspect 가 적용된 메소드가 호출되기 직전에 할 작업은 여기서 한다.
// 메소드에 전달된 인자들 목록 얻어내기
Object[] args = joinPoint.getArgs();
for (Object tmp : args) {
// 만일 String type 이면
if (tmp instanceof String) {
// 원래 type 으로 casting
String msg = (String) tmp;
System.out.println("aspect 에서 읽어낸 내용: " + msg);
if (msg.contains("바보")) {
System.out.println("바보는 금지된 단어입니다.");
return; // 메소드 끝내기
}
}
}
// aspect 가 적용된 메소드가 호출되기 직전에 할 작업은 proceed() 호출 전에 한다.
// proceed() 를 호출해야 aspect 가 적용된 메소드가 실행이 된다.
joinPoint.proceed();
// aspect 가 적용된 메소드가 호출되기 직전에 할 작업은 proceed() 호출 이후에 한다.
System.out.println("aspect 가 적용된 메소드가 리턴했습니다.");
}
/*
return type 은 String 이고
get 으로 시작은 메소드 이고
메소드에 전달되는 인자는 없다
java.lang 패키지에 있는 type 은 패키지명 생략 가능
*/
@Around("execution(String com.example.aop.util.*.get*())")
public Object checkReturn(ProceedingJoinPoint joinPoint) throws Throwable {
// aspect 가 적용된 메소드를 수행하고 리턴되는 데이터 받아오기
Object obj = joinPoint.proceed();
// 원래 type 으로 casting 해서 조사해볼 수가 있다.
String a = (String) obj;
// 조사 후 아예 다른 값을 리턴해 줄 수도 있다.
return "놀자 ~~";
}
}
- AOP는 핵심기능(Core Concerns)과 부가기능 (Cross Cutting Concerns)을 분리하여 개발할 수 있게 해 준다.
- 부가기능에 해당하는 코드인 어드바이스와 적용한 위치를 문법적으로 표현한 포인트 컷을 합친 개념이 Aspect이다.
- 스프링 AOP는 메소드 조인 포인트만 지원하여 간단하게 쉽게 AOP를 구현할 수 있다.
- 포인트 컷의 문법을 이용하여 원하는 위치에 부가기능 어드바이스를 추가할 수 있다.
- Advice는 타깃 객체 이전과 이후 그리고 이전/이후 모두에 적용 가능하다.