created at 2024-05-17
Table of contents
Spring Proxy
- Proxy = 대리자
- Spring 에서 프록시는 매우 많은 곳에서 사용
- AOP 로 로직 감싸서 처리한는 부분.
- Lazy Initialization
- Security
- Transaction Management
- 등등
예를 들어서 이런식임.
class UserService(
private val userRepository: UserRepository
) {
fun save(user: User) {
userRepository.save(user)
}
}
UserRepository 가 interface 라면, UserService 는 Proxy 객체가 매핑. 그리고 이 프록시 객체는 UserRepository 인터페이스를 구현한 클래스와 연결됨. 즉, interface
-> proxy
-> impl class 객체
이런식으로 매핑시켜주는 녀석이 Proxy 임.
그리고 이런 인터페이스를 기반으로한 프록시 구현방식을 JDK Dynamic Proxy 라고 함. 클래스 기반의 방식인 CGLIB 도 있음.
- JDK Dynamic Proxy
- 설정: proxyTargetClass = false 또는 인터페이스를 상속받은 경우 자동으로 사용
- 작동 방식: 인터페이스를 상속받아 프록시 객체를 생성합니다. 인터페이스를 구현한 클래스를 대상으로 합니다.
- CGLIB Proxy
- 설정: proxyTargetClass = true
- 작동 방식: 인터페이스가 아닌 클래스를 상속받아 프록시 객체를 생성합니다. 이를 통해 인터페이스가 없는 클래스도 프록시를 통해 DI 및 AOP 기능을 사용할 수 있습니다.
- interface -> abstract class -> impl class
nGrinder 는 이런식으로 구조를 잡고 설계되어 있음. 좀 더 유연하고 안전하게 사용할 수 있기 때문이죠.
좀 더 유연하고 안전하게 사용할 수 있기 때문이죠. 그래서 저도 이런식으로 구조잡고 진행했더니! 실제 객체가 매핑되지 않고 프록시 객체가 매핑되는 경우가 있었습니다.
여기서 Spring 이 프록시 객체를 매핑하는 방법은 두 가지가 있습니다.
interface -> abstract class -> @Service extended class
이런 경우에는 CGLIB Proxy 가 사용되어야하죠
하지만, spring 에서는 interface 를 상속받는 클래스의 구현체와 프록시가 매핑됩니다.
@Service
public class UserServiceImpl implements UserService {
@Override
public void save(User user) {
System.out.println("save user");
}
}