Chapter 7 내용
- 프록시와 AOP
- 스프링 AOP 구현
AOP( Aspect Oriented Programming)
- AOP는 여러 객체에 공통으로 적용할 수 있는 기능을 분리해서 재사용성을 높여주는 프로그래밍 기법이다
- AOP는 핵심 기능과 공통 기능의 구현을 분리해서 수정 없이 공통 기능을 적용할수 있게 한다.
- AOP 기능을 사용하기 위해 의존 관계를 추가 (intellij + gradle + AOP)
implementation group: 'org.aspectj', name: 'aspectjweaver', version: '1.8.13'
public interface Calculator {
public long factorial(long num);
}
public class RecCalculator implements Calculator {
@Override
public long factorial(long num) {
long start = System.currentTimeMillis();
try {
if (num == 0)
return 1;
else
return num * factorial(num - 1);
}finally {
long end = System.currentTimeMillis();
System.out.printf("RecCalculator(%d) 실행시간 %d \n",num,(end-start));
//start와 end 시간을 구해서 차이를 구하면 된다.
}
}
}
import chap07.test.RecCalculator;
public class Main {
public static void main(String[] args) {
RecCalculator ttCal1 = new RecCalculator( );
ttCal1.factorial(3);
}
}
위의 코드에서 보면 재귀 구현 함수의 실행 시간을 출력하고 싶으면, start시점과 end시점의 시간을 구해서 차이를 알면된다. 하지만, 위의 코드에 출력문을 넣으면 메시지가 반복으로 출력되는 문제가 있다.
[결과]
프록시(Proxy)
- 핵심 기능의 실행은 다른 객체가 하고, 부가적인 기능만을 제공하는 객체
- 핵심 기능은 구현하지 않으며 대신 여러 객체에 공통으로 적용할 수 있는 기능을 구현
public class ExeTimeCalculator implements Calculator {
private Calculator delegate;
public ExeTimeCalculator(Calculator delegate) {
this.delegate = delegate;
}
@Override
public long factorial(long num) {
long start = System.nanoTime();
long result = delegate.factorial(num);
long end = System.nanoTime();
System.out.printf("(%d) 실행 시간 = %d\n",
delegate.getClass().getSimpleName(),
num, (end - start));
return result;
}
}
public class Main2 {
public static void main(String[] args) {
ExeTimeCalculator ttCal1 = new ExeTimeCalculator(new ImpeCalculator());
System.out.println(ttCal1.factorial(20));
ExeTimeCalculator ttCal2 = new ExeTimeCalculator(new RecCalculator());
System.out.println(ttCal2.factorial(20));
}
}
[결과]
위 코드는 ExeTimeCalulator클래스에서 ImpleCalculator 객체, RecCalculator객체를 상속받아 실행한다.
- Proxy : ExeTimeCalulator에서는 부가적인 기능 (실행시간 측정) 실행
- 대상객체 : 핵심 기능의 실행은(factorial()기능)은 ImpleCalculator , RecCalculator 객체에서 실행
AOP
AOP는 핵심 기능의 코드를 수정하지 않으면서 공통 기능의 구현을 추가하는 것이다.
- 컴파일 시점에 코드에 공통 기능을 삽입
- 클래스 로딩 시점에 바이트 코드에 공통 기능을 삽입
- 런타임에 프록시 객체를 생성해서 공통 기능을 삽입 (스프링이 제공하는 방식)
AOP 주요 용어
- Aspect : 여러 객체에 공통으로 적용되는 기능 (트랙잭션, 보안 등)
- Advice : 언제 공통 관심 기능을 핵심 로직에 적용할지 정의
- Before Advice : 대상 객체의 메서드 호출 전에 공통 기능 호출
- After Returning Advice : 대상 객체의 메서드가 익셉션 없이 실행된 이후에 공통 기능을 실행
- After Throwing Advice : 대상 객체의 메서드를 실행하는 도중 익셉션이 발생한 경우 공통 기능 실행
- After Advice : 익셉션 발생 여부에 상관없이 실행 후 공통 기능 실행
- Arount Advice : 대상 객체의 메서드 실행 전, 후 또는 익셉션 발생 시점에 공통 기능 실행
- Joinpoint: Advice를 적용 가능한 지점
- Pointcut : Joinpont의 부분 집합, 실제 Advice가 적용되는 Joinpoint
- Weaving: Advice를 핵심 로직 코드에 적용하는 것
@Aspect //Advice와 Pontcut을 함께 제공
public class ExeTimeAspect {
@Pointcut("execution(public * chap07..*(..))") //공통 기능을 적용할 대상
private void publicTarget() {
}
@Around("publicTarget()") //공통 기능을 적용한다는 것을 의미, publicTarget메서드는 @Around가 붙은 measure()메서드를 적용한다.
public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {// ProceedingJoinPoint 파라미터는 프록시 대상 객체의 메서드를 호출할 때 사용
long start = System.nanoTime();
try {
Object result = joinPoint.proceed();
return result;
} finally {
long finish = System.nanoTime();
Signature sig = joinPoint.getSignature();
System.out.printf("%s.%s(%s) 실행 시간 : %d ns\n",
joinPoint.getTarget().getClass().getSimpleName(),
sig.getName(), Arrays.toString(joinPoint.getArgs()),
(finish - start));
}
}
}
@Configuration
@EnableAspectJAutoProxy // @Aspect를 공통 기능으로 적용하기 위해 설정 클래스에 필요함
public class AppCtx {
@Bean
public ExeTimeAspect exeTimeAspect() {
return new ExeTimeAspect();
}
@Bean
public Calculator calculator() {
return new RecCalculator();
}
}
public class MainAspect {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppCtx.class);
Calculator cal = ctx.getBean("calculator", Calculator.class);
long fiveFact = cal.factorial(5);
System.out.println("cal.factorial(5) = " + fiveFact);
System.out.println(cal.getClass().getName());
ctx.close();
}
}
AOP를 구현하는 코드를 작성 후 돌려보면,
REFERENCE
초보 웹 개발자를 위한 스프링 5 프로그래밍 입문(최범균)
'공부 > Spring' 카테고리의 다른 글
[Spring] Chapter 9-10장 Intellij에서 스프링 MVC 시작하기(Spring+ Gradle + MVC) (3) | 2021.07.11 |
---|---|
[Spring] Chapter 08 - DB 연동(MySQL + Gradle + JDBC) (0) | 2021.07.03 |
[Spring] Chapter 06 - 빈라이클사이클과 범위 (0) | 2021.06.13 |
[Spring] Chapter 05 - 컴포넌트 스캔 (0) | 2021.06.13 |
[Spring] Chapter 04 - 의존 자동 주입 (0) | 2021.06.13 |