这篇文章主要介绍利用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则没有这方面的限制。
全文完。转载请注明出处。