JDK動態代理
代理模式是經常使用的Java設計模式,他的特徵是代理類與委託類有一樣的接口,代理類主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及過後處理消息等。代理類與委託類之間一般會存在關聯關係,一個代理類的對象與一個委託類的對象關聯,代理類的對象自己並不真正實現服務,而是經過調用委託類的對象的相關方法,來提供特定的服務。
按照代理的建立時期,代理類能夠分爲兩種。
靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。
動態代理:在程序運行時,運用反射機制動態建立而成。 java
爲何使用動態代理?由於動態代理能夠對請求進行任何處理。
哪些地方須要動態代理?不容許直接訪問某些類;對訪問要作特殊處理等。
目前Java開發包中包含了對動態代理的支持,可是其實現只支持對接口的的實現。 其實現主要經過java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口。 Proxy類主要用來獲取動態代理對象,InvocationHandler接口用來約束調用者實現。git
如下爲模擬案例,經過動態代理實如今方法調用先後向控制檯輸出兩句字符串。程序員
定義一個HelloWorld接口:github
[java] view plain copyspring
- package com.ljq.test;
-
- /**
- * 定義一個HelloWorld接口
- *
- * @author jiqinlin
- *
- */
- public interface HelloWorld {
- public void sayHelloWorld();
- }
類HelloWorldImpl是HelloWorld接口的實現:apache
[java] view plain copy設計模式
- package com.ljq.test;
-
- /**
- * 類HelloWorldImpl是HelloWorld接口的實現
- *
- * @author jiqinlin
- *
- */
- public class HelloWorldImpl implements HelloWorld{
-
- public void sayHelloWorld() {
- System.out.println("HelloWorld!");
- }
-
- }
HelloWorldHandler是 InvocationHandler接口實現:數組
[java] view plain copyapp
- package com.ljq.test;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
-
- /**
- * 實如今方法調用先後向控制檯輸出兩句字符串
- *
- * @author jiqinlin
- *
- */
- public class HelloWorldHandler implements InvocationHandler{
- //要代理的原始對象
- private Object obj;
-
- public HelloWorldHandler(Object obj) {
- super();
- this.obj = obj;
- }
-
- /**
- * 在代理實例上處理方法調用並返回結果
- *
- * @param proxy 代理類
- * @param method 被代理的方法
- * @param args 該方法的參數數組
- */
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Object result = null;
- //調用以前
- doBefore();
- //調用原始對象的方法
- result=method.invoke(obj, args);
- //調用以後
- doAfter();
- return result;
- }
-
- private void doBefore(){
- System.out.println("before method invoke");
- }
-
- private void doAfter(){
- System.out.println("after method invoke");
- }
-
- }
測試類:框架
[java] view plain copy
- package com.ljq.test;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
-
-
- public class HelloWorldTest {
-
- public static void main(String[] args) {
- HelloWorld helloWorld=new HelloWorldImpl();
- InvocationHandler handler=new HelloWorldHandler(helloWorld);
-
- //建立動態代理對象
- HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance(
- helloWorld.getClass().getClassLoader(),
- helloWorld.getClass().getInterfaces(),
- handler);
- proxy.sayHelloWorld();
- }
- }
運行結果爲:
[plain] view plain copy
- before method invoke
- HelloWorld!
- after method invoke
基本流程:用Proxy類建立目標類的動態代理,建立時須要指定一個本身實現InvocationHandler接口的回調類的對象,這個回調類中有一個invoke()用於攔截對目標類各個方法的調用。建立好代理後就能夠直接在代理上調用目標對象的各個方法。
JDK自從1.3版本開始,就引入了動態代理,而且常常被用來動態地建立代理。JDK的動態代理用起來很是簡單,但它有一個限制,就是使用動態代理的對象必須實現一個或多個接口。好比上面的HelloWorldImpl類,實現了HelloWorld接口,因此能夠用JDK的動態代理。若是想代理沒有實現接口的繼承的類,該怎麼辦? CGLIB就是最好的選擇(https://github.com/cglib/cglib,使用apache license 2.0)。其餘比較有名的還有從JBoss項目衍生出來的Javassist(https://github.com/jboss-javassist/javassist),這裏介紹Cglib。
Cglib代碼生成庫
CGlib是一個強大的,高性能,高質量的Code生成類庫。它能夠在運行期擴展Java類與實現Java接口。其底層是經過小而快的字節碼處理框架ASM(http://forge.ow2.org/projects/asm,使用BSD License)來轉換字節碼並生成新的類。大部分功能其實是asm所提供的,CGlib只是封裝了asm,簡化了asm的操做,實現了在運行期動態生成新的class。
CGlib被許多AOP的框架使用,例如spring AOP和dynaop,爲他們提供方法的interception(攔截);最流行的OR Mapping工具hibernate也使用CGLIB來代理單端single-ended(多對一和一對一)關聯(對集合的延遲抓取,是採用其餘機制實現的);EasyMock和jMock是經過使用模仿(moke)對象來測試java代碼的包,它們都經過使用CGLIB來爲那些沒有接口的類建立模仿(moke)對象。
CGLIB包的基本代碼不多,但學起來有必定的困難,主要是缺乏文檔,API描述過於簡單,這也是開源軟件的一個不足之處。目前CGLIB的版本是cglib-2.2.jar,主要由一下部分組成:
(1)net.sf.cglib.core:底層字節碼處理類,他們大部分與ASM有關係。
(2)net.sf.cglib.transform:編譯期或運行期類和類文件的轉換。
(3)net.sf.cglib.proxy :實現建立代理和方法攔截器的類。
(4)net.sf.cglib.reflect :實現快速反射和C#風格代理的類。
(5)net.sf.cglib.util:集合排序工具類。
(6)net.sf.cglib.beans:JavaBean相關的工具類。
CGLIB包是在ASM之上的一個高級別的層。對代理那些沒有實現接口的類很是有用。本質上,它是經過動態的生成一個子類去覆蓋所要代理類的不是final的方法,並設置好callback,則原有類的每一個方法調用就會轉變成調用用戶定義的攔截方法(interceptors),這比JDK動態代理方法快多了。可見,Cglib的原理是對指定的目標類動態生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類和final方法進行代理。
用Cglib建立動態代理
下圖表示Cglib經常使用到的幾類。
![](http://static.javashuo.com/static/loading.gif)
圖1 Cglib主要的接口
建立一個具體類的代理時,一般要用到的CGLIB包的APIs:
net.sf.cglib.proxy.Callback接口:在CGLIB包中是一個很關鍵的接口,全部被net.sf.cglib.proxy.Enhancer類調用的回調(callback)接口都要繼承這個接口。
net.sf.cglib.proxy.MethodInterceptor接口:是最通用的回調(callback)類型,它常常被AOP用來實現攔截(intercept)方法的調用。這個接口只定義了一個方法。
[java] view plain copy
- public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
當net.sf.cglib.proxy.MethodInterceptor作爲全部代理方法的回調 (callback)時,當對基於代理的方法調用時,在調用原對象的方法的以前會調用這個方法,如圖下圖所示。第一個參數是代理對像,第二和第三個參數分別 是攔截的方法和方法的參數。原來的方法可能經過使用java.lang.reflect.Method對象的通常反射調用,或者使用 net.sf.cglib.proxy.MethodProxy對象調用。net.sf.cglib.proxy.MethodProxy一般被首選使用,由於它更快。在這個方法中,咱們能夠在調用原方法以前或以後注入本身的代碼。
![](http://static.javashuo.com/static/loading.gif)
圖1
net.sf.cglib.proxy.MethodInterceptor可以知足任何的攔截(interception )須要,當對有些狀況下可能過分。爲了簡化和提升性能,CGLIB包提供了一些專門的回調(callback)類型。例如:
net.sf.cglib.proxy.FixedValue:爲提升性能,FixedValue回調對強制某一特別方法返回固定值是有用的。
net.sf.cglib.proxy.NoOp:NoOp回調把對方法調用直接委派到這個方法在父類中的實現。
net.sf.cglib.proxy.LazyLoader:當實際的對象須要延遲裝載時,可使用LazyLoader回調。一旦實際對象被裝載,它將被每個調用代理對象的方法使用。
net.sf.cglib.proxy.Dispatcher:Dispathcer回調和LazyLoader回調有相同的特色,不一樣的是,當代理方法被調用時,裝載對象的方法也總要被調用。
net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回調和Dispatcher同樣,不一樣的是,它能夠把代理對象做爲裝載對象方法的一個參數傳遞。
代理類的因此方法常常會用到回調(callback),固然你也可使用net.sf.cglib.proxy.CallbackFilter 有選擇的對一些方法使用回調(callback),這種考慮周詳的控制特性在JDK的動態代理中是沒有的。在JDK代理中,對 java.lang.reflect.InvocationHandler方法的調用對代理類的全部方法都有效。
CGLIB的代理包也對net.sf.cglib.proxy.Mixin提供支持。基本上,它容許多個對象被綁定到一個單一的大對象。在代理中對方法的調用委託到下面相應的對象中。
接下來咱們看看如何使 用CGLIB代理APIs建立代理。
一、建立一個簡單的代理
CGLIB代理最核心類net.sf.cglib.proxy.Enhancer, 爲了建立一個代理,最起碼你要用到這個類。首先,讓咱們使用NoOp回調建立一個代理。
[java] view plain copy
- /**
-
- * Create a proxy using NoOp callback. The target class
- * must have a default zero-argument constructor
- *
- * @param targetClass the super class of the proxy
- * @return a new proxy for a target class instance
- */
- public Object createProxy(Class targetClass) {
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(targetClass);
- enhancer.setCallback(NoOp.INSTANCE);
- return enhancer.create();
- }
返回值是target類一個實例的代理。在這個例子中,咱們爲net.sf.cglib.proxy.Enhancer 配置了一個單一的回調(callback)。咱們能夠看到不多直接建立一個簡單的代理,而是建立一個net.sf.cglib.proxy.Enhancer的實例,在net.sf.cglib.proxy.Enhancer類中你可以使用靜態幫助方法建立一個簡單的代理。通常推薦使用上面例子的方法建立代理,由於它容許你經過配置net.sf.cglib.proxy.Enhancer實例很好的控制代理的建立。
要注意的是,target類是做爲產生的代理的父類傳進來的。不一樣於JDK的動態代理,它不能在建立代理時傳target對象,target對象必須被CGLIB包來建立。在這個例子中,默認的無參數構造器時用來建立target實例的。若是你想用CGLIB來建立有參數的實例,用net.sf.cglib.proxy.Enhancer.create(Class[], Object[])方法替代net.sf.cglib.proxy.Enhancer.create()就能夠了。方法中第一個參數定義了參數的類型,第 二個是參數的值。在參數中,基本類型應被轉化成類的類型。
二、使用MethodInterceptor建立一個代理
爲了更好的使用代理,咱們可使用本身定義的MethodInterceptor類型回調(callback)來代替net.sf.cglib.proxy.NoOp回調。當對代理中全部方法的調用時,都會轉向MethodInterceptor類型的攔截(intercept)方法,在攔截方法中再調用底層對象相應的方法。下面咱們舉個例子,假設你想對目標對象的全部方法調用進行權限的檢查,若是沒有通過受權,就拋出一個運行時的異常AuthorizationException。其中AuthorizationService.java接口的代碼以下:
[java] view plain copy
- package com.lizjason.cglibproxy;
-
- import java.lang.reflect.Method;
-
- /**
- * A simple authorization service for illustration purpose.
- * @author Jason Zhicheng Li (jason@lizjason.com)
- */
- public interface AuthorizationService {
- void authorize(Method method);
- }
對net.sf.cglib.proxy.MethodInterceptor接口的實現的類AuthorizationInterceptor.java代碼以下:
[java] view plain copy
- package com.lizjason.cglibproxy.impl;
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
-
- import com.lizjason.cglibproxy.AuthorizationService;
-
- /**
- * A simple MethodInterceptor implementation to
- * apply authorization checks for proxy method calls.
- */
- public class AuthorizationInterceptor implements MethodInterceptor {
-
- private AuthorizationService authorizationService;
-
- /**
- * Create a AuthorizationInterceptor with the given AuthorizationService
- */
- public AuthorizationInterceptor (AuthorizationService authorizationService) {
- this.authorizationService = authorizationService;
- }
-
- /**
- * Intercept the proxy method invocations to inject authorization check. * The original
- * method is invoked through MethodProxy.
- */
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- if (authorizationService != null) {
- //may throw an AuthorizationException if authorization failed
- authorizationService.authorize(method);
- }
- return methodProxy.invokeSuper(object, args);
- }
- }
咱們能夠看到在攔截方法中,首先進行權限的檢查,若是經過權限的檢查,攔截方法再調用目標對象的原始方法。因爲性能的緣由,對原始方法的調用咱們使用CGLIB的net.sf.cglib.proxy.MethodProxy對象,而不是反射中通常使用java.lang.reflect.Method對象。
下面是一個完整的使用MethodInterceptor的例子。
[java] view plain copy
- package cglibexample;
-
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
-
- /**
- * 定義一個HelloWorld類,沒有實現接口
- *
- */
- class HelloWorld {
-
- public void sayHelloWorld() {
- System.out.println("HelloWorld!");
- }
- }
-
- /**
- * 經過Cglib實如今方法調用先後向控制檯輸出兩句字符串
- *
- */
- class CglibProxy implements MethodInterceptor {
-
- //要代理的原始對象
- private Object obj;
-
- public Object createProxy(Object target) {
- this.obj = target;
- Enhancer enhancer = new Enhancer();
- // 設置要代理的目標類,以擴展它的功能
- enhancer.setSuperclass(this.obj.getClass());
- // 設置單一回調對象,在回調中攔截對目標方法的調用
- enhancer.setCallback(this);
- //設置類裝載器
- enhancer.setClassLoader(target.getClass().getClassLoader());
- //建立代理對象
- return enhancer.create();
- }
-
- /**
- * 回調方法:在代理實例上攔截並處理目標方法的調用,返回結果
- *
- * @param proxy 代理類
- * @param method 被代理的方法
- * @param params 該方法的參數數組
- * @param methodProxy
- */
- @Override
- public Object intercept(Object proxy, Method method, Object[] params,
- MethodProxy methodProxy) throws Throwable {
- Object result = null;
- // 調用以前
- doBefore();
- // 調用目標方法,用methodProxy,
- // 而不是原始的method,以提升性能
- result = methodProxy.invokeSuper(proxy, params);
- // 調用以後
- doAfter();
- return result;
- }
-
- private void doBefore() {
- System.out.println("before method invoke");
- }
-
- private void doAfter() {
- System.out.println("after method invoke");
- }
- }
-
- public class TestCglib {
-
- public static void main(String[] args) {
- CglibProxy cglibProxy = new CglibProxy();
- HelloWorld hw = (HelloWorld) cglibProxy.createProxy(new HelloWorld());
- hw.sayHelloWorld();
- }
- }
輸出結果:
[plain] view plain copy
- before method invoke
- HelloWorld!
- after method invoke
基本流程:須要本身寫代理類,它實現MethodInterceptor接口,有一個intercept()回調方法用於攔截對目標方法的調用,裏面使用methodProxy來調用目標方法。建立代理對象要用Enhance類,用它設置好代理的目標類、有intercept()回調的代理類實例、最後用create()建立並返回代理實例。
三、使用CallbackFilter在方法層設置回調
net.sf.cglib.proxy.CallbackFilter容許咱們在方法層設置回調(callback)。假如你有一個PersistenceServiceImpl類,它有兩個方法:save和load,其中方法save須要權限檢查,而方法load不須要權限檢查。
[java] view plain copy
- import com.lizjason.cglibproxy.PersistenceService;
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.CallbackFilter;
-
- /**
- * A simple implementation of PersistenceService interface
- */
- class PersistenceServiceImpl implements PersistenceService {
-
- //須要權限檢查
- public void save(long id, String data) {
- System.out.println(data + " has been saved successfully.");
- }
-
- //不須要權限檢查
- public String load(long id) {
- return "Test CGLIB CallBackFilter";
- }
- }
-
- /**
- * An implementation of CallbackFilter for PersistenceServiceImpl
- */
- public class PersistenceServiceCallbackFilter implements CallbackFilter {
- //callback index for save method
- private static final int SAVE = 0;
- //callback index for load method
- private static final int LOAD = 1;
-
- /**
- * Specify which callback to use for the method being invoked.
- * @param method the method being invoked.
- * @return
- */
- @Override
- public int accept(Method method) {
- //指定各方法的代理回調索引
- String name = method.getName();
- if ("save".equals(name)) {
- return SAVE;
- }
- // for other methods, including the load method, use the
- // second callback
- return LOAD;
- }
- }
accept方法中對代理方法和回調進行了匹配,返回的值是某方法在回調數組中的索引。下面是PersistenceServiceImpl類代理的實現。
[java] view plain copy
- ...
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(PersistenceServiceImpl.class);
- //設置回調過濾器
- CallbackFilter callbackFilter = new PersistenceServiceCallbackFilter();
- enhancer.setCallbackFilter(callbackFilter);
- //建立各個目標方法的代理回調
- AuthorizationService authorizationService = ...
- Callback saveCallback = new AuthorizationInterceptor(authorizationService);
- Callback loadCallback = NoOp.INSTANCE;
- //順序要與指定的回調索引一致
- Callback[] callbacks = new Callback[]{saveCallback, loadCallback };
- enhancer.setCallbacks(callbacks); //設置回調
- ...
- return (PersistenceServiceImpl)enhancer.create(); //建立代理對象
在這個例子中save方法使用了AuthorizationInterceptor實例,load方法使用了NoOp實例。此外,你也能夠經過net.sf.cglib.proxy.Enhancer.setInterfaces(Class[])方法指定代理對象所實現的接口。
除了爲net.sf.cglib.proxy.Enhancer指定回調數組,你還能夠經過net.sf.cglib.proxy.Enhancer.setCallbackTypes(Class[]) 方法指定回調類型數組。當建立代理時,若是你沒有回調實例的數組,就可使用回調類型。象使用回調同樣,你必須使用net.sf.cglib.proxy.CallbackFilter爲每個方法指定一個回調類型索引。
四、使用Mixin
Mixin經過代理方式將多種類型的對象綁定到一個大對象上,這樣對各個目標類型中的方法調用能夠直接在這個大對象上進行。下面是一個例子。
[java] view plain copy
- import net.sf.cglib.proxy.Mixin;
-
- interface MyInterfaceA {
-
- public void methodA();
- }
-
- interface MyInterfaceB {
-
- public void methodB();
- }
-
- class MyInterfaceAImpl implements MyInterfaceA {
-
- @Override
- public void methodA() {
- System.out.println("MyInterfaceAImpl.methodA()");
- }
- }
-
- class MyInterfaceBImpl implements MyInterfaceB {
-
- @Override
- public void methodB() {
- System.out.println("MyInterfaceBImpl.methodB()");
- }
- }
-
- public class Main {
-
- public static void main(String[] args) {
- //各個對象對應的類型
- Class[] interfaces = new Class[]{MyInterfaceA.class, MyInterfaceB.class};
- //各個對象
- Object[] delegates = new Object[]{new MyInterfaceAImpl(), new MyInterfaceBImpl()};
- //將多個對象綁定到一個大對象上
- Object obj = Mixin.create(interfaces, delegates);
- //直接在大對象上調用各個目標方法
- ((MyInterfaceA)obj).methodA();
- ((MyInterfaceB)obj).methodB();
- }
- }
動態生成Bean
咱們知道,Java Bean包含一組屬性字段,用這些屬性來存儲和獲取值。經過指定一組屬性名和屬性值的類型,咱們可使用Cglib的BeanGenerator和BeanMap來動態生成Bean。下面是一個例子。
[java] view plain copy
- import java.lang.reflect.Method;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
- import net.sf.cglib.beans.BeanGenerator;
- import net.sf.cglib.beans.BeanMap;
-
- /**
- * 動態實體bean
- *
- * @author cuiran
- * @version 1.0
- */
- class CglibBean {
-
- //Bean實體Object
- public Object object = null;
- //屬性map
- public BeanMap beanMap = null;
-
- public CglibBean() {
- super();
- }
-
- @SuppressWarnings("unchecked")
- public CglibBean(Map<String, Class> propertyMap) {
- //用一組屬性生成實體Bean
- this.object = generateBean(propertyMap);
- //用實體Bean建立BeanMap,以即可以設置和獲取Bean屬性的值
- this.beanMap = BeanMap.create(this.object);
- }
-
- /**
- * 給bean中的屬性賦值
- *
- * @param property 屬性名
- * @param value 值
- */
- public void setValue(String property, Object value) {
- beanMap.put(property, value);
- }
-
- /**
- * 獲取bean中屬性的值
- *
- * @param property 屬性名
- * @return 值
- */
- public Object getValue(String property) {
- return beanMap.get(property);
- }
-
- /**
- * 獲得該實體bean對象
- *
- * @return
- */
- public Object getObject() {
- return this.object;
- }
-
- @SuppressWarnings("unchecked")
- private Object generateBean(Map<String, Class> propertyMap) {
- //根據一組屬性名和屬性值的類型,動態建立Bean對象
- BeanGenerator generator = new BeanGenerator();
- Set keySet = propertyMap.keySet();
- for (Iterator i = keySet.iterator(); i.hasNext();) {
- String key = (String) i.next();
- generator.addProperty(key, (Class) propertyMap.get(key));
- }
- return generator.create(); //建立Bean
- }
- }
-
- /**
- * Cglib測試類
- *
- * @author cuiran
- * @version 1.0
- */
- public class CglibTest {
-
- @SuppressWarnings("unchecked")
- public static void main(String[] args) throws ClassNotFoundException { // 設置類成員屬性
- HashMap<String, Class> propertyMap = new HashMap<>();
- propertyMap.put("id", Class.forName("java.lang.Integer"));
- propertyMap.put("name", Class.forName("java.lang.String"));
- propertyMap.put("address", Class.forName("java.lang.String")); // 生成動態Bean
- CglibBean bean = new CglibBean(propertyMap);
- // 給Bean設置值
- bean.setValue("id", 123); //Auto-boxing
- bean.setValue("name", "454");
- bean.setValue("address", "789");
- // 從Bean中獲取值,固然得到值的類型是Object
- System.out.println(" >> id = " + bean.getValue("id"));
- System.out.println(" >> name = " + bean.getValue("name"));
- System.out.println(" >> address = " + bean.getValue("address"));
- // 得到bean的實體
- Object object = bean.getObject();
- // 經過反射查看全部方法名
- Class clazz = object.getClass();
- Method[] methods = clazz.getDeclaredMethods();
- for (Method curMethod : methods) {
- System.out.println(curMethod.getName());
- }
- }
- }
輸出結果:
[java] view plain copy
- >> id = 123
- >> name = 454
- >> address = 789
- getAddress
- getName
- getId
- setName
- setId
- setAddress
CGLIB輕鬆實現延遲加載
經過使用LazyLoader,能夠實現延遲加載,即在沒有訪問對象的字段或方法以前並不加載對象,只有當要訪問對象的字段或方法時才進行加載。下面是一個例子。
[java] view plain copy
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.LazyLoader;
-
- class TestBean {
- private String userName;
-
- /**
- * @return the userName
- */
- public String getUserName() {
- return userName;
- }
-
- /**
- * @param userName the userName to set
- */
- public void setUserName(String userName) {
- this.userName = userName;
- }
- }
-
- //延遲加載代理類
- class LazyProxy implements LazyLoader {
-
- //攔截Bean的加載,本方法會延遲處理
- @Override
- public Object loadObject() throws Exception {
- System.out.println("開始延遲加載!");
- TestBean bean = new TestBean(); //建立實體Bean
- bean.setUserName("test"); //給一個屬性賦值
- return bean; //返回Bean
- }
- }
-
- public class BeanTest {
-
- public static void main(String[] args) {
- //建立Bean類型的延遲加載代理實例
- TestBean bean = (TestBean) Enhancer.create(TestBean.class, new LazyProxy());
- System.out.println("------");
- System.out.println(bean.getUserName());
- }
- }
輸出結果:
[java] view plain copy
- ------
- 開始延遲加載!
- test
咱們建立TestBean類的延遲代理,經過LazyLoader中的loadObject()方法的攔截,實現對TestBean類的對象進行延遲加載。從輸出能夠看出,當建立延遲代理時,並無馬上加載目標對象(由於還有輸出「開始延遲加載!」),當經過代理訪問目標對象的getUserName()方法時,就會加載目標對象。可見loadObject()是延遲執行的。