반응형
클래스 기반의 다이나믹 프록시
자바에서 기본으로 제공하는 Proxy를 통해서는 클래스 기반의 프록시를 생성할 수 없다.
다만 서브 클래스를 만들 수 있는 라이브러리를 사용하여 프록시를 만들 수 있다.
public class CarService {
public void rent(Book book) {
System.out.println("rent: " + book.getTitle());
}
public void returnBook(Book book) {
System.out.println("return: " + book.getTitle());
}
}
CGlib
- 스프링, 하이버네이트 등에서도 사용하는 라이브러리
- 버전 호환성이 좋지 않아서 서로 다른 라이브러리 내부에 내장된 형태로 제공되기도 한다.
- 스프링에서 의존성을 따로 추가하지 않고도 CGlib의 Enhancer 클래스 사용가능.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
1. 클래스의 다이나믹 프록시 생성 방법(CGlib)
@Test
public void cglibDi(){
//핸들러를 메소드 인터셉터로 생성.
MethodInterceptor handler = new MethodInterceptor() {
CarService carService = new CarService();
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if(method.getName().equals("rent")){
System.out.println("aaaa");
Object invoke = method.invoke(carService, args);
System.out.println("bbbb");
return invoke;
}
return method.invoke(carService, args);
}
};
//프록시 객체의 메소드가 호출될 때마다 부가적으로 어떤일을 처리해야하는지에 대한 핸들러를 넘겨준다.
CarService carService = (CarService) Enhancer.create(CarService.class, handler);
Book book = new Book();
book.setTitle("spring");
carService.rent(book);
carService.returnBook(book);
}
ByteBuddy
- 스프링은 ByteBuddy의 버전관리를 해주기 때문에 따로 의존성에 버전 명시안해줘도 된다.
- 바이트 코드 조작뿐 아니라 런타임(다이나믹) 프록시를 만들 때도 사용할 수 있다.
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.11.1</version>
</dependency>
2. 클래스의 다이나믹 프록시 생성 방법(Bytebuddy)
@Test
public void bytebuddyDi() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//ByteBuddy에서 특정 메소드 호출 시, 부가적인 기능 수행하도록 처리(rent라는 이름의 메서드는 가로채서 부가적인 기능 수행)
Class<? extends CarService> proxyClass2 = new ByteBuddy().subclass(CarService.class)
.method(named("rent")).intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
CarService carService = new CarService();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("aaaa");
Object invoke = method.invoke(carService, args);
System.out.println("bbbb");
return invoke;
}
}))
.make().load(CarService.class.getClassLoader()).getLoaded();
CarService carService = proxyClass2.getConstructor(null).newInstance();
Book book = new Book();
book.setTitle("spring");
carService.rent(book);
carService.returnBook(book);
}
서브 클래스를 만드는 방법의 단점
클래스
상속을 사용하지 못하는 경우 프록시를 만들 수 없다.- Private 생성자만 있는 경우
- Final 클래스인 경우
- 인터페이스가 있을 때는 인터페이스의 프록시를 만들어 사용하자
[참고자료]
Interface MethodInterceptor - cglib
반응형
'Java > 기본' 카테고리의 다른 글
자바 람다(Java Lambda) - 1 (함수형 인터페이스, 람다 표현식) (0) | 2021.06.15 |
---|---|
자바 애노테이션 프로세서(Java Annotation Processor) (0) | 2021.06.03 |
자바 다이나믹 프록시(Java Dynamic Proxy) - 1 (0) | 2021.05.31 |
자바 리플렉션(Java Reflection) API - 클래스 정보 수정 및 실행 (0) | 2021.05.30 |
자바 리플렉션(Java Reflection) API - 애노테이션 정보 조회 (0) | 2021.05.29 |