java動(dòng)態(tài)代理(JDK和cglib)(轉(zhuǎn)載自http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html)

java動(dòng)態(tài)代理(JDK和cglib)

JAVA的動(dòng)態(tài)代理

代理模式

代理模式是常用的java設(shè)計(jì)模式,他的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后處理消息等。代理類與委托類之間通常會(huì)存在關(guān)聯(lián)關(guān)系,一個(gè)代理類的對象與一個(gè)委托類的對象關(guān)聯(lián),代理類的對象本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的對象的相關(guān)方法,來提供特定的服務(wù)。

按照代理的創(chuàng)建時(shí)期,代理類可以分為兩種。

靜態(tài)代理:由程序員創(chuàng)建或特定工具自動(dòng)生成源代碼,再對其編譯。在程序運(yùn)行前,代理類的.class文件就已經(jīng)存在了。

動(dòng)態(tài)代理:在程序運(yùn)行時(shí),運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。

首先看一下靜態(tài)代理:

1、Count.java

package net.battier.dao;

/**

* 定義一個(gè)賬戶接口

*

* @author Administrator

*

*/

public interface Count {

// 查看賬戶方法

public void queryCount();

// 修改賬戶方法

public void updateCount();

}

2、CountImpl.java

package net.battier.dao.impl;

import net.battier.dao.Count;

/**

* 委托類(包含業(yè)務(wù)邏輯)

*

* @author Administrator

*

*/

public class CountImpl implements Count {

@Override

public void queryCount() {

System.out.println("查看賬戶方法...");

}

@Override

public void updateCount() {

System.out.println("修改賬戶方法...");

}

}

、CountProxy.java

package net.battier.dao.impl;

import net.battier.dao.Count;

/**

* 這是一個(gè)代理類(增強(qiáng)CountImpl實(shí)現(xiàn)類)

*

* @author Administrator

*

*/

public class CountProxy implements Count {

private CountImpl countImpl;

/**

* 覆蓋默認(rèn)構(gòu)造器

*

* @param countImpl

*/

public CountProxy(CountImpl countImpl) {

this.countImpl = countImpl;

}

@Override

public void queryCount() {

System.out.println("事務(wù)處理之前");

// 調(diào)用委托類的方法;

countImpl.queryCount();

System.out.println("事務(wù)處理之后");

}

@Override

public void updateCount() {

System.out.println("事務(wù)處理之前");

// 調(diào)用委托類的方法;

countImpl.updateCount();

System.out.println("事務(wù)處理之后");

}

}

3、TestCount.java

package net.battier.test;

import net.battier.dao.impl.CountImpl;

import net.battier.dao.impl.CountProxy;

/**

*測試Count類

*

* @author Administrator

*

*/

public class TestCount {

public static void main(String[] args) {

CountImpl countImpl = new CountImpl();

CountProxy countProxy = new CountProxy(countImpl);

countProxy.updateCount();

countProxy.queryCount();

}

}

觀察代碼可以發(fā)現(xiàn)每一個(gè)代理類只能為一個(gè)接口服務(wù),這樣一來程序開發(fā)中必然會(huì)產(chǎn)生過多的代理,而且,所有的代理操作除了調(diào)用的方法不一樣之外,其他的操作都一樣,則此時(shí)肯定是重復(fù)代碼。解決這一問題最好的做法是可以通過一個(gè)代理類完成全部的代理功能,那么此時(shí)就必須使用動(dòng)態(tài)代理完成。

再來看一下動(dòng)態(tài)代理:

JDK動(dòng)態(tài)代理中包含一個(gè)類和一個(gè)接口:

InvocationHandler接口:

public interface InvocationHandler {

public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;

}

參數(shù)說明:

Object proxy:指被代理的對象。

Method method:要調(diào)用的方法

Object[] args:方法調(diào)用時(shí)所需要的參數(shù)

可以將InvocationHandler接口的子類想象成一個(gè)代理的最終操作類,替換掉ProxySubject。

Proxy類:

Proxy類是專門完成代理的操作類,可以通過此類為一個(gè)或多個(gè)接口動(dòng)態(tài)地生成實(shí)現(xiàn)類,此類提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces,

InvocationHandler h)

throws IllegalArgumentException

參數(shù)說明:

ClassLoader loader:類加載器

Class[] interfaces:得到全部的接口

InvocationHandler h:得到InvocationHandler接口的子類實(shí)例

Ps:類加載器

在Proxy類中的newProxyInstance()方法中需要一個(gè)ClassLoader類的實(shí)例,ClassLoader實(shí)際上對應(yīng)的是類加載器,在Java中主要有一下三種類加載器;

Booststrap ClassLoader:此加載器采用C++編寫,一般開發(fā)中是看不到的;

Extendsion ClassLoader:用來進(jìn)行擴(kuò)展類的加載,一般對應(yīng)的是jre\lib\ext目錄中的類;

AppClassLoader:(默認(rèn))加載classpath指定的類,是最常使用的是一種加載器。

動(dòng)態(tài)代理

與靜態(tài)代理類對照的是動(dòng)態(tài)代理類,動(dòng)態(tài)代理類的字節(jié)碼在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成,無需程序員手工編寫它的源代碼。動(dòng)態(tài)代理類不僅簡化了編程工作,而且提高了軟件系統(tǒng)的可擴(kuò)展性,因?yàn)镴ava 反射機(jī)制可以生成任意類型的動(dòng)態(tài)代理類。java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動(dòng)態(tài)代理類的能力。

動(dòng)態(tài)代理示例:

1、BookFacade.java

package net.battier.dao;

public interface BookFacade {

public void addBook();

}

2、BookFacadeImpl.java

package net.battier.dao.impl;

import net.battier.dao.BookFacade;

public class BookFacadeImpl implements BookFacade {

@Override

public void addBook() {

System.out.println("增加圖書方法。。。");

}

}

、BookFacadeProxy.java

package net.battier.proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

/**

* JDK動(dòng)態(tài)代理代理類

*

* @author student

*

*/

public class BookFacadeProxy implements InvocationHandler {

private Object target;

/**

* 綁定委托對象并返回一個(gè)代理類

* @param target

* @return

*/

public Object bind(Object target) {

this.target = target;

//取得代理對象

return Proxy.newProxyInstance(target.getClass().getClassLoader(),

target.getClass().getInterfaces(), this);? //要綁定接口(這是一個(gè)缺陷,cglib彌補(bǔ)了這一缺陷)

}

@Override

/**

* 調(diào)用方法

*/

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

Object result=null;

System.out.println("事物開始");

//執(zhí)行方法

result=method.invoke(target, args);

System.out.println("事物結(jié)束");

return result;

}

}

3、TestProxy.java

package net.battier.test;

import net.battier.dao.BookFacade;

import net.battier.dao.impl.BookFacadeImpl;

import net.battier.proxy.BookFacadeProxy;

public class TestProxy {

public static void main(String[] args) {

BookFacadeProxy proxy = new BookFacadeProxy();

BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());

bookProxy.addBook();

}

}

但是,JDK的動(dòng)態(tài)代理依靠接口實(shí)現(xiàn),如果有些類并沒有實(shí)現(xiàn)接口,則不能使用JDK代理,這就要使用cglib動(dòng)態(tài)代理了。

Cglib動(dòng)態(tài)代理

JDK的動(dòng)態(tài)代理機(jī)制只能代理實(shí)現(xiàn)了接口的類,而不能實(shí)現(xiàn)接口的類就不能實(shí)現(xiàn)JDK的動(dòng)態(tài)代理,cglib是針對類來實(shí)現(xiàn)代理的,他的原理是對指定的目標(biāo)類生成一個(gè)子類,并覆蓋其中方法實(shí)現(xiàn)增強(qiáng),但因?yàn)椴捎玫氖抢^承,所以不能對final修飾的類進(jìn)行代理。

示例

1、BookFacadeCglib.java

package net.battier.dao;

public interface BookFacade {

public void addBook();

}

2、BookCadeImpl1.java

package net.battier.dao.impl;

/**

* 這個(gè)是沒有實(shí)現(xiàn)接口的實(shí)現(xiàn)類

*

* @author student

*

*/

public class BookFacadeImpl1 {

public void addBook() {

System.out.println("增加圖書的普通方法...");

}

}

3、BookFacadeProxy.java

package net.battier.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

/**

* 使用cglib動(dòng)態(tài)代理

*

* @author student

*

*/

public class BookFacadeCglib implements MethodInterceptor {

private Object target;

/**

* 創(chuàng)建代理對象

*

* @param target

* @return

*/

public Object getInstance(Object target) {

this.target = target;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(this.target.getClass());

// 回調(diào)方法

enhancer.setCallback(this);

// 創(chuàng)建代理對象

return enhancer.create();

}

@Override

// 回調(diào)方法

public Object intercept(Object obj, Method method, Object[] args,

MethodProxy proxy) throws Throwable {

System.out.println("事物開始");

proxy.invokeSuper(obj, args);

System.out.println("事物結(jié)束");

return null;

}

}

4、TestCglib.java

package net.battier.test;

import net.battier.dao.impl.BookFacadeImpl1;

import net.battier.proxy.BookFacadeCglib;

public class TestCglib {

public static void main(String[] args) {

BookFacadeCglib cglib=new BookFacadeCglib();

BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());

bookCglib.addBook();

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 原文 代理模式 代理模式是常用的 Java 設(shè)計(jì)模式,它的特征是代理類與委托類有同樣的接口,代理類主要負(fù)責(zé)為委托類...
    Coder_Y閱讀 1,193評論 0 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 不久之后,市里將舉行一場少兒英語口語大賽。我們學(xué)校只有一個(gè)參賽名額,所以競爭也就異常激烈。 我本無意參加這次比賽,...
    子敬wu閱讀 263評論 1 3
  • 上課時(shí),他用筆戳戳她的背:“喂,班長!三點(diǎn)水一個(gè)來來去去的來念什么?” “來。” “那么三點(diǎn)水一個(gè)來來去去的去呢?...
    猜不中的尾聲閱讀 295評論 7 1