Jdk 動態(tài)代理
Jdk動態(tài)代理薯鳍,利用反射挪鹏,實現(xiàn) InvocationHandler 接口。Jdk 動態(tài)代理需要實現(xiàn)類通過接口定義業(yè)務方法郁副,也就是說,委托類必須實現(xiàn)一個定義了業(yè)務方法的接口豌习,在接口里約定需要代理的方法存谎,并且只能對接口里約定的方法實現(xiàn)代理。由于需要委托類實現(xiàn)一個接口斑鸦,這是一個局限性愕贡。
Jdk 代理類圖
- Subject 類
public interface Subject {
void doSomething();
}
- RealSubject 類
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("do something");
}
}
- Jdk 代理
public class JdkProxy implements InvocationHandler {
private Object target;
public JdkProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
System.out.println("jdk proxy before");
result = method.invoke(target, args);
System.out.println("jdk proxy after");
return result;
}
}
- Jdk 代理測試
public class JdkProxyTest {
@Test
public void testJdkProxy() {
RealSubject realSubject = new RealSubject();
Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new JdkProxy(realSubject));
subject.doSomething();
}
}
運行結(jié)果:
jdk proxy before
do something
jdk proxy after
Cglib 動態(tài)代理
Cglib 代理是針對類來實現(xiàn)代理的,并不要求委托類必須實現(xiàn)接口巷屿,它的原理是對指定的目標類生成一個子類固以,并覆蓋其中方法實現(xiàn)增強,采用的是繼承的方式嘱巾。由于是采用繼承的方式憨琳,所以用 Cglib 實現(xiàn)的代理類是不能處理被final關鍵字修飾的方法的。
Cglib 代理類圖
- Cglib 代理
public class CglibProxy implements MethodInterceptor {
public Object getInstance(Class clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result;
System.out.println("cglib proxy before");
result = methodProxy.invokeSuper(o, objects);
System.out.println("cglib proxy after");
return result;
}
}
在上文中可以看到旬昭,代理對象的生成過程是由 Enhancer 類來實現(xiàn)的篙螟,大概步驟是:
- 生成代理類 Class 的二進制字節(jié)碼;
- 通過 Class.forName 加載二進制字節(jié)碼问拘,生成Class對象遍略;
- 通過反射機制獲取實例構(gòu)造惧所,并初始化代理類對象。
intercept() 方法攔截目標類方法的調(diào)用绪杏,o 表示目標類的實例下愈,method 為目標類方法的反射對象,objects 為方法的動態(tài)入?yún)⒗倬茫琺ethodProxy 為代理類實例势似。
- Cglib 代理測試
public class CglibProxyTest {
@Test
public void testCglibProxy() {
RealSubject realSubject = (RealSubject) new CglibProxy().getInstance(RealSubject.class);
realSubject.doSomething();
}
}
運行結(jié)果:
cglib proxy before
do something
cglib proxy after