java動態代理

java動態代理

1. 簡介

java的動態代理功能是用來解決現有類功能不足,但咱們又不想去修改現有類方法的問題,或者就是咱們沒法直接使用現有類的狀況。它的實現方式有兩種,第一種是jdk自帶的動態代理功能,它的實現前提是現有類必須擁有一個接口,由於它是經過對現有類接口的實現來完成的。第二種方式是cglib,這是一個開源工具包,它的實現是經過繼承現有類,而後重寫現有類的方法實現的。它們在spring與mybatis框架中均有使用。學習它們的前提是你要對java的反射機制有必定的認知。本篇只介紹jdk原生的動態代理。java

2. jdk動態代理

2.1 演示前景

客戶:購買u盤spring

代理商:淘寶mybatis

u盤工廠:金士頓,三星等app

用戶想要購買u盤,是不能夠直接去廠家購買的,須要經過淘寶等代理商進行購買,抽象成程序就是,u盤工程就是目標類,也就是現有類,淘寶就是代理類,客戶就是用戶類.用戶須要調用淘寶的方法進行購買u盤,而淘寶又須要調用工廠的方法進行購買.若是咱們直接建立一個淘寶類,讓它去代理金士頓工廠,就會出現一個問題,那就是三星工廠由誰去代理,總不能再建立一個代理類吧,因此就可使用動態代理的方式,在程序運行時期,根據不一樣的狀況去建立一個合適的代理類框架

2.2編寫代碼

首先咱們須要一個工廠的接口UsbFactoryide

package com.hzq.application.targetclass;

public interface UsbFactory {
    //售賣u盤,並返回實際價格的方法
    float sell(int num);
}

第二步就是建立一個UsbFactory的實現類UsbKingFactory表明金士頓工廠工具

package com.hzq.application.targetclass.impl;

import com.hzq.application.targetclass.UsbFactory;

public class UsbKingFactory implements UsbFactory {
    @Override
    public float sell(int num) {
        float onePrice = 30.0F;
        float price = onePrice * num;
        System.out.println("向廠家購買花費了"+price+"元");
        return price;
    }
}

如今須要咱們代理的目標類已經好了,接下來就是重點了,jdk動態代理的實現方法(這個實現套路是固定的)。第三步,建立一個MyInvocationHandler類去實現接口InvocationHandler。這個接口只有一個須要咱們去實現的方法,那就是invoke()方法,它有3個參數,第一個參數其實就是咱們後面經過動態代理去建立的代理類,這個參數不須要咱們的參與,不用去理會,第二個參數是咱們要去加強的目標類的方法,第三個是該方法的參數.invoke內部就是咱們要對目標類的方法加強的具體邏輯,也就是咱們想怎樣去加強它,在本示例中咱們是對用戶購買的商品收取20元中介費,而後送給用戶一張10元的優惠券學習

package com.hzq.application.proxy;

import com.hzq.application.targetclass.UsbFactory;

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

public class MyInvocationHandler implements InvocationHandler {
    private UsbFactory factory ;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //1.調用目標類的售賣方法,而後返回價格
        Float price = (Float) method.invoke(factory, args);
      //2.咱們在以後進行自定義的加強,這裏咱們是抽取20元的中介費用,而後送給客戶一張10元優惠券
        price += 20;
        System.out.println("代理商送您一張10元優惠券");
        System.out.println("客戶購買商品花費了"+price+"元");
        return price;
    }

    public MyInvocationHandler(UsbFactory factory) {
        this.factory = factory;
    }
}

最後一步就是去使用jdk動態代理來在運行期建立一個代理類對象了,在代碼中第第三步是重點,咱們若是咱們想要建立一個動態代理類,就必需要調用Proxy類的靜態方法newProxyInStance()方法,這個方法會返回給咱們一個代理類對象,咱們實際購買商品也是經過這個代理類來進行購買的。newProxyInstance()方法一共有三個參數,第一個參數是一個類加載器對象,類加載器對象能夠經過目標類的Class對象去調用getClassLoader()方法去獲取,其實也可使用其餘你自定義的類的Class對象去獲取,由於最後得到的都是同一個類加載器實例,但爲了代碼的易讀性,就使用了目標類。第二個參數是目標類的接口類型,第三個參數就是咱們自定義的MyInvocationHandler類的實例對象了,它裏面封裝這咱們具體的加強邏輯代碼。方法調用完成後,若是沒有出現問題就會返回給咱們一個代理類的實例,以後咱們就能夠去使用這個代理類的。this

package com.hzq.application;

import com.hzq.application.proxy.MyInvocationHandler;
import com.hzq.application.targetclass.UsbFactory;
import com.hzq.application.targetclass.impl.UsbKingFactory;

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

public class ProxyMain {
    public static void main(String[] args) {
      //1.實例化一個金士頓工廠對象
        UsbFactory usbFactory = new UsbKingFactory();
      //2.實例化一個MyInvocationHandler對象
        InvocationHandler handler = new MyInvocationHandler(usbFactory);
      //3.經過jdk動態代理建立出代理對象
        UsbFactory proxyInstance = (UsbFactory) Proxy.newProxyInstance(usbFactory.getClass().getClassLoader(),
                usbFactory.getClass().getInterfaces(),
                handler);
      //4.經過代理對象來購買商品
        float price = proxyInstance.sell(3);
        System.out.println(price);
    }
}

最後,當咱們須要代理其餘工廠去售賣u盤時,只須要將main方法中的第一步實例化的金士頓工廠改爲其餘品牌的工廠便可,固然前提是這個工廠的類實現了UsbFactory接口。代理

2.3 總結

當咱們去使用jdk動態代理時,首先須要確保目標類實現了接口。以後的使用步驟就是:

  1. 實現InvocationHandler接口,將咱們具體的加強邏輯代碼寫在invoke()方法中
  2. 使用Proxy類的newProxyInstance()方法去建立一個代理類的實例對象.
  3. 使用這個代理類對象
相關文章
相關標籤/搜索