JDK和CGLib兩種方式實現動態代理模式

這篇文章主要介紹利用JDK和cgLib兩種方式實現動態代理模式的實例。


1. 利用JDK中的類

在JDK中的動態代理用到了兩個類:Proxy和InvocationHandler,如下:

1.1 抽象主題

抽象主題的Java代碼如下:

public interface Hello {
	void sayHello(String to);
	void print(String p);
}

1.2 實際主題

實際主題的Java代碼如下:

public class HelloImpl implements Hello {
	@Override
	public void sayHello(String to) {
		System.out.println("Say Hello to " + to);
	}
	@Override
	public void print(String p) {
		System.out.println("print : " + p);
	}
}

1.3 代理

代理要實現的功能爲:在sayHello()和print()兩個方法前後加了Log日誌。代理類的代碼如下:

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

public class LogHandler implements InvocationHandler {
	private Object dele; //被代理對象傳進來了

	public LogHandler(Object obj) {
		this.dele = obj;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		doBefore();
		// 在這裏完全可以把下面這句註釋掉,而做一些其它的事情
		Object result = method.invoke(dele, args);
		doAfter();
		return result;
	}

	private void doBefore() {
		System.out.println("before....");
	}

	private void doAfter() {
		System.out.println("after....");
	}
}

1.4測試運行

import java.lang.reflect.Proxy;

public class ProxyTest {
	public static void main(String[] args) {
		Hello impl = new HelloImpl();
		LogHandler handler = new LogHandler(impl);
		// 這裏把handler與impl新生成的代理類相關聯
		Hello hello = (Hello) Proxy.newProxyInstance(
				impl.getClass().getClassLoader(), 
				impl.getClass().getInterfaces(), handler);

		// 這裏無論訪問哪個方法,都是會把請求轉發到handler.invoke
		hello.print("All the test");
		hello.sayHello("Denny");
	}
}

其運行結果如下:

這樣,通過動態代理,就成功的在sayHello()和print()兩個方法前後加了Log日誌。


2. 利用cgLib中的類

下面這個例子展現了利用cgLib實現對ArrayList進行攔截,在在add或addAll元素的之前,會實行攔截操作,執行相關操作後再添加到ArrayList中去。

2.1 代理(攔截器)

import java.lang.reflect.Method;
import java.util.List;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 利用cglib的動態代理方法。java.util.List的攔截器,在add或addAll元素的之前,
 * 會實行攔截操作, 執行相關操作後再添加到ArrayList中去。<br>
*/
public class ListAddMethodInterceptor implements MethodInterceptor {
	@Override
	@SuppressWarnings("unchecked")
	public Object intercept(Object object, Method method,
                        Object[] args, MethodProxy methodProxy)
			throws Throwable {
		//函數體的執行
		if(args != null && args.length >= 1) {
			if(method.getName().equals("add")) { //add方法
				addedThing = (T) args[0]; //被添加的對象
				//進行過濾操作,在線化簡時,這裏就是執行局部搜索策略
				doSomething();
			} else if(method.getName().equals("addAll")) {
				List<IChromosome> list = (List<IChromosome>) args[0];
				for(int i=0; i<list.size(); i++) {
					addedThing = (T)list.get(i); //被添加的對象
					//進行過濾操作,在線化簡時,這裏就是執行局部搜索策略
					doSomething ();
				}
			}
		}
		
		//攔截完畢,放行
		Object result = methodProxy.invokeSuper(object, args);
		return result; 
	}
}


2.2 主要的調用方法

針對上述代理,其調用方式如下:

import net.sf.cglib.proxy.Enhancer;
// 設置java.util.List的動態代理
Enhancer en = new Enhancer();
// 進行代理
en.setSuperclass(java.util.ArrayList.class);
en.setCallback(new ListAddMethodInterceptor(pts, distanceTolerance));
// en.setCallbackFilter(new ListCallbackFilter());
@SuppressWarnings("unchecked")
List<IChromosome> popu = (List<IChromosome>) en.create();
// 動態代理設置結束

3 cgLib與JDK相比的優勢

cgLib與JDK相比最大的好處就是不再需要主題有抽象接口。例如HelloImpl類,如果它沒有Hello接口則無法使用動態代理,而利用cgLib則沒有這方面的限制。


全文完。轉載請註明出處。


發佈了52 篇原創文章 · 獲贊 17 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章