Both sides previous revisionPrevious revisionNext revision | Previous revision |
back-end:spring [2022/06/18 17:25] – [Weaving] ledyx | back-end:spring [2024/10/14 01:35] (current) – [Lifecycle Callbacks] ledyx |
---|
</sxh> | </sxh> |
| |
* 메서드를 구현하고 @PostConstruct, @PostDestroy 사용. (Java 표준) => 추천! | * 메서드를 구현하고 @PostConstruct, @PreDestroy 사용. (Java 표준) => 추천! |
| |
| |
* 원하는 관심사의 유지보수가 수월한 코드를 구성할 수 있다. | * 원하는 관심사의 유지보수가 수월한 코드를 구성할 수 있다. |
* 높은 응집도(같은 목적의 Logic 모여있는 정도)를 위해 사용. | * 높은 응집도(같은 목적의 Logic 모여있는 정도)를 위해 사용. |
| * **Spring AOP는 AspectJ 라이브러리의 어노테이션 인터페이스만 사용하고, 동적 런타임중에 Proxy를 생성하는 방식을 이용한다.** |
| |
| |
client-- request -->ProxyFactory | client-- request -->ProxyFactory |
ProxyFactory-- Proxy 대상 객체가 Interface를 구현 O -->p1[JDK dynamic proxy] | ProxyFactory-- Proxy 대상 객체가 Interface를 구현 O -->p1[JDK dynamic proxy] |
ProxyFactory-- Proxy 대상 객체가 Interface를 구현 X -->p2[CGLIB proxy] | ProxyFactory-- Proxy 대상 객체가 Interface를 구현 X<br>Target Class를 상속 -->p2[CGLIB proxy] |
p1-- "call" -->a["Advice\n(추상화)"] | p1-- "call" -->a["Advice\n(추상화)"] |
p2-- "call" -->a["Advice\n(추상화)"] | p2-- "call" -->a["Advice\n(추상화)"] |
* [[#Pointcut]] 대상/후보라고도 한다. | * [[#Pointcut]] 대상/후보라고도 한다. |
| |
==== Pointcut ==== | === Pointcut === |
* Filtering 된 [[#Joinpoint]]. | * Filtering 된 [[#Joinpoint]]. |
* 수많은 Business Method 중에서 원하는 특정 Method에서만 [[#Cross-cutting Concern | 횡단 관심]]에 해당하는 공통 기능 수행. | * 수많은 Business Method 중에서 원하는 특정 Method에서만 [[#Cross-cutting Concern | 횡단 관심]]에 해당하는 공통 기능 수행. |
* **Advice가 적용될 __<fc red>위치</fc>__, __<fc red>Filter Logic</fc>__** | * **Advice가 적용될 __<fc red>위치</fc>__, __<fc red>Filter Logic</fc>__** |
| |
| ==== Pointcut Designators ==== |
| |
| [[https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-pointcuts-designators|Supported Pointcut Designators]] |
| |
| Spring AOP 에서 지원하는 Pointcut Designator(PCD)는 아래와 같다. |
| |
| * execution : Method 실행 join points를 matching. Spring AOP로 작업할 때 가장 우선적인 PCD이다. |
| * declaring-type-pattern에서 부모 타입 가능 |
| * param-pattern에서 부모 타입 불가능 |
| |
| * within : 특정 Type에 join points 적용. |
| * 부모 타입 불가능. 정확히 맞아야 한다. |
| * target : target 객체(Spring AOP Porxy가 적용되는 __실제 객체__)를 대상으로 하는 join points 적용 |
| * 부모 타입 가능. |
| * this : Spring 빈 객체(Spring AOP __Proxy__)를 대상 |
| * 부모 타입 가능. |
| |
| * args : 인자가 주어진 타입의 인스턴스 한정 |
| * 부모 타입 가능 |
| |
| |
| * @target : Annotation이 있는 Type에서 부모 타입을 허용하여 모든 Method에 join points 적용 |
| * @within : Annotation이 있는 Type 내에 있는 Method에 join points 적용. (부모 타입 불가) |
| |
| * @args : 전달된 실제 arguments의 Runtime type이 주어진 Type의 Annotation이 있는 Join points 적용 |
| * 부모 타입 허용 |
| * @annotation : Method가 주어진 Annotation을 갖고 있는 Join points 적용. |
| |
| <note important> |
| **args, @args, @target**는 단독으로 사용하면 안된다! |
| 이 PCD들은 인스턴스가 만들어진 후 Runtime 시점에서 동작한다. |
| 그러므로 단독으로 사용하면 모든 스프링 빈에 AOP를 적용하려고 시도한다. |
| 이 때, 스프링 내부에서 사용하는 빈 중에 'final'로 지정된 빈이 있어서 오류가 발생한다. |
| </note> |
| |
| ===== execution ===== |
| |
| * [[https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-pointcuts-examples|Official]] |
| *[[https://www.baeldung.com/spring-aop-pointcut-tutorial|Baeldang]] |
| |
| * Pattern |
| * **<nowiki>*</nowiki>** : 1개 |
| * **..** : 0..n개 |
| |
| <code> |
| execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)) |
| </code> |
| |
| <sxh java ; gutter:false> |
| execution(public app.domain.Member app.repository.Repository.findById(String)) |
| |
| // - modifiers-pattern : public |
| // - ret-type-pattern : app.domain.Member |
| // - declaring-type-pattern : app.repository.Repository |
| // - name-pattern : findById |
| // - param-pattern : String |
| </sxh> |
| |
| |
=== Advice === | === Advice === |
* [[#Cross-cutting Concern | 횡단 관심]]에 해당하는 공통 기능의 Code. 독립된 Class의 Method로 작성되는 **__<fc red>부가 기능 Logic</fc>__** | * [[#Cross-cutting Concern | 횡단 관심]]에 해당하는 공통 기능의 Code. 독립된 Class의 Method로 작성되는 **__<fc red>부가 기능 Logic</fc>__** |
* 해당 기능이 **언제 동작할 지** 스프링 설정 파일에서 지정한다. | * 해당 기능이 **언제 동작할 지** 스프링 설정 파일에서 지정한다. |
| |
=== Weaving === | ==== 종류 ==== |
* [[#Pointcut]]으로 지정한 핵심 관심 Method가 호출될 때,\\ [[#Advice]]에 해당하는 [[#Cross-cutting Concern | 횡단 관심]] Method가 **삽입되는 과정** | |
* 컴파일 시점. ".class" 파일의 바이트코드를 수정. 별도의 Aspectj 컴파일러 필요 | * 전체. 첫 번째 인자가 [[https://www.eclipse.org/aspectj/doc/next/runtime-api/org/aspectj/lang/ProceedingJoinPoint.html|ProceedingJoinPoint]]이어야 한다. 그리고 이 인자의 "proceed()"가 호출되어야 그 다음 흐름 제어가 가능하다. |
* 클래스 로딩 시점. ".class" 파일의 바이트코드를 조작하여 로딩. 'java -javaagent' 옵션 필요 | * @Around |
* 런타임 시점. Proxy 객체 구현 필요 | * 부분적. 첫 번째 인자가 [[https://www.eclipse.org/aspectj/doc/next/runtime-api/org/aspectj/lang/JoinPoint.html|JoinPoint]]이어야 한다. "proceed()"가 자동으로 호출된다. |
* 스프링에서 사용하는 방식. 즉, Method 실행 시점에만 Advisor 동작. | * @Before : "proceed()" 실행 전 |
| * @AfterReturning : "proceed()" 실행 후 |
| * @AfterThrowing : 오류 발생 (try ~ catch의 catch) |
| * @After : 모든 작업 수행 후 실행 (try ~ catch의 finally) |
| |
| 실행 순서는 기술한 순서와 같다. |
| 만약 @Around 끼리 순서를 지정할 경우 @Order를 사용한다. 단. __<fc red>@Aspect 기반의</fc> **<fc red>Class</fc>**__만 작동한다! |
| |
| |
| |
=== Aspect & Advisor === | === Aspect & Advisor === |
| |
| <flow> |
| stateDiagram |
| state Aspect(Advisor) { |
| Pointcut |
| Advice |
| |
| } |
| </flow> |
| |
| |
* 하나의 [[#Pointcut]] + 하나의 [[#Advice]] | * 하나의 [[#Pointcut]] + 하나의 [[#Advice]] |
* [[#Pointcut]] Method에 **<fc red>필터링</fc>**되어 어떤 [[#Advice]] Method에 있는 **<fc red>부가 기능</fc>**을 실행할 지 결정. | * [[#Pointcut]] Method에 **<fc red>필터링</fc>**되어 어떤 [[#Advice]] Method에 있는 **<fc red>부가 기능</fc>**을 실행할 지 결정. |
* 차이점 | |
* Aspect : Advice 객체의 ID와 Method를 확인할 수 있을 때 사용. | 같은 개념으로, Advisor는 Spring AOP에서만 사용되는 개념 |
* Advisor : Advice 객체의 ID나 Method를 확인할 수 없을 때 사용. 대표적인 경우로 Transaction. | |
| |
| === Weaving === |
| * [[#Pointcut]]으로 지정한 핵심 관심 Method가 호출될 때,\\ [[#Advice]]에 해당하는 [[#Cross-cutting Concern | 횡단 관심]] Method가 **삽입되는 과정** |
| * Compile-Time Weaving : ".class" 파일의 바이트코드를 수정. 별도의 Aspectj 컴파일러 필요 |
| * Binary Weaving : ".class" 파일 혹은 jar 파일을 클래스 로딩시 바이트코드를 조작하여 로딩. 'java -javaagent' 옵션 필요 |
| * Runtime Weaving : Class가 JVM에 로드되기 직전에수행. Proxy 객체 구현 필요 |
| * 스프링에서 사용하는 방식. 즉, Method 실행 시점에만 Advisor 동작. Method는 static이 아니면서 public이어야 한다. |
| |
=== Core Concerns === | === Core Concerns === |