티스토리 뷰
스프링 AOP: @AOP
Spring AOP 구성
- SimpleEventService(Real Subject)가 Bean으로 등록된다
- BeanPostProcessor(Bean을 가공할 수 있는 LifeCycle 인터페이스)를 구현한 AbstractAutoProxyCreator로 Real Subject Bean을 감싸는 Proxy Bean을 만든다.
- 해당 Proxy Bean을 Real Subject Bean 대신에 등록을 해준다.
즉, Spring Boot로 인해 Proxy Bean을 동적으로 만들어주고, 구현한 Aspect가 Proxy 역할을 하는 것이다.
- Aspect내에서는 해야할 일(Advice)들을 개발자 재량에 따라 구현하면 되는 것이다.
그럼 이제 Spring Boot에서 제공하는 Proxy 기반의 Spring AOP를 적용해보자.
Spring AOP Dependency 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Aspect 추가
Aspect는 그림과 같이 해야할 일(Advice, 띠)와 어디에 적용할 것인지(PointCut, 각 객체 혹은 객체의 메소드(A,B,C))가 필요하다.
Aspect 적용을 소스로 살펴보자
@Component
@Aspect
public class PerfAspect {
//Advice가 적용되는 대상(createEvent, publishEvent 메소드 자체라고 생각하면 됨)
//즉, 메소드를 감싸고 있다고 생각하면 됨.
//타겟의 메소드를 호출하고 결과값을 리턴
@Around("execution(* com.mesung..*.EventService.*(..))") //EventService 안에 있는 모든 메소드에 logPerf() 기능을 적용해라
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
Object retVal = pjp.proceed(); //해당 메소드
System.out.println(System.currentTimeMillis() - begin);
return retVal;
}
}
- @Aspect : 해당 클래스를 Aspect로 사용하겠다.
- @Around : 대상 객체의 메소드의 실행 전, 후 또는 에러 발생 처리가 가능하다.
- execution : 현재 소스에서는 com.mesung 패키지 밑에 Eventservice 객체 안에 있는 메소드들을 모두 적용하겠다라는 의미이다.
- @Around("bean(simpleEventService)") : simpleEventService bean에 있는 메소드들을 모두 적용하겠다.
실행결과
그런데 우리는 모든 메소드를 호출하는 것이 아니라 deleteEvent는 제외시키고 싶은데, deleteEvent가 나타나는 것을 확인할 수 있다.
이 때는 애노테이션을 만들어서 활용하자
//perfLogging 애노테이션
/*
* 메소드 성능 시간을 측정한다.
* */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PerfLogging {
}
//SimpleEventService(Real Subject)
@PerfLogging
@Override
public void createEvent() {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Created an event");
}
@PerfLogging
@Override
public void publishEvent() {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Published an event");
}
@Override
public void deleteEvent() {
System.out.println("Delete an event");
}
//PerfAspect
@Component
@Aspect
public class PerfAspect {
@Around("@annotation(PerfLogging)")
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
Object retVal = pjp.proceed(); //해당 메소드
System.out.println(System.currentTimeMillis() - begin);
return retVal;
}
}
기동되는 순서는 다음과 같다.
-
AppRunner를 통해 SimpleEventService 각 메소드들을 실행하는데 각 메소드에 붙여진 애노테이션을 확인한다.
-
@PerfLogging 애노테이션의 정보를 확인한다.
-
정보 확인 후 Spring AOP이 적용된 것을 런타임 시점에 확인 후 해당 @Asepct의 정보를 확인한다.
-
확인 결과, logPerf()는 Advice인 @Around를 통해 @PerfLogging이 붙여진 클래스 혹은 메소드에 해당 로직을 적용한다.
-
@PerfLogging이 붙여진 SimpleEventService의 createEvent()와 PublishEvent()만 성능 시간을 나타낸 것을 확인할 수 있다.
-
실행결과
각 애노테이션들을 살펴보자
@Retention(RetentionPolicy.CLASS)
public @interface PerfLogging {
}
여기서 살펴보면 @Retention이라는 애노테이션을 사용하는데, @Retention은 해당 애노테이션 정보를 얼마나 유지시킬 것인지를 나타내는 것이다.
- RetentionPolicy.CLASS는 .class(클래스 파일)까지 유지하겠다라는 것이고, 이것이 기본값이다.
- 해당 객체는 바이트코드까지 남아 있는다.
- @Retention을 사용할 때는 클래스 파일 이상 유지시켜야 한다.
- RetentionPolicy.SOURCE
- 컴파일하고 사라진다.
- RetentionPolicy.RUNTIME
- 런타임까지 살아있는 것인데, 굳이 여기까지 사용하지는 않아도 된다.
- @Documented와 @Target을 사용하는 좋다.(Java에서 제공하는 애노테이션)
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface PerfLoggin {
}
//@Documented : Java Doc 만들 때 Documentation이 될 수 있도록 한다.
//@Target(ElementType.METHOD) : AOP 형태로 만들어 줄 것이 메소드 형태다라는 것을 알려준다.
또 다른 Advice
-
@Before : 어떤 메소드가 실행되기 이전에 작업을 하겠다.
@Before("bean(simpleEventService)") public void hello() { System.out.println("hello"); }
-
@AfterReturning
-
@AfterThrowing
-
@Around
'Spring > Spring 핵심' 카테고리의 다른 글
[스프링 핵심] 스프링 AOP: 프록시 기반 AOP (0) | 2020.02.03 |
---|---|
[스프링 핵심] 스프링 AOP: 개념 소개 (0) | 2020.01.30 |
[스프링 핵심] Validation 추상화 (0) | 2020.01.17 |
[스프링 핵심] Resource 추상화 (0) | 2020.01.17 |
[스프링 핵심] ResourceLoader (0) | 2019.12.29 |
- Total
- Today
- Yesterday
- java
- 이펙티브자바
- 팩토리 메소드 패턴
- package-private
- 연관관계
- flatMap
- Effective Java
- mustache
- 인프런
- junit
- 점층적 생성 패턴
- 생성자
- java8
- jdk버전
- 자바8
- 빈 순환 참조
- 김영한
- 빌더 패턴
- Spring
- @Lazy
- ifPresent
- try catch finally
- effectivejava
- JPA
- 스프링부트
- 정적팩터리메서드
- springboot
- try with resources
- 복사 팩토리
- 이펙티브 자바
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |