1. 程式人生 > 實用技巧 >Erlang那些事兒第3回之我是函式(fun),萬物之源MFA

Erlang那些事兒第3回之我是函式(fun),萬物之源MFA

技術標籤:動態代理

動態代理

一.動態代理特點

位元組碼隨用隨建立,隨用隨載入。它與靜態代理的區別也在於此。因為靜態代理是位元組碼一上來就建立好,並完成載入。裝飾者模式就是靜態代理的一種體現。

二.動態代理方式

1.基於介面的動態代理

提供者:JDK 官方的 Proxy 類。
要求:被代理類最少實現一個介面。

2.基於子類的動態代理

提供者:第三方的 CGLib,如果報 asmxxxx 異常,需要匯入 asm.jar。
要求:被代理類不能用 final 修飾的類(最終類)。

三.基於介面的動態代理的實現案例

1.提供一個介面:

在這裡插入圖片描述

2.提供一個實現類:

package com.xszx.
dynamicProxy.baseInte; /** * @author Mr Z * * * 廠家 */ public class Producer implements ProducerInte { public void salProduct(float money) { System.out.println("銷售產品,收錢"+money); } public void afterService(float money) { System.out.println("提供售後服務,收錢"
+money); } }

3.實現過程

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

/**
 * @author Mr Z
 * 
 * 顧客
 *
 * newProxyInstance方法的引數:
 *    ClassLoader:類載入器
 *                  它是用於載入代理物件位元組碼;和被代理物件使用相同的類載入器。
 *    Class[]:位元組碼陣列
 *                   用於讓代理物件和被代理物件有相同的方法
 *    InvocationHandler:用於提供增強的程式碼。
 *                        寫如何代理,通常使用匿名內部類
 */
public class Client { public static void main(String[] args) { final Producer producer = new Producer(); ProducerInte producerInte = (ProducerInte) 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 returnValue=null; //1.獲取方法執行的引數 Float money=(Float)args[0]; //2.判斷當前的方法是否為銷售 if ("saleProduct".equals(method.getName())){ returnValue=method.invoke(producer,money*0.8f); System.out.println("經銷商賺取差價:"+money*0.2f); } return returnValue; } }); producerInte.saleProduct(1000); } }

四.基於子類的動態代理

1.匯入第三方jar包

 <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.3.0</version>
 </dependency>
 

2.介面和實現類同上

3.實現程式碼

import com.xszx.dynamicProxy.baseInte.Producer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


import java.lang.reflect.Method;


/**
 * @author Mr Z
 * @create 2021 01 2021/1/6 16:52
 * 顧客
 *
 * create方法的引數:
 *    Class:位元組碼
 *                  它是用於指定被代理物件位元組碼
 *    Callback:用於提供增強的程式碼
 *              一般寫該介面的子介面實現類:MethodInterceptor
 */
public class Client {
    public static void main(String[] args) {
       final Producer producer = new Producer();
        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 returnValue=null;
                //1.獲取方法執行的引數
                Float money=(Float)args[0];
                //2.判斷當前的方法是否為銷售
                if ("saleProduct".equals(method.getName())){
                    returnValue=method.invoke(producer,money*0.8f);
                    System.out.println("經銷商賺取差價:"+money*0.2f);
                }
                return returnValue;
            }
        });
        cglibproducer.saleProduct(1000f);
    }
}