《設計模式》1 代理模式

參考博客: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是通過繼承實現類定義。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章