
cglib의 사용
다음과 같이 스프링, 하이버네이트 에도 Enhacer 클래스 내부에도 내장되어 있다.

pom.xml 추가
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
Enhancer의 활용
BookService bookService = (BookService) Enhancer.create(BookService.class, handler);
MethodInterceptor를 활용하여 handler 생성
MethodInterceptor handler = new MethodInterceptor() {
BookService bookService = new BookService();
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return method.invoke(bookService, args);
}
};
https://github.com/cglib/cglib/wiki
cglib/cglib
cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept f...
github.com
ByteBuddy의 활용
Proxy 클래스 생성 : ByteBuddy를 활용하여 BookService의 subClass를 만든다.
Class<? extends BookService> proxyClass = new ByteBuddy().subclass(BookService.class)
.make().load(BookService.class.getClassLoader()).getLoaded();
Proxy클래스의 인스턴스 생성
BookService bookService = proxyClass.getConstructor(null).newInstance();

특정 작업을 하고 싶을 때(with InvocationHandlerAdapter)
Class<? extends BookService> proxyClass = new ByteBuddy().subclass(BookService.class)
/*********************************************
* 여기에
* 특정 작업을 진행 한다.
*********************************************/
.make().load(BookService.class.getClassLoader()).getLoaded();
BookService bookService = proxyClass.getConstructor(null).newInstance();
- 가공하고 싶은 method를 intercept 하여 자바의 프록시패턴과 유사하게 InvocationHandler()를 활용한다.
- return으로 invoke(instance, 인자)를 리턴한다.
- return 하기 이전에 특정 작업을 실행하고 싶다면 invoke 전후로 작업을 수행하면 된다.
(아래 코드의 aaaaa , bbbbb 출력과 같이)
Class<? extends BookService> proxyClass = new ByteBuddy().subclass(BookService.class)
.method(named("rent")).intercept(InvocationHandlerAdapter.of(new InvocationHandler() {
BookService bookService = new BookService();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("aaaaa");
Object invoke = method.invoke(bookService,args);
System.out.println("bbbbb");
return invoke;
}
}))
.make().load(BookService.class.getClassLoader()).getLoaded();

문제점
상속을 활용하는 방법이기 때문에 특정한 면에서는 제한이 따른다.
가령
1. 상수를 사용하는 경우
public final class BookService {
public void rent(Book book) {
System.out.println("rent : "+book.getTitle());
}
public void returnBook(Book book) {
System.out.println("returnBook : "+book.getTitle());
}
}

2. 생성자의 접근제어자가 private 한 경우
public class BookService {
private BookService() {
}
public void rent(Book book) {
System.out.println("rent : "+book.getTitle());
}
public void returnBook(Book book) {
System.out.println("returnBook : "+book.getTitle());
}
}

subClass를 만들 때 부모인 BookService의 디폴트 생성자의 접근제어자가 private으로 되어있다면
자식의 인스턴스가 생성될 때 부모의 인스턴스도 같이 올라가게 되는데 부모의 디폴트 생성자가 private이라면 부모의 인스턴스를 생성할 수 없기에 에러가 발생하는 것이다.
서브 클래스를 만드는 방법의 단점
-
상속을 사용하지 못하는 경우 프록시를 만들 수 없다.
-
Private 생성자만 있는 경우
-
Final 클래스인 경우
-
인터페이스가 있을 때는 인터페이스의 프록시를 만들어 사용할 것.
Code Link
https://github.com/mike6321/PURE_JAVA/tree/master/TheJava/proxy-pattern
mike6321/PURE_JAVA
Contribute to mike6321/PURE_JAVA development by creating an account on GitHub.
github.com
'Java > Java' 카테고리의 다른 글
(JAVA) 쓰레드의 개요 (1) (0) | 2020.01.19 |
---|---|
(JAVA) 애노테이션 프로세서 (0) | 2019.12.28 |
(JAVA) 다이나믹 프록시 (0) | 2019.12.24 |
(JAVA) 프록시 패턴 (0) | 2019.12.24 |
(JAVA) 리플렉션 API(4) - 나만의 DI 프레임워크 만들어보기 (0) | 2019.12.24 |