Java動態代理可以通過以下幾種方式實現:
java.lang.reflect.Proxy
類:Proxy
類提供了一個靜態方法newProxyInstance()
,可以通過傳入目標對象的類加載器、目標對象實現的接口和InvocationHandler
接口的實現類來創建代理對象。InvocationHandler
接口的實現類負責處理代理對象的方法調用。代理對象在調用方法時,會把方法調用轉發給InvocationHandler
的invoke()
方法,從而實現代理功能。public interface Subject {
void doSomething();
}
public class RealSubject implements Subject {
public void doSomething() {
System.out.println("RealSubject doSomething");
}
}
public class MyInvocationHandler implements InvocationHandler {
private Subject target;
public MyInvocationHandler(Subject target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method invoke");
Object result = method.invoke(target, args);
System.out.println("After method invoke");
return result;
}
}
public class Main {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxySubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new MyInvocationHandler(realSubject));
proxySubject.doSomething();
}
}
CGLib
庫:CGLib
是一個基于ASM
框架的字節碼生成庫,它可以在運行時動態生成目標對象的子類,并覆蓋其中的方法以實現代理功能。public interface Subject {
void doSomething();
}
public class RealSubject implements Subject {
public void doSomething() {
System.out.println("RealSubject doSomething");
}
}
public class MyMethodInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invoke");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method invoke");
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new MyMethodInterceptor());
Subject proxySubject = (Subject) enhancer.create();
proxySubject.doSomething();
}
}
需要注意的是,使用CGLib
實現動態代理時,目標對象不能是final
類或者包含final
方法,因為CGLib
是通過生成目標對象的子類來實現代理的。
ByteBuddy
庫:ByteBuddy
是一個輕量級的字節碼操作庫,它可以在運行時動態生成目標對象的子類,并覆蓋其中的方法以實現代理功能。public interface Subject {
void doSomething();
}
public class RealSubject implements Subject {
public void doSomething() {
System.out.println("RealSubject doSomething");
}
}
public class MyInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method invoke");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method invoke");
return result;
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<? extends Subject> proxyClass = new ByteBuddy()
.subclass(Subject.class)
.method(any()).intercept(MethodDelegation.to(MyInterceptor.class))
.make()
.load(RealSubject.class.getClassLoader())
.getLoaded();
Subject proxySubject = proxyClass.getDeclaredConstructor().newInstance();
proxySubject.doSomething();
}
}
需要注意的是,使用ByteBuddy
實現動態代理時,需要引入net.bytebuddy:byte-buddy
和net.bytebuddy:byte-buddy-agent
兩個依賴。