這篇文章主要介紹利用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則沒有這方面的限制。
全文完。轉載請註明出處。