Java實現動態代理——基於子類cglib、基於接口proxy

動態代理

特點
字節碼隨用隨創建,隨用隨加載。
作用
不修改源碼的基礎上對方法增強。
分類
基於接口的動態代理
基於子類的動態代理

1.基於接口的動態代理

涉及的類:Proxy

提供者:JDK官方

要求:被代理對象最少實現一個接口,如果沒有則不能使用

創建代理對象:使用Proxy類中的newProxyInstance方法

  • newProxyInstance方法的參數
    • ClassLoader:類加載器
      • 用於加載代理對象字節碼的,和被代理對象使用相同的類加載器 固定寫法
    • Class[]:字節碼數組
      • 用於讓代理對象和被代理對象有相同方法 固定寫法
    • InvocationHandler:用於提供增強的代碼
      • 寫如何代理,一般都是寫一個該接口的實現類,通常用匿名內部類
      • 此接口的實現類都是誰用誰寫

案例:

使用一個生產者和消費者的模式來描述問題,通過代理生產者來實現代理商收取費用,代理過程中不改動生產者的任何代碼。

生產者接口:

package com.dsy.proxy;

/**
 * 對生產廠家要求的接口
 */
public interface IProducer {
    /**
     * 銷售
     * @param money
     */
    public void saleProduct(float money);

    /**
     * 售後
     * @param money
     */
    public void afterService(float money);
}

生產者:

package com.dsy.proxy;

/**
 * 一個生產者
 */
public class Producer implements IProducer{

    /**
     * 銷售
     * @param money
     */
    public void saleProduct(float money){
        System.out.println("銷售產品,並拿到錢:"+money);
    }

    /**
     * 售後
     * @param money
     */
    public void afterService(float money){
        System.out.println("提供售後服務,並拿到錢:"+money);
    }

}

消費者(在main函數中實現代理):

package com.dsy.proxy;

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

/**
 * 模擬一個消費者
 */
public class Client {

    public static void main(String[] args) {
        final Producer producer = new Producer();
        /**
         *  如何創建代理對象:
         *      使用Proxy類中的newProxyInstance方法
         *  創建代理對象的要求:
         *      被代理類最少實現一個接口,如果沒有則不能使用
         *  newProxyInstance方法的參數:
         *      ClassLoader:類加載器
         *          用於加載代理對象字節碼的,和被代理對象使用相同的類加載器 固定寫法
         *      Class[]:字節碼數組
         *          用於讓代理對象和被代理對象有相同方法 固定寫法
         *      InvocationHandler:用於提供增強的代碼
         *          寫如何代理,一般都是寫一個該接口的實現類,通常用匿名內部類
         *          此接口的實現類都是誰用誰寫
         */
        IProducer proxyProducer = (IProducer)Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 執行被代理對象的任何接口方法都會經過該方法
                     * @param proxy 代理對象的引用
                     * @param method 當前執行的方法
                     * @param args 當前執行方法的參數
                     * @return 和被代理對象有相同的返回值
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //提供增強的代碼
                        Object resultVal = null;
                        //1.獲取方法執行參數
                        Float money = (Float) args[0];
                        //2.判斷當前方法是不是銷售
                        if ("saleProduct".equals(method.getName())){
                            resultVal = method.invoke(producer, money*0.8f);
                        }
                        return resultVal;
                    }
                });

        proxyProducer.saleProduct(10000f);
    }
}

2. 基於子類的動態代理

涉及的類:Enhancer

提供者:第三方cglib庫

要求:被代理類不能是最終類(final修飾)

創建代理對象:使用Enhancer類中的create方法

  • create方法的參數
    • Class:字節碼
      • 它是用於指定被代理對象的字節碼
    • Callback:用於提供增強的代碼
      • 寫如何代理,一般都是寫一個該接口的實現類,通常用匿名內部類
      • 此接口的實現類都是誰用誰寫
      • 我們一般寫的都是該接口的子接口實現類:MethodInterceptor

導入cglib類庫:

<dependencies>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.1_3</version>
    </dependency>
</dependencies>

案例:

和上面一樣的生產者:

package com.dsy.cglib;

import com.dsy.proxy.IProducer;

/**
 * 一個生產者
 */
public class Producer{

    /**
     * 銷售
     * @param money
     */
    public void saleProduct(float money){
        System.out.println("銷售產品,並拿到錢:"+money);
    }

    /**
     * 售後
     * @param money
     */
    public void afterService(float money){
        System.out.println("提供售後服務,並拿到錢:"+money);
    }

}

消費者實現:

package com.dsy.cglib;

import com.dsy.proxy.IProducer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

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

/**
 * 模擬一個消費者
 */
public class Client {

    public static void main(String[] args) {
        final Producer producer = new Producer();
        /**
         *  如何創建代理對象:
         *      使用Enhancer類中的create方法
         *  創建代理對象的要求:
         *      被代理類不能是最終類(final修飾)
         *  create方法的參數:
         *      Class:字節碼
         *          它是用於指定被代理對象的字節碼
         *      Callback:用於提供增強的代碼
         *          寫如何代理,一般都是寫一個該接口的實現類,通常用匿名內部類
         *          此接口的實現類都是誰用誰寫
         *          我們一般寫的都是該接口的子接口實現類:MethodInterceptor
         */
        Producer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 執行被代理對象的任何方法都會經過該方法
             * @param proxy 代理對象的引用
             * @param method 當前執行的方法
             * @param args 當前執行方法的參數
             * @param methodProxy 當前執行方法的代理對象
             * @return
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //提供增強的代碼
                Object resultVal = null;
                //1.獲取方法執行參數
                Float money = (Float) args[0];
                //2.判斷當前方法是不是銷售
                if ("saleProduct".equals(method.getName())) {
                    resultVal = method.invoke(producer, money * 0.8f);
                }
                return resultVal;
            }
        });
        cglibProducer.saleProduct(10000f);
    }
}

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