一、 有这样的需求,如果在不给一个目标的源代码的情况下,要为这个目标类增加一些系统功能,例如,异常处理,日志等等。程序需要怎么处理呢?这个时候就需要用到代理类了,编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同的方法,并在调用方法时,增加上系统功能的代码即可实现。
二、 下面我们来看看代理怎么创建和实例化的?
有3中方式来实例化:(1)内部类的实现方式(2) 上面的 匿名内部类的实现方式。(3) 将 JVM创建动态类及其的实例对象 合二为一的实现方式。 Proxy为我们提供了静态方法newProxyInstance
三、下面看看代码演示:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyDemo {
public static void main(String[] args) throws Exception{
//
Class clsProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);
System.out.println(clsProxy1.getName());
System.out.println("--------------begin constructors list------");
/*
* 按照下面的格式 打印
* $Proxy0()
* $Proxy0(InvocationHandler ,int)
*/
Constructor[] constructors =clsProxy1.getConstructors();
for(Constructor constructor: constructors){
String name =constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
// StringBuilder 和StringBuffer的区别 单线程的时候不用考虑同步安全,StringBuilder效率高。
//多线程的时候要考虑线程安全,StringBuffer才更好。
sBuilder.append('(');
Class[] claszzParams = constructor.getParameterTypes();
for(Class claszzParam: claszzParams){
sBuilder.append(claszzParam.getName()).append(',');
}
if(claszzParams !=null && claszzParams.length !=0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
Method[] methods =clsProxy1.getMethods();
for(Method method: methods){
String name =method.getName();
StringBuilder sBuilder = new StringBuilder(name);
// StringBuilder 和StringBuffer的区别 单线程的时候不用考虑同步安全,StringBuilder效率高。
//多线程的时候要考虑线程安全,StringBuffer才更好。
sBuilder.append('(');
Class[] claszzParams = method.getParameterTypes();
for(Class claszzParam: claszzParams){
sBuilder.append(claszzParam.getName()).append(',');
}
if(claszzParams !=null && claszzParams.length !=0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
System.out.println("--------begin 创建实例对象------");
// Object obj = clsProxy1.newInstance(); 只能实例化 无参的构造方法。
Constructor constructor = clsProxy1.getConstructor(InvocationHandler.class);
//(1)内部类的实现方式
class MyInvocationHandler1 implements InvocationHandler // 其实可以用匿名内部类来写
{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
//此处要是InvocationHandler的一个对象,而InvocationHandler是一个接口,所以只能new他的实现类。
Collection proxy1=(Collection)constructor.newInstance(new MyInvocationHandler1());
System.out.println(proxy1);// 结果为null ,可能对象是null,也可能proxy.toString返回的是null。但是如果对象为null,会发生空指针异常。
proxy1.clear(); //返回值为 void
// proxy1.size(); // 返回值为 int
//(2) 上面的 匿名内部类的实现方式。
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
// (3) 将 JVM创建动态类及其的实例对象 合二为一的实现方式。 Proxy为我们提供了静态方法newProxyInstance
Collection proxy3 = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(), // 第一个参数 类加载器
new Class[]{Collection.class},// 第二个参数 接口的数组, 注意是 大括号。
new InvocationHandler(){ // 第三个参数 handler的实例对象
ArrayList target =new ArrayList();
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
//如何把 要在代理中添加的功能,封装成一对象,作为参数,而不是生硬的把功能写在里面。详细参考ProxyDemo1
System.out.println(method.getName()+"running time of"+(endTime-beginTime));
return retVal;
}
});
// 每调用一次add 都会调用一次InvocationHandler的invoke方法,代理对象,代理对象的方法,代理对象的方法参数这三要素传递给invoke。
proxy3.add("zxx");
//代理对象proxy3,代理对象的方法add,代理对象的方法参数"zxx",这3个参数传递给代理对象的invoke。然后执行完InvocationH andler()
//的返回值 是一个Object,其实就相当于 Object obj = proxy3.add("zxx");
proxy3.add("bxd");
proxy3.add("lhm");
System.out.println(proxy3.size());
}
}