1. 스프링 AOP ( Aspect Oriented Programming )
AOP 는 관점 지향 프로그래밍이라고 불립니다.
관점 지향은 로직의 핵심적인 관점과 부가적인 관점으로 나누어 관점을 기준으로 각각 모듈화하겠다는 것입니다.
※ 모듈화 : 공통된 로직이나 기능을 하나의 단위로 묶는 것을 의미합니다.
Class A, Class B, Class C 소스 코드에서 A();, C(); 는 계속 반복해서 쓰는 코드를 발견할 수 있습니다.
(흩어진 관심사라고 부릅니다.)
코드 변경이 필요한 경우 일일이 찾아서 바꿔줘야합니다.
AOP 는 여러곳에서 사용되는 중복되는 코드를 분리하고 자신이 해야할 작업만을 갖고 있자는 것입니다.
2. AOP 주요 개념
- Aspect : 흩어진 관심사를 모듈화 한 것입니다.(주로 부가기능을 모듈화 합니다.)
- Target : Aspect 를 적용하는 곳입니다.(클래스, 메서드 ... )
- Advice : 실질적으로 어떤 일(부가기능)을 해야할 지에 대한 구현체 입니다.
- JoinPonit : Advice 가 적용될 위치, 끼어들 수 있는 지점, 메서드 진입 지점, 생성자 호출 시점 등 다양한 시점에서 적용 가능합니다.
- 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 에 실행 |
'Spring' 카테고리의 다른 글
[Spring-Boot] 기초 - 프로젝트 생성 (0) | 2022.07.28 |
---|---|
[Spring] Spring Framework MVC 커뮤니티 사이트Tutorial - 4 (0) | 2021.02.02 |
[Spring] Spring Framework MVC 커뮤니티 사이트Tutorial - 3 (0) | 2021.01.29 |
[Spring] Spring Framework MVC 커뮤니티 사이트 Tutorial - 2 (2) | 2021.01.21 |
[Spring] Spring Framework MVC 커뮤니티 사이트Tutorial - 1 (0) | 2021.01.20 |
댓글