一、 理解動態代理設計模式
代理模式,是常用的Java設計模式,他的特徵是代理類與委託類有同樣的接口,代理類主要負責爲委託類預處理消息,過濾消息,把消息轉發給委託類,以及事後處理消息等。代理類與委託類之間通常會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象本身並不真正實現業務,而是通過調用委託類的對象相關方法,來提供特定的服務。
動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程序員手工編寫它的源代碼。動態代理類不僅簡化了編程工作,而且提高了軟件系統的可擴展性,因爲Java反射機制可以生成任意類型的動態代理類。Java.lang.reflect包中的Proxy類和Invocationhandler接口提供了生成動態代理類的能力。
Java動態代理中包含一個類和一個接口:
InvocationHandler接口:
publicinterface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } |
參數說明:
Object proxy:指被代理的對象
Method method:要調用的方法
Object[] args:方法調用時需要的參數
Proxy類
Proxy類是專門完成代理的操作類,可以通過此類爲一個或多個接口動態的生成一個實現類,此類提供瞭如下的操作方法:
publicstatic Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { thrownew NullPointerException(); }
|
參數說明:
ClassLoader loader:類加載器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類實例
類加載器
在Proxy類中的newProxyInstance()方法中需要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有一下三種類加載器
Bootstrap ClassLoader:此類加載器採用C++編寫,一般開發中看不到的;
Extendsion ClassLoader:用來進行擴展類的加載,一般對應的是jre\lib\ext目錄中的類;
AppClassLoader :(默認)加載classpath指定的類,是最常用的一種加載器
例子:
代理類:
package com.eden.proxy;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class DAOProxy implements InvocationHandler { // 委託類,及原代理類 private Object originalObject;
public Object bind(Object obj){ this.originalObject=obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this); }
private void preMothed(){ System.out.println("方法執行之前……"); } private void afterMothed(){ System.out.println("方法執行之後……"); } @Override public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { this.preMothed(); Object result=arg1.invoke(this.originalObject, arg2); System.out.println(" arg0 classname="+arg0.getClass().getName()); this.afterMothed(); return result; }
} |
測試類:
import com.eden.dao.StudentsDAO; import com.eden.dao.impl.StudentsImpl; import com.eden.proxy.DAOProxy;
import junit.framework.TestCase;
publicclass TestProxy extends TestCase { publicvoid testProxy(){ StudentsDAO sdao= new StudentsImpl(); DAOProxy proxy=new DAOProxy(); sdao=(StudentsDAO) proxy.bind(sdao); sdao.savaStudents(); }
}
|
二、 Cglib動態代理
Jdk的動態代理依靠接口實現,如果有些類並沒有實現接口,則不能使用jdk代理,這就要使用cglib動態代理了。
Cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中的方法實現增強,但因爲採用的是繼承,所以不能對final修飾的類進行代理。
Bytecode:java 的二進制字節碼文件。
ASM:爲Java字節碼文件進行反彙編的工具
CGLIB、 Groovy、BeanShell :爲三個常用動態代理組件
Hibernate Spring AOP Dynaop,etc: 使用CGLIB的常見框架
Applications :應用
MethedInterceptor接口
接口方法
Public Object Intercept(Object obj,Method method,Object[] args MethodProxy proxy) throw Throwable
參數介紹:
Obj:代理對象
Method:攔截的方法
Args:方法參數
Proxy:攔截器
三、 在Spring中
兩種代理模式都支持,Spring默認使用的是jdk proxy;