> For the complete documentation index, see [llms.txt](https://leehyokyun.gitbook.io/openbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://leehyokyun.gitbook.io/openbook/2-3.-proxy.md).

# 2-3. Proxy

공통 관심사에 기반한 보일러 플레이트 제거, 호출 과정의 일관화와 효율화 : 프록시에 대하여

### 1. Spring AOP 관점에서의 프록시 객체 생성 목적과 두 가지 핵심 방식

* Spring AOP는 프록시(Proxy) 기반의 AOP 구조로 작동하며, 대상 메서드의 호출 시점에 동적으로 개입하여 프록시 객체를 생성하고 부가 기능을 수행한다.
* 프록시 객체를 생성하는 가장 대표적인 방법은 클래스 기반의 CGLIB Proxy 방식과 인터페이스 기반의 JDK Dynamic Proxy 방식 두 가지로 분류된다.

### 2. JDK Dynamic Proxy의 구동 메커니즘과 자바 표준 구현 코드

* JDK Dynamic Proxy는 개발자가 정의한 인터페이스를 기반으로, JVM 측에서 런타임 시점에 인터페이스 구현체를 동적으로 직접 만들어 주는 방식이다. 이는 자바 JDK에서 기본으로 제공하는 프록시 생성 체계다.
* 구현 메커니즘 및 표준 자바 코드 구조: Client > MyService proxy = (MyService)&#x20;

  ```
  Proxy.newProxyInstance( classLoader, new Class[]{MyService.class}, (proxyInstance, method, args) 
  -> 
  { System.out.println("before"); 
    Object result = method.invoke(target, args); 
    System.out.println("after"); return result; 
  } );
  ```
* 위 연산 흐름과 같이 클라이언트가 프록시의 메서드를 호출(invoke)하면 인터페이스 명세에 맞춰 내부적으로 InvocationHandler가 동작하며, 타깃 객체(Target Object)의 실제 메서드 실행 전후에 공통 관심사 로직을 주입하고 결과를 반환한다. 인터페이스가 필연적으로 존재해야만 프록시 객체를 대리로 생성할 수 있다는 제약 조건을 가진다.

### 3. CGLIB(Code Generator Library) Proxy의 작동 원리와 확장성

* CGLIB Proxy는 대상 클래스를 직접 상속(extends)받은 자식 클래스를 런타임에 동적으로 바이트 코드를 생성하여 프록시 객체로 빌드하는 방식이다.
* 작동 특성 및 장점: 부모 클래스의 메서드를 오버라이드하여 인터셉트하는 형태로 구동되기 때문에, JDK Dynamic Proxy와 달리 별도의 인터페이스가 존재하지 않는 일반 구체 클래스만으로도 프록시 객체를 완벽하게 대리 생성할 수 있다는 강력한 확장성을 지닌다.
* 한계점 및 비용: 구체 클래스를 동적으로 상속받아 바이트 코드를 가공하고 오버라이딩해야 하므로 프록시 객체 생성 및 연산 처리 시 상대적으로 무거운 연산 비용이 동반된다는 특징을 가진다.

### 4. ApplicationContext 초기화 시점과 프록시 객체의 대리 등록 역할

* Spring 프레임워크가 구동되면서 ApplicationContext 시작 연산이 발동하는 시점에는 컴포넌트 스캔을 통해 수많은 빈(Bean) 객체들이 컨텍스트에 등록되고 의존성 주입이 수행된다.
* 시점상의 딜레마와 해결 매커니즘: 만약 특정 배치 단계나 구체적인 실행 스텝(Step) 등이 컨텍스트 초기화 시점에는 아직 물리적으로 실행되지 않아서 실제 대상 빈 객체가 메모리에 존재하지 않음에도 불구하고, 다른 컴포넌트나 리더 빈(Reader Bean)에서 해당 객체를 의존성 주입으로 강력히 요구하는 상황이 발생할 수 있다.
* 프록시의 대리 역할: 대상 객체가 아직 가동되거나 존재하지 않는 모호한 시점이라도, Spring AOP는 해당 자리에 CGLIB 또는 JDK Dynamic 방식을 활용하여 껍데기뿐인 가짜 프록시 객체를 대리로 먼저 생성하여 의존성 주입 통로에 안전하게 채워 넣는다.
* 지연 로딩과 실행: 초기화 단계의 에러를 원천 차단하고 컨텍스트를 성공적으로 빌드 완료한 뒤, 향후 실제 메서드가 호출되는 정확한 런타임 시점에 비로소 타깃 인스턴스를 찾아 실제 로직(Advice)을 실행하고 공통 관심사를 처리하는 구조로 작동한다.

### 5. Spring AOP 동작의 핵심은 Proxy이다.

* AOP와 Transactional에 기술한 Advisor(\*어디에(Pointcut) 어떤 공통 관심사(Advice)를 실행할지)들의 결합 = 단일 AOP Proxy에 연결하여 Interceptor Chain으로 구성한다.
* 실행흐름은Interceptor Chain에 구성하는 순서에 따라 구성, 구성내역에 따라 실행하는 로직(Advice)의 순서 결정.

```
                  Spring Container
                        │
                        │ Bean 생성
                        ↓
                OrderService 객체
                        │
                        │ @Transactional
                        │ @DbAdmission
                        ↓
             ┌──────────────────────┐
             │ Spring AOP Proxy     │
             │                      │
             │ Interceptor Chain    │
             │                      │
             │ ① DbAdmissionAspect  │
             │ ② Transaction        │
             │    Interceptor       │
             │                      │
             └──────────┬───────────┘
                        │
                        ↓
                OrderService target
                        │
                        ↓
                   update()
```

Spring AOP가 Container 생성 시점에 Pointcut, Advice를 참고하여, 이들을 실행할 Proxy 생성 및 Interceptor Chain 구성하는것(\* 일반 AOP = Interceptor, @Transactional = TransactionInterceptor).<br>

### 6. Spring AOP의 Interceptor Chain(Proxy의 Multi-AOP 진행)

* @Transactional의 핵심은 포인트컷에 트랜잭션의 시작과 commit을 통해 원자성을 확보하는 것.
  * 다만, 해당 트랜잭션을무조건 삽입하는 것은 아니고, Spring AOP가 Advisor 검토 후 해당 TransactionInterceptor를 Proxy 등록

```
if (@Transactional) {
    transaction.begin();
    update();  // -> Service logics
    transaction.commit();
}
```

```
@Transactional 
> TransactionAttributeSource 
> "이 메서드는 Transactional인가?" 
> TransactionAttributeSourceAdvisor
>  TransactionInterceptor
>  AOP Proxy의 interceptor chain에 등록 
```

TransactionAttributeSourceAdvisor를 통해 Interceptor Chain에 해당 Advice를 등록하고 트랜잭션을 진행하는 것(=즉, Proxy 내부적으로 관심사 진행 후 Service logic를 진행)

* Customized Aspect도 유사한 원리로 동작한다.
  * @Around > Pointcut > "@DbAdmission이 붙은 메서드인가?" > Advice > DbAdmissionAspect.admission()&#x20;
  * Pointcut을 통해 메서드에 해당 Aspect가 붙으면, Spring AOP 측이 감지 후 Interceptor/advisor 형태로 등록.

```
@Transactional
      ↓
TransactionInterceptor

@DbAdmission
      ↓
DbAdmissionAspect interceptor
```

즉, InterCeptor/Advisor가 AOP Interceptor Chain에 등록되어 연쇄 구성, 이로 인해 공통관심사가 다수 실행할 수 있는 것이다.

```
return joinPoint.proceed();
```

이는 단순히 "원래 메소드를 호출한다"가 아닌, AOP에 등록된 다음의 Interceptor 로직을 실행하는 것이다(=advice). 즉, AOP Interceptor(Advice) 실행 후, 트랜잭션을 실행(begin) (\*2개 AOP 등록시).

* AOP Advisor 실행 후 재귀에 의해 역순으로 실행(돌아간다).

<br>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://leehyokyun.gitbook.io/openbook/2-3.-proxy.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
