AOP 는 Aspect-oriendted Programming의 약자로 흩어진 Aspect를 모듈화 할 수 있는 프로그래밍 기법을 뜻하며, OOP를 보완하는 수단으로 사용된다.
AOP 개념 AOP 주요 개념
Aspect
관점 지향적으로 모듈화된 모듈
Advice와 Pointcut을 담고 있음
Target
Advice
Pointcut
Join point
Target에 Advice가 실행되는 여러가지 합류 지점
생성자 호출직전, 생성자 호출이후, 필드에 접근하기전, 필드에서 값을 가져갔을 때 등
AOP 구현체
AOP 적용 방법
컴파일
자바 파일을 클래스 파일로 만들때 조작된 바이트 코드를 생성하여 적용
로드 타임
JVM이 클래스를 로딩하는 시점에 추가하여 로딩(로드 타임 위빙)
런타임
JVM이 클래스를 로딩한 후 Bean을 생성할 때 해당 클래스의 프록시빈을 생성하여 적용
스프링 AOP: 프록시 기반 AOP 스프링 AOP 특징
프록시 기반의 AOP 구현체
스프링 빈에만 AOP를 적용 가능
모든 AOP 기능을 제공하는 것이 목적이 아니라, 스프링 IoC와 연동하여 엔터프라이즈 애플리케이션에서 가장 흔한 문제에 대한 해결책을 제공하는 것이 목적.
프록시 패턴 AOP 기존 코드 변경 없이 접근 제어 또는 부가 기능 추가하기 위해 프록시 패턴을 사용하여 AOP 구현
1 2 3 public interface EventService { void createEvent () ; }
1 2 3 4 5 6 7 8 9 10 11 12 @Service public class SimpleEventService implements EventService { @Override public void createEvent () { try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Create an event" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Primary @Service public class ProxySimpleEventService implements EventService { @Autowired SimpleEventService simpleEventService; @Override public void createEvent () { long begin = System.currentTimeMillis(); simpleEventService.createEvent(); System.out.println(System.currentTimeMillis() - begin); } }
1 2 3 4 5 6 7 8 9 10 11 @Component public class AppRunner implements ApplicationRunner { @Autowired EventService eventService; @Override public void run (ApplicationArguments args) throws Exception { eventService.createEvent(); } }
매번 프록시 클래스를 정의 해야하고 객체의 관계도 복잡한 문제 발생
스프링 AOP: @AOP 스프링 IoC 컨테이너가 제공하는 기반 시설과 Dynamic 프록시를 사용하여 여러 복잡한 문제 해결
동적 프록시: 동적으로 프록시 객체 생성하는 방법
자바가 제공하는 방법은 인터페이스 기반 프록시 생성.
CGlib은 클래스 기반 프록시도 지원.
스프링 IoC: 기존 빈을 대체하는 동적 프록시 빈을 만들어 등록
클라이언트 코드 변경 없음.
AbstractAutoProxyCreator implements BeanPostProcessor
애노테이션 기반의 스프링 @AOP
spring-boot-starter-aop
의존성 추가하여 사용 가능
1 2 3 4 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
애스팩트 정의
@Aspect 모듈 정의
빈으로 등록을 위해 (컴포넌트 스캔을 사용한다면) @Component 추가
포인트컷 정의
@Pointcut(표현식)
주요 표현식
execution
@annotation
bean
포인트컷 조합 가능 - &&, ||, !
어드바이스 정의
@Before
@AfterReturning
@AfterThrowing
@Around
1 2 3 4 5 @Documented @Target (ElementType.METHOD)@Retention (RetentionPolicy.CLASS)public @interface PerfLogging {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @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; } @Before ("bean(simpleEventService)" ) public void hello () { System.out.println("Hello" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Service public class SimpleEventService implements EventService { @PerfLogging @Override public void createEvent () { try { Thread.sleep(1000 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Create an event" ); } @Override public void deleteEvent () { System.out.println("Delete an event" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 @Component public class AppRunner implements ApplicationRunner { @Autowired EventService eventService; @Override public void run (ApplicationArguments args) throws Exception { eventService.createEvent(); eventService.deleteEvent(); } }
1 2 3 4 5 6 7 출력: Hello Create an event 1003 Hello Delete an event
Contributors