簡單瞭解spring中用到的代理模式


靜態代理:

1、代理對象和目標對象都要實現的   公共接口

2、代理對象持有目標對象引用,重寫構造方法,

3、實現共同的方法,代理對象增強行爲。


缺點:

代理角色固定,一次只能代理一個對象。



接口

public interface Marry {
    void marry();
}

目標對象

public class You implements Marry {
    public void marry() {
        System.out.println("sihai get marry");
    }
}

代理對象

public class MarryCompany implements Marry {
    private You you;
    public MarryCompany(You you) {
        this.you = you;
    }
    public void marry() {
        before();
        you.marry();
        after();
    }

    private void after() {
        System.out.println("get after work done");
    }

    private void before() {
        System.out.println("get ready for marry");
    }
}
測試

public class TestMarry {
    public static void main(String[] args) {
        You you = new You();
        MarryCompany marryCompany = new MarryCompany(you);
        marryCompany.marry();
    }
}

結果

get ready for marry
sihai get marry
get after work done

動態代理

根據需要通過反射機制在程序運行期動態的爲目標對象創建代理對象,代理的行爲可以代理多個方法,即滿足生產需要的同時又達到代碼的通用目的。

動態代理有兩種實現方法:JDK方式和cglib方式。
區別
jdk動態代理的目標對象必須有接口,且創建的代理對象也是需要轉化成接口類型去執行方法,達到增強目標對象行爲的目的。這個過程製作快,執行慢。
cglib動態代理以 繼承 來實現,主要解決沒有接口類的代理實現。 這個過程製作慢,執行快。

JDK動態代理:

接口Marry和目標對象You不變

動態代理類

/**
 * JDK動態代理:
 *  1. 目標對象要有接口,且最後創建的代理對象要轉換成此接口類型,來調用方
 *  2. 動態代理類實現InvocationHandler接口,持有目標對象引用,利用構造器動態傳入目標對象
 *  3. 使用proxy.newProxyInstance()來動態地創建代理對象
 *  4. 代理對象重寫invoke方法,利用反射調用目標對象的方法,同時增加行爲
 */
public class JDKHandler implements InvocationHandler {

    //目標對象引用
    private Object target;

    //構造器,可以動態傳入目標對象
    public JDKHandler(Object target) {
        this.target = target;
    }

    //創建代理對象
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    //利用反射機制調用目標對象的方法,並增強行爲
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target,args);
        after();
        return result;
    }

    private void after() {
        System.out.println("get after work done");
    }

    private void before() {
        System.out.println("get ready for marry");
    }
}
測試
public class MarryTest {
    public static void main(String[] args) {
        //動態代理類,利用構造器傳入目標對象        
	JDKHandler jdkHandler = new JDKHandler(new You());
//創建代理對象 Marry marryProxy = (Marry) jdkHandler.getProxy(); //代理對象調用方法,會增加目標對象的行爲 marryProxy.marry(); }}



cgib動態代理

目標對象無要求,最後創建的動態代理會轉換成此目標對象類型,去調用方法實現行爲增強。
/**
 * cglib動態代理
 * 1. 目標對象
 * 2. 實現MethodInterceptor接口,持有目標對象引用,利用構造器動態傳入目標對象
 * 3. 重寫intercept方法,實現行爲增強
 */
public class CglibInterceptor implements MethodInterceptor {
    //目標對象
    private Object target;
    //構造器
    public CglibInterceptor(Object target){
        this.target=target;
    }
    //動態創建代理對象
    public Object getProxy(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    //行爲增強
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        after();
        Object result = methodProxy.invoke(target,objects);
        return result;
    }

    private void after() {
        System.out.println("after");
    }

    private void before() {
        System.out.println("before");
    }
}

目標對象
public class Hello {
    public void print(){
        System.out.println("hello");
    }
}
測試
public class Test {
    public static void main(String[] args) {
        //動態代理類
        CglibInterceptor cglibInterceptor = new CglibInterceptor(new Hello());
        //創建代理,且需要轉換成目標對象類型
        Hello proxy = (Hello) cglibInterceptor.getProxy();
        //代理對象調用方法,行爲會得到增強
        proxy.print();
    }
}




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