본문 바로가기
Backend/Spring

[Spring] Proxies in JPA

by Everyday Sustler 2023. 5. 30.
반응형

Proxy?

 

JPA를 공부하다보면 Proxy 라는 단어를 많이 접하게 됩니다.

 

내가 알고있는 프록시와 어떤 것이 다를까 찾아보다가 재미있는 표현을 찾았습니다.

 

한 Article의 저자는 바로 마법같은 일로 개발자의 생산성을 폭발시키는 이것이 바로 프록시이다, 라고 합니다.

 

It's very common to refer to some Spring features as "magic". How else could you add functionality like caching at the method level with nothing but a single annotation? Magic!
- Christopher Anatalio in medium.com -

 

스프링의 프록시는 Proxy Design Pattern의 구현이며 스프링은 이를 통해 Aspect-Oriented Programming (AOP)를 지원합니다.

 

프록시의 장점은 아래와 같이 정리할 수 있습니다.

  • 객체 접근을 제어하는 대리자 역할을 제공합니다.
  • 실제 컴포넌트가 Logging 과 같은 cross-cutting logic 에 의해 복잡해지는 것을 방지하는 Wrapper 역할을 합니다.
  • 분산, 제어, 수정된 접근을 위한 간접성을 제공합니다.
  • 생성 비용이 큰 객체의 대체로서 사용되어 지연 생성을 가능하게 합니다.
  • 보안된 객체에 접근하기 전에 권한을 확인하는데 사용할 수 있습니다.
  • 객체에 액세스 할 때 Logging, Caching, Transaction Management 등과 같은 추가 기능을 주입할 수 있습니다.
  • 서비스에 영향 없이 프록시를 교체할 수 있기 때문에 Open/Close Principle 을 만족할 수 있습니다.

그럼 다양한 장점을 가진 프록시 패턴의 실제 예시를 살펴보겠습니다.

 

Credit Card 객체는 Payment 인터페이스를 사용하는 클라이언트의 프록시

사용자는 가지고 있는 Cash에 직접 접근해 사용할 수 있지만, CreditCard 객체 역시 이용할 수 있습니다.

 

CreditCard 내부에는 포인트, 거래 기록, 보안 코드 등 부가적인 정보가 기록될 수 있습니다.

 

아래는 이를 조금 더 정형화 한 프록시 패턴의 구조입니다.

 

프록시 패턴의 구조

 

Proxy in Spring

 

스프링에서 프록시는 두 가지 방법으로 제공됩니다.

 

하나는 JDK Dynamic Proxies, 다른 하나는 CGLIB(Code Generation Library) 입니다.

 

먼저 JdkDynamicAopProxy.class 소스 코드를 보면 아래와 같이 선언되어 있습니다.

 

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

 

AopProxy, InvocationHandler, Serializable 인터페이스를 구현하는 구현체임을 알 수 있습니다.

 

그리고 상단의 주석으로부터 아래와 같은 설명도 읽어볼 수 있습니다.

 

JDK-based AopProxy implementation for the Spring AOP framework, based on JDK java.lang.reflect.Proxy dynamic proxies.

Creates a dynamic proxy, implementing the interfaces exposed by the AopProxy. Dynamic proxies cannot be used to proxy methods defined in classes, rather than interfaces.

Objects of this type should be obtained through proxy factories, configured by an AdvisedSupport class. This class is internal to Spring's AOP framework and need not be used directly by client code.

Proxies created using this class will be thread-safe if the underlying (target) class is thread-safe. Proxies are serializable so long as all Advisors (including Advices and Pointcuts) and the TargetSource are serializable.

 

먼저 "Dynamic proxies cannot be used to proxy methods defined in classes, rather than interface" 를 보면 동적 프록시는 인터페이스가 아닌 클래스에 정의된 메서드를 프록시화 할 수 없음을 알 수 있습니다.

 

또한, 이렇게 만들어진 Object은 AdvisedSupport 클래스에 의해 구성되는 프록시 팩토리에 반드시 관리되어야 한다고 합니다.

 

JdkDynamicAopProxy Source Code

소스 코드 안에서 프록시 객체를 동적으로 생성하는 부분이 있습니다.

 

그러나 java.lang.reflect.* 라이브러리를 사용하는 부분이 많아 이해가 어려웠습니다.

 

그래서 상세한 분석 대신 대강의 흐름을 나열해보면 아래와 같습니다.

  • 프록시에 감싸진 method 호출(invoked)합니다.
  • 호출된 프록시와 호출된 메소드, 메소드 매개변수를 invoke() 메소드에 전달합니다.
  • 모든 프록시 로직이 정의된 Interception chain 을 반환 받습니다.
  • 반환된 MethodInterceptors 를 통해 모든 프록시 행위를 수행한 뒤 실제 대상 클래스의 비즈니스 로직을 수행합니다.
  • 이 후, 결과는 다시 프록시로 반환됩니다.

이 과정은 아래 레퍼런스의 Proxy 설명에서 GIF 그림으로 자세히 설명되어 있습니다.

 

Conclusion

장황하게 글을 썼지만 결론은 간단합니다.

 

스프링에서 Annotation 을 통한 기능 추가 과정에서는 Proxy Design Pattern을 사용한다.

 

이러한 프록시 객체는 생성 조건이 있어 의도하지 않은 에러를 발생시키는 원인이 될 수 있다.

 

따라서 프록시 관련 에러라면 프록시를 생성하는 부분에서 의도하지 않은 동작이 발생했을 수 있음을 인지하고 디버깅을 해보면 좋을 것 같습니다.

 

References

 

Proxy

There are dozens of ways to utilize the Proxy pattern. Let’s go over the most popular uses. Access control (protection proxy). This is when you want only specific clients to be able to use the service object; for instance, when your objects are crucial p

refactoring.guru

 

Spring Dependency Injection Demystified Part 1: Proxying

Spring features can be“magic.” How else could you add functionality like caching at the method level with…

medium.com

 

GitHub - spring-projects/spring-framework: Spring Framework

Spring Framework. Contribute to spring-projects/spring-framework development by creating an account on GitHub.

github.com

 

반응형

'Backend > Spring' 카테고리의 다른 글

[Spring] 예외처리는 곧 유비무환  (1) 2023.12.26