✔AOP(Aspect Oriented Programming)
1. AOP(Aspect Oriented Programming)
- 핵심 관심 사항과 전체에 적용되는 공통관심 사항을 기준으로 프로그래밍 함으로서 공통 모듈을 여러 코드에 쉽게 적용할 수 있도록 지원
◾AOP
Aspect
- AOP의 모듈화 단위.
- 여러 타입과 객체에 거쳐서 사용되는 기능(Cross Cutting, 트랜잭션 관리 등)의 모듈화.
- Spring의 필수 요소는 아니지만 Spring IoC를 보완.
◾AOP 용어
- Aspect : 여러 객체에 공통으로 적용되는 공통 관심 사항을 Aspect라고 한다. 트랜잭션이나 보안 등이 Aspect의 좋은 예시이다.
- Advice : 언제 공통 관심 기능을 핵심 로직에 적용할지를 정의하고 있다. 예를 들어, '메서드를 호출하기 전' (언제)에 '성능 측정을 시작한다' (공통 기능) 기능을 적용한다는 것을 정의하고 있다.
- Joinpoint : Advice를 적용 가능한 지점을 의미한다. 메서드 호출, 필드 값 변경 등이 Joinpoint에 해당한다.
- Pointcut : Joinpoint의 부분 집합으로써 실제로 Advice가 적용되는 Joinpoint를 나타낸다. 스프링에서는 정규 표현식이나 AspectJ의 문법을 이용하여 Pointcut를 정의할 수 있다.
- Weaving : Advice를 핵심 로직 코드에 적용하는 것을 Weaving이라고 한다. 공통 코드를 핵심 로직 코드에 삽입하는 것이 Weaving이다.
- Target 객체 : 하나 이상의 advice가 적용될 객체. Spring AOP는 Runtime Proxy를 사용하여 구현되므로 항상 Proxy 객체가 된다.
- AOP Proxy : AOP를 구현하기 위해 AOP 프레임워크에 의해 생성된 객체, Spring에서 AOP Proxy는 JDK dynamic proxy 또는 CGLIB proxy이다.
◾Spring AOP Proxy
- Spring은 Target 객체에 대한 Proxy를 만들어 제공.
- Target을 감싸는 Proxy는 실행시간(Runtime)에 생성.
- Proxy는 Advice를 Target 객체에 적용하면서 생성되는 객체.
2. AOP 적용하기 - XML
◾Aspect 선언
- 핵심 관심 사항 Aspect 작성 및 XML을 통해 bean 등록.
public class ServiceAspect{
public void method1(){
System.out.println("method1");
}
public void method2(){
System.out.println("method1");
}
<bean id = "myAspect" class="com.project.ServiceAspect">
</bean>
◾Pointcut 선언
- 어떤 조인 포인트를 사용할지 결정.
- 조인 포인트에 대한 표현식.
- 포인트 컷의 이름.
<aop:config>
<aop:pointcut
expression="execution(public * project.service.*.doSomthing())" id = "mypt"/>
<aop:before method = "method1" pointcut-ref="mypt"/>
<aop:after method = "method2" pointcut-ref="mypt"/>
3. AOP 적용하기 - Annotation
◾@AspectJ 활성화
- Annotation으로 AOP를 사용하기 위해 자동으로 적용되도록 설정.
<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.project"/>
◾Bean 등록.
- 원하는 클래스에 Annotation을 이용해 Bean 등록.
- Advice Type
- before : target 메서드 호출 이전.
- after : target 메서드 호출 이후, java exception 문장의 finally와 같이 동작.
- after returning : target 메서드 정상 동작 후
- after throwing : target 메서드 에러 발생 후
- around : target 메서드의 실행 시기, 방법, 실행 여부 결정
@Component
@Aspect
public class ServiceAspect{
@Pointcut("execution(public * com.project.service.*.doSomething())")
public void servicepointcut(){}
@Before("servicepointcut()")
public void method1(){
System.out.println("method1");
}
@After("servicepointcut()")
public void method2(){
System.out.println("method1");
}
}
◾Pointcut Expression 패턴
Pointcut | 선택된 joinpoints |
---|
execution(public * *(..)) | public 메소드 실행. |
execution(* set*(..)) | 이름이 set으로 시작하는 모든 메소드 실행 |
execution(* com.test.service.AccountService.*(..)) | AccountService의 모든 메소드 실행 |
execution(* com.test.service..(..)) | service 패키지의 모든 메소드 실행. |
execution(* com.test.service...(..)) | service 패키지와 하위 패키지의 모든 메소드 실행 |