1. 程式人生 > >基於介面和子類的兩種動態代理的解析及使用

基於介面和子類的兩種動態代理的解析及使用

基於介面:

package com.itheima.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
         *      提供者:JDK官方
         *  如何建立代理物件:
         *      使用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
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //提供增強的程式碼
                        Object returnValue = null;

                        //1.獲取方法執行的引數
                        Float money = (Float)args[0];
                        //2.判斷當前方法是不是銷售
                        if("saleProduct".equals(method.getName())) {
                            returnValue = method.invoke(producer, money*0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(10000f);
    }
}

基於子類:

package com.itheima.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

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

    public static void main(String[] args) {
        final Producer producer = new Producer();

        /**
         * 動態代理:
         *  特點:位元組碼隨用隨建立,隨用隨載入
         *  作用:不修改原始碼的基礎上對方法增強
         *  分類:
         *      基於介面的動態代理
         *      基於子類的動態代理
         *  基於子類的動態代理:
         *      涉及的類:Enhancer
         *      提供者:第三方cglib庫
         *  如何建立代理物件:
         *      使用Enhancer類中的create方法
         *  建立代理物件的要求:
         *      被代理類不能是最終類
         *  create方法的引數:
         *      Class:位元組碼
         *          它是用於指定被代理物件的位元組碼。
         *
         *      Callback:用於提供增強的程式碼
         *          它是讓我們寫如何代理。我們一般都是些一個該介面的實現類,通常情況下都是匿名內部類,但不是必須的。
         *          此介面的實現類都是誰用誰寫。
         *          我們一般寫的都是該介面的子介面實現類:MethodInterceptor
         */
        Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 執行北地阿里物件的任何方法都會經過該方法
             * @param proxy
             * @param method
             * @param args
             *    以上三個引數和基於介面的動態代理中invoke方法的引數是一樣的
             * @param methodProxy :當前執行方法的代理物件
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //提供增強的程式碼
                Object returnValue = null;

                //1.獲取方法執行的引數
                Float money = (Float)args[0];
                //2.判斷當前方法是不是銷售
                if("saleProduct".equals(method.getName())) {
                    returnValue = method.invoke(producer, money*0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(12000f);
    }
}