上一篇说到的静态代理,但是有新的接口,就需要新的代理,那么我们需要一个动态代理。java.lang.reflect包里,有个封装类Proxy,正好解决这个问题。
有很多很多的人都说过Proxy,无非就是这行代码的作用,Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)根据参数(接口),以反射机制生成动态代理,执行相应接口方法。
1、参数(接口)
/**
* 公共接口
* @author Biligle
*
*/
public interface IPublicManager {
/**
* 排水
*/
void out();
/**
* 发电
*/
void power();
/**
* 净化
*/
void clean(String params);
}
/**
* 生成动态代理,执行接口方法
* @author Biligle
*
*/
public class ProxyUtil {
public <T> Object create(Class<T> service){
if(!service.isInterface()){
new IllegalArgumentException("API声明必须是接口");
}else if(service.getInterfaces().length > 0){
new IllegalArgumentException("API接口不能扩展其他接口");
}
/**
* ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:
*/
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
/**
* proxy 代理对象
* method 接口方法
* args 接口方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//无论代理去执行哪个method,首先统一执行一个方法common,之后,在分别执行各自方法
//简言之,这里可以添加公共方法
BasicVoid.common(method,args);
return null;
}
});
}
}
/**
* 代理模式统一执行方法
* @author Biligle
*
*/
public class BasicVoid {
static void common(Method method, Object[] args){
System.out.println("接收到" + method.getName() + "接口" + "+parmas" + ":" + args[0]);
System.out.println("给" + method.getName() + "接口方法返回相应数据");
}
}
测试
public class Test {
public static void main(String[] args) {
ProxyUtil p = new ProxyUtil();
IPublicManager iPublic = (IPublicManager) p.create(IPublicManager.class);
iPublic.clean("纯净水");
}
}
测试结果:
接收到clean接口+parmas:纯净水
给clean接口方法返回相应数据
大家应该发现了,我们没有去实现clean方法,而是用BasicVoid.common(method,args)做了统一处理,这样的好处是,我们又少写了一个实现类。
下面,我们写一下处理逻辑,这里需要一个接口,来给clean返回一些相应数据。
对BasicVoid修改如下:
/**
* 代理模式统一执行方法
* @author Biligle
*
*/
public class BasicVoid {
private BasicVoid(){}
private static VisitListener listener;
private static Object data;
public static BasicVoid basicVoid = null;
public static BasicVoid get(){
if(basicVoid == null){
basicVoid = new BasicVoid();
}
return basicVoid;
}
public BasicVoid common(Method method, Object[] args){
data = visit(method.getName());
return basicVoid;
}
/**
* 传入接口,用于监听返回数据
* @param l
* @return
*/
public BasicVoid call(VisitListener l){
listener = l;
listener.callData(data);
return basicVoid;
}
/**
* 统一标准访问,并返回相应数据
* @param method
* @return
*/
private Object visit(String method){
return method;
}
/**
* 获取数据的监听
*/
interface VisitListener {
/**
* 回调数据
* @param obj
*/
void callData(Object obj);
}
}
对ProxyUtil修改如下:
/**
* 生成动态代理,执行接口方法
* @author Biligle
*
*/
public class ProxyUtil implements BasicVoid.VisitListener {
public <T> Object create(Class<T> service){
if(!service.isInterface()){
new IllegalArgumentException("API声明必须是接口");
}else if(service.getInterfaces().length > 0){
new IllegalArgumentException("API接口不能扩展其他接口");
}
/**
* ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:
*/
return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
/**
* proxy 代理对象
* method 接口方法
* args 接口方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//无论代理去执行哪个method,首先统一执行一个方法common,之后,在分别执行各自方法
//简言之,这里可以添加公共方法
BasicVoid.get().common(method, args).call(ProxyUtil.this);
return null;
}
});
}
@Override
public void callData(Object obj) {
System.out.println("返给了" + obj);
}
}
测试结果
返给了clean
好了,最后在强调一下代理模式的核心概念
根据参数(接口IPublicManager.class),以反射机制生成动态代理,执行相应接口方法(clean)。