在Spring中的相關介紹 https://blog.csdn.net/m0_37989980/article/details/104593905
具體什麼是靜態代理、動態代理這裏不贅述, 可以參考上面 !
一、靜態代理
/**
* Description: 傳統靜態代理的舉例
* <p>
* 特點: 代理類和被代理類在編譯期間, 就確定下來了
*
* @author zygui
* @date Created on 2020/6/18 15:12
*/
interface ClothFactory {
void produceCloth();
}
// 代理類
class ProxyClothFactory implements ClothFactory {
private ClothFactory factory; // 用被代理對象進行實例化(真實類)
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工廠準備一些工作...");
factory.produceCloth(); // 被代理類乾的事情
System.out.println("代理工廠做一些後續的收尾工作...");
}
}
// 被代理類
class NikeClothFactory implements ClothFactory {
@Override
public void produceCloth() {
System.out.println("Nike工廠生產一批運動服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
// 創建被代理對象
ClothFactory nike = new NikeClothFactory();
// 創建代理類對象
ClothFactory proxy = new ProxyClothFactory(nike);
// 代理類執行的工作,實際是被代理類乾的事情
proxy.produceCloth();
}
}
二、動態代理
想要實現動態代理, 需要解決的問題?
- 問題一: 如何根據加載到內存中被代理類, 動態的創建一個代理類及其對象
- 問題二: 當通過代理類的對象調用方法時, 如何動態的去調用被代理類中的同名方法
/**
* Description: 動態代理的舉例
*
* 代理類和被代理類要實現同一接口!
*
* @author zygui
* @date Created on 2020/6/18 15:39
*/
interface Human {
String getBelief();
void eat(String food);
}
// 被代理類
class SuperMan implements Human {
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜歡喫" + food);
}
}
/*
想要實現動態代理, 需要解決的問題?
問題一: 如何根據加載到內存中被代理類, 動態的創建一個代理類及其對象
問題二: 當通過代理類的對象調用方法時, 如何動態的去調用被代理類中的同名方法
*/
// 生產代理類的工廠
class ProxyFactory {
/**
* 調用此方法,通過傳遞過來的被代理類對象, 返回一個該被代理類對象的代理對象; 解決問題一
*
* @param obj 被代理類的對象
* @return
*/
public static Object getProxyInstance(Object obj) {
/*
// 用來創建代理類的方法
public static Object newProxyInstance(
ClassLoader loader, // 和被代理類使用同一加載器
Class<?>[] interfaces, // 因爲代理類和被代理類要實現同一接口, 這裏獲取被代理類所實現的接口, 供創建出來的代理類也實現這些接口
InvocationHandler h // 解決上面的問題二: 會去找下面的Invoke方法
)
也就是說, 創建的代理類對象去調用a方法時, 被代理類就會去handler裏面調用invoke方法
*/
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
class MyInvocationHandler implements InvocationHandler {
// 聲明一個被代理對象
private Object obj; // 賦值時, 也需要使用具體的被代理對象進行賦值
public void bind(Object obj) {
this.obj = obj;
}
// 當我們通過代理類對象,調用方法a時, 就會自動的調用如下的方法: invoke(), 在invoke方法中的參數Method就是代理類對象調用的方法對象
// 將被代理類要執行的方法a的功能就聲明在invoke()中了
@Override
/*
參數:
Object proxy : 代理類對象
Method method : 代理類調用的那個方法,這裏就是該方法
Object[] args : 代理類調用的那個方法中的參數
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method: 即爲 代理類對象調用的方法, 此方法也就作爲了 被代理類對象 要調用的方法
// 下面的invoke方法中的 參數1: 調用該方法的對象(這裏就是被代理類的對象), 參數2: 是調用該方法的參數
Object retrunValue = method.invoke(obj, args);
return retrunValue;
}
}
public class DynamicProxyTest {
public static void main(String[] args) {
// 被代理類對象
SuperMan superMan = new SuperMan();
// proxyInstance代理類對象(此時是superMan的代理對象)
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
// 通過代理類對象調用下面的方法, 就動態調用了被代理類中的同名方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("四川麻辣燙");
}
}
此時通過調用代理類中的方法, 就動態的調用的是被代理類中的同名方法了!