AOP : 핵심 기능과 공통 기능의 구현을 분리함으로써 핵심 기능을 구현한 코드의 수정 없이 공통 기능을 적용할 수 있게 해주는 기법입니다.
AOP 공통 기능 삽입 방법 3가지
1. 컴파일 시점에 코드에 공통 기능 삽입
2. 클래스 로딩 시점에 바이트 코드에 공통 기능 삽입
3. 런타임에 프록시 객체를 생성하여 공통 기능 삽입
스프링에서는 3번 방법을 사용하고 자동으로 프록시 객체를 생성합니다.
AOP를 설정하는데 필요한 어노테이션을 사용하기 위해 aspectjweaver모듈을 추가하고 aop는 spring-aop모듈이 제공하며 spring-context에 의존되어져 있으므로 추가해줄 필요가 없습니다.
공통기능 객체 : 핵심 기능의 실행은 다른 객체에 위임하고 부가적인 기능을 제공하는 객체
대상 객체 : 실제 핵심 기능을 수행하는 객체
=> 중복되는 부분을 공통 기능 객체로 만들고 중복 되지 않는 부분을 핵심 기능 객체로 만들어 두 객체를 합쳐 원래의 목적을 달성합니다.
프록시 : 핵심 기능의 실행은 다른 객체에 위임하고 부가적인 기능을 제공하는 객체로써 스프링에서 자동으로 생성해 줍니다. 스프링은 프록시를 생성할 때 호출한 핵심기능의 객체와 동일한 인터페이스를 구현하여 생성하므로 getBean시 프록시 객체를 받기 때문에 인터페이스를 구현한 클래스의 객체 타입으로 객체를 받으면 익셉션이 발생하게 됩니다. 이를 해결하기 위해 설정 클래스에서 @EnableAspectJAutoProxy 어노테이션을 지정할 때 속성으로 proxyTargetClass = true 로 지정하면 인터페이스가 아닌 클래스로 프록시를 생성하여 해결이 가능하지만 다형성을 위해 잘 사용되지 않는다.
프록시와 데코레이터 차이
프록시는 접근 제어 관점에 초점이 맞춰져 있고 데코레이터는 기능 추가와 확장에 초점이 맞춰져 있습니다.
프록시의 작동 방식
사용자가 대상 객체를 사용하러 들어오면 스프링이 프록시로 변경하고 프록시는 공통 기능 객체를 호출하고 공통 기능 객체는 내부적으로 대상 객체를 호출하도록 하는데 이때 대상 객체는 의존 주입에 따라 다르며 코드가 섞여서 실행이 된다.
AOP의 용어
*Advice : 어느 시점에 공통기능을 적용할 지 나타낸 것을 의미합니다.
- Before Advice : 대상 객체 메소드 호출 전에 공통 기능 수행
- After Returning Advice : 대상 객체 메소드가 익셉션 없이 실행된 이후에 공통 기능 수행
- After Throwing Advice : 대상 객체 메소드가 실행 도중 익셉션이 발생한 경우 공통 기능 수행
- Atfer Advice : 익셉션 발생 여부 상관 없이 메소드 실행 후 공통 기능 수행
- Around Advice : 다양한 시점에서 공통 기능 수행 (가장 많이 사용)
*Joinpoint : 현재 어떤 핵심 기능 객체가 연결되어 있는지 나타낸 것을 의미합니다.
*Pointcut : 핵심 기능 객체를 나타낸 Joinpoint의 집단을 의미합니다.
*Aspect : 여러 객체에 공통으로 적용되는 공통 기능을 의미합니다.
*Weaving : 핵심 기능 코드에 공통 기능 코드가 섞여서 동작하는 것을 의미합니다.
먼저 공통 기능을 담당하는 객체에 @Aspect 어노테이션을 붙여줍니다. @Aspect 어노테이션이 붙은 클래스들은 설정 클래스에 Bean 객체로 등록이 되어져야 합니다.
그런다음 @Pointcut 어노테이션을 이용하여 공통 기능을 적용할 대상들을 정의하는데 이때 속성에 excution 명시자로 어떤 메소드가 사용될 때 공통 기능이 적용 되는지를 나타냅니다.
execution 기본 형식
execution(수식어패턴? 리턴타입패턴 클래스이름패턴? 메소드이름패턴(파라미터패턴))
=>?가 붙은 패턴은 생략이 가능하며 *으로 모든 값을 표현할 수 있고 ..을 이용해 0개 이상이라는 의미를 표현할 수 있습니다.
@Around 어노테이션의 속성에 execution을 지정하면 Advice에서만 사용이 가능하며 private 메소드에 @Pointcut 어노테이션을 지정하고 속성에 execution을 지정하면 같은 클래스에서 여러 Advice가 사용될 수 있으며 public 메소드에 @Pointcut 어노테이션을 지정하고 속성에 execution을 지정하면 다른 클래스에서도 사용이 가능합니다. 이때 패키지.클래스.메소드로 Advice 속성값을 줍니다. 또한 여러 Aspect에서 공통으로 사용하는 Pointcut이 있다면 별도의 클래스에 Pointcut을 지정하여 사용합니다. 이때는 해당 클래스를 Bean으로 등록할 필요가 없습니다.
공통기능으로 제공할 메소드를 구현한 뒤 공통 기능 메소드에 @Around 어노테이션을 주어Advice를 지정합니다. 이때 속성값으로 Pointcut을 지정한 메소드를 속성값으로 주어 해당 메소드가 실행될 때 공통 기능을 제공하게 합니다. 또한 @Around가 지정된 메소드의 파라미터의 ProceedingJoinPoint 타입의 파라미터는 실제 Joinpoint에 해당되며 프록시 대상 객체의 메소드 즉 핵심 기능 메소드를 호출 할 때 사용됩니다. 이 파라미터의 메소드를 이용해 핵심 기능 메소드를 호출하고 이 메소드의 호출 이전과 이후에 공통 기능을 구현하는 코드를 작성하빈다.
ProceedingJoinPoint는 현재 동작하는 핵심 객체의 정보들을 모두 가지고 있으며 메소드의 정보, 대상 핵심 객체, 파라미터 목록 등을 getSignature(), getTarget(), getArgs()로 확인할 수 있습니다.
설정 클래스에서는 @EnableAspectJAutoProxy 어노테이션을 지정해야 @Aspect 어노테이션이 지정된 Bean객체를 찾아 사용할 수 있습니다.
@Enable로 시작하는 어노테이션들은 관련 기능을 적용하는데 필요한 다양한 설정을 한번에 처리해 줍니다.
여러 Aspect객체가 등록되어져 있으면 등록된 순서에 맞춰 공통기능이 실행되고 첫번째 공통 기능에서 핵심 기능을 호출하면 Joinpoint의 대상은 그 다음 공통 기능 프록시 객체가 되고 마지막 공통 기능 프록시 호출이 되면 여기서 핵심 기능을 호출합니다. 이때 공통 기능의 순서는 @Aspect 어노테이션을 지정할 때 @Order 어노테이션을 사용하여 지정하며 1이 가장 먼저 수행됩니다.
사진 출처 : 가메출판사 - 스프링 5 - 최범균
'학습(구) > Spring 요약' 카테고리의 다른 글
Spring - MVC (0) | 2020.10.19 |
---|---|
Spring - DB (0) | 2020.10.19 |
Spring - Bean라이프사이클과 스코프 (0) | 2020.10.16 |
Spring - 자동 Bean 등록 (0) | 2020.10.16 |
Spring - 자동 의존 주입 (0) | 2020.10.15 |