1. 程式人生 > >Java動態代理(JDK介面代理和Cglib類代理)

Java動態代理(JDK介面代理和Cglib類代理)

代理模式 
代理模式是常用的java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,而是通過呼叫委託類的物件的相關方法,來提供特定的服務。 
按照代理的建立時期,代理類可以分為兩種。 
靜態代理:由程式設計師建立或特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。 

動態代理:在程式執行時,運用反射機制動態建立而成。 

靜態代理:

BookInterface.java

public interface BookInterface
{
    /**
     * 業務方法
     * Description: <br> 
     * @see
     */
    void addBook();
}

BookImpl.java
public class BookImpl implements BookInterface
{

    @Override
    public void addBook()
    {
        System.out.println("[email protected]#addBook");
    }

}

BookProxy.java
/**
 * 靜態代理類   需要和委託類實現同樣的介面 
 * @author lyh
 * @version 2013-4-16
 * @see BookProxy
 * @since
 */
public class BookProxy implements BookInterface
{

    private BookImpl bookImpl;
    
    /**
     * 這裡使用建構函式注入委託類
     * @param bookImpl
     */
    public BookProxy(BookImpl bookImpl)
    {
        this.bookImpl = bookImpl;
    }
    
    @Override
    public void addBook()
    {
        System.out.println("Before Advice");
        
        bookImpl.addBook();
        
        System.out.println("After Advice");
    }

}

Will.java
/**
 * 測試類
 * @author lyh
 * @version 2013-4-16
 * @see Will
 * @since
 */
public class Will
{

    /**
     * Description: <br>
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        BookImpl impl=  new BookImpl();
        
        BookProxy proxy = new BookProxy(impl);
        
        //展示給客戶端呼叫的是代理類的方法
        proxy.addBook();
    }

}

觀察程式碼可以發現每一個代理類只能為一個介面服務,這樣一來程式開發中必然會產生過多的代理,而且,所有的代理操作除了呼叫的方法不一樣之外,其他的操作都一樣,則此時肯定是重複程式碼。解決這一問題最好的做法是可以通過一個代理類完成全部的代理功能,那麼此時就必須使用動態代理完成。 
再來看一下動態代理: 
JDK動態代理中包含一個類和一個介面(具體參見API手冊): 
InvocationHandler介面(這裡推薦一篇文章 對於這個介面解釋的很清楚 http://www.cnblogs.com/yixiwenwen/archive/2012/11/14/2770068.html): 
public interface InvocationHandler { 
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 

引數說明: 
Object proxy:指被代理的物件。 
Method method:要呼叫的方法 
Object[] args:方法呼叫時所需要的引數 

可以將InvocationHandler介面的子類想象成一個代理的最終操作類,替換掉ProxySubject。 

Proxy類: 
Proxy類是專門完成代理的操作類,可以通過此類為一個或多個介面動態地生成實現類,此類提供瞭如下的操作方法: 
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
引數說明: 
ClassLoader loader:類載入器 
Class<?>[] interfaces:得到全部的介面 
InvocationHandler h:得到InvocationHandler介面的子類例項 

Ps:類載入器 
在Proxy類中的newProxyInstance()方法中需要一個ClassLoader類的例項,ClassLoader實際上對應的是類載入器,在Java中主要有一下三種類載入器; 
Booststrap ClassLoader:此載入器採用C++編寫,一般開發中是看不到的; 
Extendsion ClassLoader:用來進行擴充套件類的載入,一般對應的是jre\lib\ext目錄中的類; 
AppClassLoader:(預設)載入classpath指定的類,是最常使用的是一種載入器。 

動態代理 
與靜態代理類對照的是動態代理類,動態代理類的位元組碼在程式執行時由Java反射機制動態生成,無需程式設計師手工編寫它的原始碼。動態代理類不僅簡化了程式設計工作,而且提高了軟體系統的可擴充套件性,因為Java 反射機制可以生成任意型別的動態代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 介面提供了生成動態代理類的能力。 

JDK動態介面代理: 

BookInterface.java

public interface BookInterface
{
    /**
     * 業務方法
     * Description: <br> 
     * @see
     */
    void addBook();
    
    /**
     * 攔截方法
     * Description: <br> 
     * @see
     */
    void intercept();
}

BookImpl.java
public class BookImpl implements BookInterface
{


    @Override
    public void addBook()
    {
        System.out.println("[email protected]#addBook");
    }
    
    @Override
    public void intercept()
    {
        System.out.println("[email protected]#intercept is intercepted...");
    }


}

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


/**
 * JDK 動態代理類  介面代理 
 * @author lyh
 * @version 2013-4-16
 * @see BookProxy
 * @since
 */
public class BookProxy implements InvocationHandler
{
    /**
     * 委託類
     */
    private Object target;

    public Object getInstance(Object target)
    {
        this.target = target;
        
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
            target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object obj, Method method, Object[] args)
        throws Throwable
    {
        System.out.println("Before Advice");
        
        if("intercept".equals(method.getName()))
        {
            System.out.println("intercept method is intercepted");
            
            return null;
        }
        
        //注意此處的引數是注入的target 而不是obj
        Object  result = method.invoke(target, args);
        
        System.out.println("After Advice");
        
        return result;
    }

}
Will.java
/**
 * 測試類 
 * @author lyh
 * @version 2013-4-16
 * @see Will
 * @since
 */
public class Will
{

    /**
     * Description: <br>
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        BookProxy proxy = new BookProxy();
        BookInterface impl = (BookInterface)proxy.getInstance(new BookImpl());
        
        //impl.addBook();
        impl.intercept();
    }
}

但是,JDK的動態代理依靠介面實現,如果有些類並沒有實現介面,則不能使用JDK代理,這就要使用cglib動態代理了。 

Cglib動態代理 
JDK的動態代理機制只能代理實現了介面的類,而不能實現介面的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為採用的是繼承,所以不能對final修飾的類進行代理。 

Cglib動態類代理:

BookClass.java

public class BookClass
{
    /**
     * 業務方法 使用cglib則不需要額外定義介面
     * Description: <br> 
     * @see
     */
    public void addBook()
    {
        System.out.println("[email protected]#addBook");
    }
}

BookProxy.java
import java.lang.reflect.Method;

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


/**
 * Cglib 動態代理類 類代理 
 * @author lyh
 * @version 2013-4-16
 * @see BookProxy
 * @since
 */
public class BookProxy implements MethodInterceptor
{
    /**
     * 委託類
     */
    private Object target;
    
    public Object getInstance(Object target)
    {
        this.target = target;
        
        Enhancer en = new Enhancer();
        
        en.setSuperclass(target.getClass());
        
        en.setCallback(this);
        
        return en.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
        throws Throwable
    {
        System.out.println("Before Advice");
        
        //注意此處的引數是注入的target 而不是obj
        Object result = proxy.invoke(target, args);
        
        System.out.println("After Advice");
        
        return result;
    }

}

Will.java
/**
 * 測試類
 * @author lyh
 * @version 2013-4-16
 * @see Will
 * @since
 */
public class Will
{

    /**
     * Description: <br>
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        BookProxy proxy = new BookProxy();
        
        BookClass bc = (BookClass)proxy.getInstance(new BookClass());
        
        bc.addBook();
    }

}


相關推薦

Java動態代理JDK介面代理Cglib代理

代理模式 代理模式是常用的java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服

java學習筆記13-介面、final、多型

1.介面interface 1.1 介面基本使用 package com.daigua13; /* * 介面的成員特點: * 只能有抽象方法 * 只能有常量 * 預設使用public&abstract修飾方法 * 只能使用public&ab

Java型別轉換自動型別轉換強制型別轉換

資料型別轉換 ①自動型別轉換:小資料型別–>大資料型別 ②強制型別轉換:大資料型別–>小資料型別 強轉格式:小資料型別 變數名 = (小資料型別)大資料型別,如: int a = 10; byte b = (byte)a;//把int強轉成

mac安裝java開發環境jdk+eclipse+maven+svn

新入職後公司配發Mac筆記本用於工作開發。儘管之前用過Linux作業系統,但完全沒有用過蘋果產品,工作學習基本還是以windows為主。因此剛剛領到電腦時還是有點不知所措。經過一天的學習與工作,基本的

java動態代理JDKCGLIB筆記

動態代理:為一堆interface或類的實現提供統一的執行通道,從含義上就像區域網電腦通過代理上網一樣,走統一的通道,代理控制通道,自然可以在通道里加上自定義實現,例如像AOP切面,日誌等。 JDK的動態代理只能對介面實現,代理類需要實現InvocationHandler 介面。 一、介面 pub

Java核心-反射動態代理JDK ProxyCglib

反射和動態代理放有一定的相關性,但單純的說動態代理是由反射機制實現的,其實是不夠全面不準確的,動態代理是一種功能行為,而它的實現方法有很多。要怎麼理解以上這句話,請看下文。 一、反射 反射機制是 Java 語言提供的一種基礎功能,賦予程式在執行時 自省 (intro

Java提高班反射動態代理JDK ProxyCglib

反射和動態代理放有一定的相關性,但單純的說動態代理是由反射機制實現的,其實是不夠全面不準確的,動態代理是一種功能行為,而它的實現方法有很多。要怎麼理解以上這句話,請看下文。 一、反射 反射機制是 Java 語言提供的一種基礎功能,賦予程式在執行時自省(introspect,官方用語)的能力。通過反射我們可

java動態代理JDKcglib

JAVA的動態代理  代理模式  代理模式是常用的java設計模式,他的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服務,

帶你用例項學習代理模式:靜態代理動態代理JDKCGlib以及區別優缺點

Spring AOP的核心技術就是動態代理,所以小編學習並整理了代理模式的材料,供大家一起學習。 1、代理模式滿足的三個必要條件: 兩個角色:執行者、被代理物件 這個過程必須要做,但是自己不能做或者不想做,交給專業的人(媒婆) 執行者必須拿到被代理物件的引用(需要知道你要什

代理設計模式 靜態代理設計模式+ 動態代理JDKCglib

一、代理設計模式 1、設計模式:前人總結一套解決特定問題的程式碼 2、代理設計模式優點:     2.1 保護真實物件     2.2 讓真實物件職責更明確     2.3 擴充套件 3、代理設計模式     3.1 真實物件(老總)     3.2 代理物件(祕書)     3.3 抽象物

談談java代理模式的認識二——動態代理JDK)

 讓我們就接著上篇部落格的靜態代理來開始今天的動態代理。 一、動態代理              靜態代理需要在執行之前就寫好代理類,這樣就造成了程式碼的大量重複,所以我們通過動態代理在執行時期動態生

Java代理jdk靜態代理jdk動態代理cglib動態代理,aop,aspectj

一.概念 代理是什麼呢?舉個例子,一個公司是賣攝像頭的,但公司不直接跟使用者打交道,而是通過代理商跟使用者打交道。如果:公司介面中有一個賣產品的方法,那麼公司需要實現這個方法,而代理商也必須實現這個方法。如果公司賣

靜態代理動態代理jdk/cglib詳解

##### **1.靜態代理模式** ![](https://img2020.cnblogs.com/blog/1054413/202008/1054413-20200811114656604-915657843.png) 代理模式上,基本上有Subject角色,RealSubject角色,Proxy

JDK動態代理JDK dynamic proxy

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK動態代理。 * @author Bright Le

Java第四章第五章

簡潔 重復 清晰 快速 結束 編寫 int() input 出現 第四章 一、 switch結構(開關語句)的語法 switch(表達式[dream1] ){ case 常量1[dream2] : //語句塊1

PRX通過LSP實現瀏覽器Socks5/Tcp代理從發送數據上著手

md4 npm www. sock blank tor cst socks5 sel 8R幾枷汾厝r拷1噶3http://www.docin.com/qkiw43261 Kw497Q泳5MCSI肺1http://t.docin.com/qwjg61513 q嚷OB9

java-String中的各字符串判斷包括" "null的區別

mos 大小 既然 main 引用數據類型 同時 ins emp gpo package com.day7.one; public class DemoString1 {   /**   * @param args   * 1.boolean equals(Objec

Centos7下配置Java web環境JDK、Tomcat、Mysql

sql ner route aio word client rpm node share 在Centos7中配置java web環境主要涉及三方面配置:JDK、Tomcat以及Mysql 這裏使用版本如下: JDK:jdk-8u181-linux-x64,下載地址:http

Java後臺怎麼獲取session的所有內容獲取到keyvalue的方法

程式碼如下: //獲取session HttpSession session = request.getSession(); // 獲取session中所有的鍵值 Enumeration<String> attrs = session.getAtt

java執行緒池有返回值無返回值

無返回值: package ThreadPool2; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class test { public stat