public class UserClassService { void join(User user) { System.out.println("join = " + user); } void terminate(User user) { System.out.println("terminate = " + user); }}
Java
복사
1. cglib 를 이용하는 방법
dependencies { // https://mvnrepository.com/artifact/cglib/cglib implementation 'cglib:cglib:3.3.0'}
Groovy
복사
@Testvoid cglib() { MethodInterceptor handler = new MethodInterceptor() { private final UserClassService userClassService = new UserClassService(); @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if (method.getName().equals("terminate")) { System.out.println("proxy start"); Object invoke = method.invoke(userClassService, args); System.out.println("proxy end"); return invoke; } return method.invoke(userClassService, args); } }; UserClassService userClassService = (UserClassService) Enhancer.create(UserClassService.class, handler); userClassService.join(user); userClassService.terminate(user); //join = User@6f306067 //proxy start //terminate = User@6f306067 //proxy end}
Java
복사
2. byteBuddy library를 이용하는 방법
dependencies { implementation 'net.bytebuddy:byte-buddy:1.14.0'}
Groovy
복사
@Testvoid byteBuddy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class<? extends UserClassService> proxyClass = new ByteBuddy() .subclass(UserClassService.class) .method(named("terminate")) .intercept(InvocationHandlerAdapter.of(new InvocationHandler() { UserClassService userClassService = new UserClassService(); @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { System.out.println("proxy start"); Object invoke = method.invoke(userClassService, args); System.out.println("proxy end"); return invoke; } })) .make() .load(UserClassService.class.getClassLoader()) .getLoaded(); UserClassService userClassService = proxyClass.getConstructor(null).newInstance(); userClassService.join(user); userClassService.terminate(user);}
Java
복사
3. 한계
•
위의 두 방식 모두 대상 클래스의 서브 클래스를 프록시로 만들어 사용하는 방법이라서 대상 클래스가 상속을 막아놓은 경우 사용할 수 없다.
◦
final 클래스인 경우
◦
private 생성자만 존재하는 경우
•
interface 가 존재하면 interface 를 통해서 구현하는 것이 확장성과 유연성 면에서 좋다. 따라서 인터페이스가 존재하면 인터페이스의 프록시를 만들어 사용하자.
//1. final 로 상속을 막은 경우//public final class UserClassService {public class UserClassService { //2. private 생성자로 상속을 막은 경우 //private UserClassService() { } void join(User user) { System.out.println("join = " + user); } void terminate(User user) { System.out.println("terminate = " + user); }}
Java
복사