CGLIB子類代理和JDK動態代理示例和比較

Cglib代理,也叫作子類代理。在內存中構建一個子類對象從而實現對目標對象功能的擴展。java

比較:spring

      JDK的動態代理有一個限制,就是使用動態代理的對象必須實現一個或多個接口。若是想代理沒有實現接口的類,就能夠使用CGLIB實現。編程

      CGLIB是一個強大的高性能的代碼生成包,它能夠在運行期擴展Java類與實現Java接口。它普遍的被許多AOP的框架使用,例如Spring AOP和dynaop,爲他們提供方法的interception(攔截)。markdown

       CGLIB包的底層是經過使用一個小而快的字節碼處理框架ASM,來轉換字節碼並生成新的類。不鼓勵直接使用ASM,由於它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉。框架

Cglib子類代理:ide

         1)須要引入cglib – jar文件,可是spring的核心包中已經包括了cglib功能,因此直接添加spring-core的依賴便可工具

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.10.RELEASE</version>
        </dependency>

         2)引入功能包後,就能夠在內存中動態構建子類性能

         3)代理的類不能爲final, 不然報錯。測試

         4) 目標對象的方法若是爲final/static,那麼就不會被攔截,即不會執行目標對象額外的業務方法。this

在Spring的AOP編程中,

         若是加入容器的目標對象有實現接口,用JDK代理;

         若是目標對象沒有實現接口,用Cglib代理;

下面開始CGLIB代理的示例

先寫一個UserDao

package xin.sun.proxy.cglib;

/**
 * @author Ginkgo
 */
public class UserDao {

    public void save() {
        System.out.println("UserDao . save");
    }
}

再寫一個代理工廠ProxyFactory,實現CGLIB中的MethodInterceptor接口

package xin.sun.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author Ginkgo
 */
public class ProxyFactory implements MethodInterceptor {

    /**
     * 被代理對象
     */
    private Object target;

    /**
     * 構造器
     *
     * @param target
     */
    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 獲取代理對象實例
     *
     * @return Object 代理對象實例
     */
    public Object getProxyInstance() {

        /**
         * 工具類
         */
        Enhancer enhancer = new Enhancer();
        /**
         * 設置父類
         */
        enhancer.setSuperclass(target.getClass());
        /**
         * 設置回調對象
         */
        enhancer.setCallback(this);
        /**
         * 建立子類代理對象,並返回
         */
        return enhancer.create();
    }

    /**
     * 重寫攔截方法
     *
     * @param o           代理對象
     * @param method      委託類方法
     * @param objects     方法參數
     * @param methodProxy 代理方法的MethodProxy對象
     * @return Object 目標方法執行結果
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

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

        /**
         * 方法執行結果
         */
        Object result = method.invoke(target,objects);

        System.out.println("結束事務...");

        return result;
    }
}

再寫一個入口類Portal來測試

package xin.sun.proxy.cglib;

/**
 * @author Ginkgo
 */
public class Portal {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new UserDao());
        UserDao proxyInstance = (UserDao) proxyFactory.getProxyInstance();
        proxyInstance.save();
    }
}

運行結果:

開始事務...
UserDao . save
結束事務...

而後再看看JDK動態代理

先寫一個接口IOrderDao和實現類OrderDaoImpl

package xin.sun.proxy.dynamic;

/**
 * @author Ginkgo
 */
public interface IOrderDao {

    /**
     * 保存對象
     *
     * @param obj
     */
    void save(Object obj);
}

-----------------------------------------------------------------------------------------------------

package xin.sun.proxy.dynamic;

/**
 * @author Ginkgo
 */
public class OrderDaoImpl implements IOrderDao {
    @Override
    public void save(Object obj) {
        System.out.println("OrderDaoImpl -> save " + obj);
    }
}

再寫一個代理工廠ProxyFactory,實現InvocationHandler接口

package xin.sun.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Ginkgo
 */
public class ProxyFactory implements InvocationHandler {

    /**
     * 被代理對象
     */
    private Object target;

    /**
     * 構造器
     *
     * @param target
     */
    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * desc:獲取代理對象
     *
     * @return java.lang.Object
     * @author Ginkgo
     */
    public Object getProxyInstance() {

        Object proxyInstance = Proxy
                .newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return proxyInstance;
    }

    /**
     * 重寫調用方法
     *
     * @param proxy
     * @param method
     * @param args
     * @return Object 方法執行結果
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

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

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

        System.out.println("結束事務 ...");

        return result;
    }
}

在寫一個Portal入口類測試一下

package xin.sun.proxy.dynamic;

/**
 * @author Ginkgo
 */
public class Portal {

    public static void main(String[] args) {

        ProxyFactory proxyFactory = new ProxyFactory(new OrderDaoImpl());
        IOrderDao proxyInstance = (IOrderDao) proxyFactory.getProxyInstance();
        proxyInstance.save("test");
    }
}

運行結果

開始事務 ...
OrderDaoImpl -> save test
結束事務 ...
相關文章
相關標籤/搜索