參考博客:https://blog.csdn.net/luanlouis/article/details/24589193
1 代理模式的作用
(1)中介作用:通過中介訪問實際對象,並且中介可以在實際業務前後進行業務處理;
(2)延遲加載。
2 靜態代理:(1)代理類持有委託類引用(2)代理類和委託類共同實現一個接口(也可以不實現)
// 公共接口
public interface CoustomerI {
void buy();
}
// 委託類
public class CarCustomer implements CoustomerI{
public CarCustomer(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void buy() {
System.out.println(this.name + " buy a car");
}
}
// 代理類
public class CarCustomerProxy implements CoustomerI{
private CarCustomer carCustomer;
public CarCustomerProxy(CarCustomer carCustomer) {
this.carCustomer = carCustomer;
}
@Override
public void buy() {
if (null == carCustomer) {
return;
}
// proxy do something before real business logic
carCustomer.buy();
// proxy do something after real business logic
}
}
// 單元測試
public class ProxyMain {
@Test
public void testStaticProxy() {
CarCustomer carCustomer = new CarCustomer("WangXin");
CarCustomerProxy carCustomerProxy = new CarCustomerProxy(carCustomer);
carCustomerProxy.buy();
}
}
打印結果:
3 動態代理:動態代理的意思是動態生成代理類,避免過多的代理類造成代碼的臃腫。動態代理的實現分爲2種,通過接口實現動態代理,通過繼承實現動態代理。
3.1 通過接口實現動態代理:JDK原生的代理,整個執行過程是:
3.1.1 獲取委託類的接口類的Class和ClassLoader,新加回調方法的實現類InvocationHandler,通過接口Class和ClassLoader動態生成代理類並加載到JVM中,並返回代理類對象
3.1.2 通過返回的代理類對象訪問方法
3.1.3 生成的代理類中的方法調用的是InvocationHandler中的invoke方法,所以我們在面向切面編程的邏輯就卸載invoke方法裏面
// 公共接口
public interface Vehicle {
void drive();
}
// 公共接口
public interface Rechargable {
public void recharge();
}
// 委託類(被代理類)
public class ElectricCar implements Vehicle,Rechargable{
@Override
public void drive() {
System.out.println("drive");
}
@Override
public void recharge() {
System.out.println("recharge");
}
}
// invoke實現類
public class InvocationHandlerImpl implements InvocationHandler{
private ElectricCar car;
public InvocationHandlerImpl(ElectricCar car) {
this.car = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before method invoke.the method is :" + method.getName());
method.invoke(car, null);
System.out.println("after method invoke.the method is :" + method.getName());
return null;
}
}
// 單元測試
public class JDKProxyTest {
@Test
public void testJDKProxy() {
ElectricCar car = new ElectricCar();
ClassLoader classLoader = car.getClass().getClassLoader();
Class[] interfaces = car.getClass().getInterfaces();
InvocationHandler handler = new InvocationHandlerImpl(car);
Object o = Proxy.newProxyInstance(classLoader, interfaces, handler);
Vehicle vehicle = (Vehicle) o;
vehicle.drive();
Rechargable rechargeable = (Rechargable) o;
rechargeable.recharge();
}
}
實際的效果:
PS:生成的代理類Object o的方法就是調用了invoke方法,沒有別的。
3.2 通過繼承實現動態代理:cglib
cglib創建代理類的過程
3.2.1 用Enhancer通過superClass和MehtodInterceptor生成字節碼,然後加載到jvm中去
3.2.2 用生成的代理類調用接口方法,實際上最後也是調用MehtodInterceptor的方法
// 委託類(被代理類)
public class Programmer {
public void code() {
System.out.println("just code");
}
}
// 代理類
public class ProgrammerMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("before method " + method.getName() + " invoke");
proxy.invokeSuper(obj, args);
System.out.println("after method " + method.getName() + " invoke");
return null;
}
}
// 測試類
public class CglibTest {
@Test
public void testCblib() {
ProgrammerMethodInterceptor pmi = new ProgrammerMethodInterceptor();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Programmer.class);
enhancer.setCallback(pmi);
Programmer proxy = (Programmer) enhancer.create();
proxy.code();
}
}
總結:JDK的動態代理和cglib代理本質上都是根據反射獲取類定義,根據類定義生成字節碼,然後加載到jvm中,最後通過代理類調用(強制類型轉換),實際上是調用回調方法。區別是JDK代理是通過接口的方式實現類定義,cblib是通過繼承實現類定義。