天天看點

Spring代理模式

代理有靜态代理、動态代理和cglib代理

靜态代理:1.目标類必須實作一個接口,比如dao層的先寫一個接口,再寫一個接口的dao實作類,靜态代理就是對這個實作類進行代理

                 2. 必須實作和目标對象(需要代理的類的對象)一樣的接口,就是這個目标對象實作了什麼接口,靜态代理類就必須實作什麼接口

弊端:如果目标類方法太多豈不是所有的方法都要寫一下?太麻煩

靜态代理

public class UserDaoProxy implements IUserDao{

    // 接收儲存目标對象

    private IUserDao target;

    public UserDaoProxy(IUserDao target) {

        this.target = target;

    }

    @Override

    public void save() {

        System.out.println("開始事務...");

        target.save();             // 執行目标對象的方法

        System.out.println("送出事務...");

}

動态代理:1.和靜态代理一樣也是目标類必須實作接口

                  2.代理類不用必須實作和目标類一樣的接口,是一個方法,給裡面有三個參數,有一個參數是要指定目标類實作接口的類型,(注意指明的是實作接口的類型)

動态代理

public class ProxyFactory {

    // 維護一個目标對象

    private Object target;

    public ProxyFactory(Object target){

    // 給目标對象,生成代理對象  

    public Object getProxyInstance() {

        return Proxy.newProxyInstance(

                target.getClass().getClassLoader(), 

                target.getClass().getInterfaces(),

                new InvocationHandler() {

                    @Override

                    public Object invoke(Object proxy, Method method, Object[] args)

                            throws Throwable {

                        System.out.println("開啟事務");

                        // 執行目标對象方法

                        Object returnValue = method.invoke(target, args);

                        System.out.println("送出事務");

                        return returnValue;

                    }

                });

cglib代理:1.目标類沒有實作的接口,是以子類的形式代理!

                   2.如果你又不想像靜态代理那樣實作相同的接口重寫所有的方法,也不想像動态代理那種指明接口類型或者說目标對象根本沒有實作接口

                   3.用cglib的方法可以實作,兩個方法,看下面代碼。

                    4.使用cglib代理的話是需要導包的,cglib.jar,但是spring-core.jar包中裡面有引入這個cglib.jar的包,也就是導了spring的包就可以用了。

cglib代理

public class ProxyFactory implements MethodInterceptor{

    // 維護目标對象

    // 給目标對象建立代理對象

    public Object getProxyInstance(){

        //1. 工具類

        Enhancer en = new Enhancer();

        //2. 設定父類

        en.setSuperclass(target.getClass());

        //3. 設定回調函數

        en.setCallback(this);

        //4. 建立子類(代理對象)

        return en.create();

    public Object intercept(Object obj, Method method, Object[] args,

            MethodProxy proxy) throws Throwable {

        System.out.println("開始事務.....");

        // 執行目标對象的方法

        Object returnValue = method.invoke(target, args);

        System.out.println("送出事務.....");

        return returnValue;

spring中的代理模式:根據目标對象是否有實作接口動态的選擇代理的模式。

                                    1.如果目标類有實作的接口就使用動态代理

                                    2.如果目标類沒有實作的接口就使用cglib代理

 為什麼上層向下層提供的是接口支援,而不是具體的實作類?

  這裡面涉及到spring中的事務管理,是aop方式,aop又涉及到代理,代理分為三種,靜态、動态、cglib代理。

  具體三種代理的差別和實作上面展示了

  這裡值得一說的是如果你用動态代理需要告訴spring一個被代理類的父類對象,動态代理是以目标類子類的形式代理;

  如果使用cglib代理被代理類是要繼承接口的。

  換個角度看,如果你的dao或者service層寫了接口定義方法,實體類是實作這個接口,那麼spring就給你采用cglib代理,

  如果你的dao或者service層是直接寫實作類,那麼spring就給你采用jdk動态代理

  是以寫代碼時要細心點,比如說如果你寫具體實作類是實作接口,spring給你采用cglib代理,

  你糊塗的在下層調用和注入的時候是直接用實作類,

  那麼是會報錯的,因為你告訴spring用cglib代理,而你在下層用的時候用jdk動态代理,肯定沖突啊。