매일 까먹는 스프링 개념 정리 3
2018-09-14
1. AOP
1-1. AOP란
- 관점 지향 프로그램(Aspect Oriented Programming)
- 프로그래밍을 하다 보면 공통적인 기능이 발생하는데, 이러한 공통 기능을 모든 모듈에 적용하기 위한 방법으로 상속을 통한 방법이 있다
- 하지만 자바에는 다중 상속이 불가하므로 다양한 모듈에 상속 기법을 통한 공통 기능 부여에는 한계가 있다.
- 그리고 기능 구현 부분에 핵심 기능 코드와 공통 기능 코드가 섞여 있어 효율성이 떨어진다 (ex. log)
- 위의 상속을 통한 방법에는 한계가 있어 AOP가 등장했다.
- AOP 방법은 핵심 기능과 공통 기능을 분리 시켜 놓고, 공통 기능을 필요로 하는 핵심 기능들에서 사용하는 방식이다.
1-2. 용어
- Aspect: 여러 객체에 공통으로 적용되는 공통 관심 사항으로 Advice와 JointPoint를 합친 것 (트랜잭션이나 보안)
- Advice: 언제 공통 관심 기능을 핵심 로직에 적용할지 정의. around, Before, After, after-returning, after-throwing
- Jointpoint: Advice를 적용 가능한 지점. 메소드 호출 시점, 예외 발생 시점 등 특정 작업시 시작 되는 시점. Advice를 weaving하는 포인트를 JointPoint라고 한다
- Weaving: Advice를 핵심 로직 코드에 적용하는 것을 위빙이라고 한다. 즉 공통 코드를 핵심 로직 코드에 삽입하는 것. Aspect를 Target 객체에 제공하여 새로운 프록시 객체를 생성하는 과정
- Target: 핵심 로직을 구현하는 클래스
- Proxy: 대상 객체에 Advice가 적용된 후 생성된 객체
1-4. 스프링에서의 AOP 구현 방법: proxy를 이용한다
- 호출부(client) –> 대행(proxy) –> 핵심기능(target)
1-5. 스프링에서 AOP 구현 방법
- XML 스키마 기반의 AOP 구현
- @Aspect 어노테이션 기반의 AOP 구현
2. XML 기반의 AOP 구현
2-1. 작업 순서
-
1) 의존 설정(pom.xml)
-
2) 공통 기능의 클래스 제작 - Advice 역할 클래스
public class LogAop {
public Object loggerAop(ProceedingJointPoint jointPoint) throew Throwable {
String signatureStr = jointPoint.getSignature().toShortString();
System.out.println(signatureStr + " is start");
long st = System.currentTimeMills();
try {
Object obj = jointPoint.proceed(); // 핵심 기능 코드 실행
return obj;
} finally {
long et = System.currentTimeMills();
System.out.println(signatureStr + " is finished");
System.out.println(signatureStr + " 경과시간 : " + (et-st) );
}
}
}
- 3) XML 설정 파일에 Aspect 설정
<!-- com.test.* 내부의 클래스 메소드 호출 시 around aspect 실행 됨 -->
<bean id="logAop" class="com.test.yjh.LogAop"/>
<aop:config>
<aop:aspect id="logger" reg="logAop">
<aop:pointcut id="publicM" expression="within(com.test.yjh.*)"/>
<aop:around pointcut-ref="publicM" method="loggerAop"/>
</aop:aspect>
</aop:config>
2-2. Advice 종류
- <aop:before>: 메소드 실행 전에 Advice 실행
- <aop:after-returning>: 정상적으로 메소드 실행 후에 Advice 실행
- <aop:after-throwing>: 메소드 실행 중 exception 발생 시 Advice 실행
- <aop:after>: 메소드 실행 중 exception이 발생하여도 advice 실행
- <aop:around>: 메소드 실행 전/후 및 exception 발생 시 advice 실행
3. @Aspect를 이용한 AOP구현
3-1. 작업 순서
- 1) 의존 설정(pom.xml)
- 2) @Aspect 어노테이션을 이용한 Aspect 클래스 제작
- 3) XML파일에 <aop:aspectj-autoproxy/> 설정
@Aspect
public class LogApp {
@Pointcut("within(com.test.yjh.*)")
private void pointcutMethod(){
}
// 방법1) point cut 사용
@Around("pointcutMethod())
public Object loggerAop(ProceedingJoinPoint joinPoint) throws Throwable {
String signatureStr = jointPoint.getSignature().toShortString();
System.out.println(signatureStr + " is start");
long st = System.currentTimeMills();
try {
Object obj = jointPoint.proceed(); // 핵심 기능 코드 실행
return obj;
} finally {
long et = System.currentTimeMills();
System.out.println(signatureStr + " is finished");
System.out.println(signatureStr + " 경과시간 : " + (et-st) );
}
}
// 방법2) expression 적용
@Before("within(com.test.yjh.*)")
public void beforeAdvice(){
System.out.println("beforeAdvice")
}
}
4. Aspect Pointcut 표현식
- pointcut을 지정할 때 사용하는 표현식으로 AspectJ 문법을 사용한다
- * : 모든 / . : 현재 / .. : 0개 이상
- Execution
// public void인 모든 get메소드
@Pointcut("execution(public void get*(..))")
// com.test.yjh 패키지에 파라미터가 없는 모든 메소드
@Pointcut("execution(* com.test.yjh.*.*()))
// com.test.yjh 패키지 & com.test.yjh 하위 패키지에 파라미터가 없는 모든 메소드
@Pointcut("execution(* com.test.yjh..*.*()))
// com.test.yjh.Book 안의 모든 메소드
@Pointcut("execution(* com.test.yjh.Book.*()))
- within
@Pointcut("within(com.test.yjh.*)") // com.test.yjh 패키지 안에 있는 모든 메소드
@Pointcut("within(com.test.yjh..*)") // com.test.yjh 패키지 및 하위 패키지 안에 있는 모든 메소드
@Pointcut("within(com.test.yjh.Book)") // com.test.yjh.Book의 모든 메소드