1. 程式人生 > 程式設計 >詳細分析java 動態代理

詳細分析java 動態代理

1、動態代理的特點:

位元組碼隨用隨建立,隨用隨載入

2、作用:

不修改原始碼的基礎上對原始碼進行加強

3、分類:

(1)基於介面的動態代理:

涉及到的類:Proxy,由JDK官方提供,使用Proxy類中的newProxyInstance方法建立物件。建立代理物件時要求被代理物件至少實現一個介面,否則無法使用

引數:

  • ClassLoader:類載入器,他是用於載入物件位元組碼的,和被代理物件使用相同的類載入器,為固定寫法
  • class[]:位元組碼陣列,他是用於讓代理物件和被代理物件具有相同的方法,也是固定寫法
  • InvocationHandler:使用者提供增強的程式碼 ,他是讓我們寫如何代理。我們一般都是寫一個該介面的實現類,通常情況下都是匿名內部類,但不是必須的,此介面的實現類都是誰用誰寫

示例: 建立 Producter介面和實體類

package com.mingqi.proxy;
/**
 * 對生產廠家要求的介面
 */
public interface IProducer {
  /**
   * 銷售
   * @param money
   */
  public void SaleProduct(float money);

  /**
   * 售後
   * @param money
   */
  public void AfterService(float money);
}
package com.mingqi.proxy;

public class Producer implements IProducer {
  public void SaleProduct(float money) {
    System.out.println("銷售產品,並拿到錢:"+money);
  }

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

測試方法:

public static void main(String[] args) {
 /*   1、動態代理
    特點:位元組碼隨用隨建立,隨用隨載入
    作用:不修改原始碼的基礎上對原始碼進行加強
    分類:基於介面的動態代理
    涉及的類: Proxy
    提供者:JDK官方
    如何建立代理物件:
    使用Proxy類中的newProxyInstance方法
    建立代理物件的要求:
    被代理物件至少實現一個介面,如果沒有則不能使用
    newProxyInstance的方法引數:
    ClassLoader:類載入器
    他是用於載入代理物件位元組碼的,和被代理物件使用相同的類載入器,固定寫法
    class[]  :位元組碼陣列
    InvocationHandler 用於提供增強的程式碼
    他是讓我們寫如何代理,我們一般都是寫一個介面的實現類,通常情況下都是匿名內部類,但不是必須的,此介面的實現類都是誰用誰寫*/
   final Producer producer=new Producer();
   IProdurcer proxyProducer= (IProdurcer)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];
           //判斷當前方法是否是銷售
           if("SaleProduct".equals(method.getName()))
           {
             returnValue=method.invoke(producer,money*0.8f);
           }
           return returnValue;
         }
       });
    proxyProducer.SaleProduct(10000f);
  }

(2)基於子類的動態代理

涉及到的類:Enhancer,由第三方cglib提供,使用Enhancer類中的create方法建立物件。建立代理物件的類不能是最終類,否則無法使用

引數:

  • Class:位元組碼,他是用於指定被代理物件的位元組碼,為固定寫法
  • Callback:使用者提供增強的程式碼 ,他是讓我們寫如何代理。我們一般都是寫一個該介面的實現類,通常情況下都是匿名內部類,但不是必須的,此介面的實現類都是誰用誰寫,我們一般寫的都是該介面的子介面實現類MethodInterceptor

示例: 建立 Product介面和實體類

package com.mingqi.cglib;

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

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

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

測試類及方法:

package com.mingqi.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 Product product=new Product();
    Product cglibproduct= (Product) Enhancer.create(product.getClass(),new MethodInterceptor() {
      public Object intercept(Object o,Object[] objects,MethodProxy methodProxy) throws Throwable {
        Object returnValue=null;
        //1、獲取方法執行的引數
        Float money=(Float)objects[0];
        //判斷當前方法是不是銷售
        if("SaleProduct".equals(method.getName())) {
          returnValue = method.invoke(product,money*0.8f);
        }
        return returnValue;
      }
    });
    cglibproduct.SaleProduct(1000f);
  }
}

以上就是建立動態代理物件的兩種型別,以後要經常練習使用,讓這種思想能給我們工作中帶來方便。

到此這篇關於詳細分析java 動態代理的文章就介紹到這了,更多相關java 動態代理內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!