----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
首先总结下代理,本人理解的代理就是客户端和访问目标之间的中介,例如,客户端要访问一个对象,可以通过代理来访问,而不用直接访问对象,但是代理需要和目标对象实现相同的接口,这属于一种规范,只有实现相同的接口,代理才能知道目标对象都有什么方法,因为他们都要实现接口中的所有方法。
如何创建代理,java虚拟机(jvm)提供了一个创建代理的方法,通过Proxy.getProxyClass()方法获得代理类,这个方法需要传入两个参数,一个是需要实现的类加载器,第二个参数是目标的字节码文件。通过反射机制可以获得代理的构造函数和方法,发现代理只有一个有参构造函数,参数类型是需要实现InvocationHandler接口。而InvocationHandler接口需要实现一个invoke方法。所以这时候就想到用匿名内部类的方式来传入实现InvocationHandler接口的匿名内部类。
具体实现代码:
以下代码是获得代理的构造函数以及方法的实现。
下面例子是获得Collection集合的代理,可以通过这个例子来了解代理的使用方法。
Class classProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
Constructor[] constructors = classProxy1.getConstructors();
for(Constructor constructor : constructors)
{
String nameC = constructor.getName();
StringBuilder sBulider = new StringBuilder(nameC);
sBulider.append('(');
Class[] classPars = constructor.getParameterTypes();
for(Class classpar : classPars)
{
sBulider.append(classpar.getName()).append(',');
}
if(classPars!=null && classPars.length!=0)
sBulider.deleteCharAt(sBulider.length()-1);
sBulider.append(')');
System.out.println(sBulider.toString());
}
Method[] methods = classProxy1.getMethods();
for(Method method : methods)
{
String nameC = method.getName();
StringBuilder sBulider = new StringBuilder(nameC);
sBulider.append('(');
Class[] classPars = method.getParameterTypes();
for(Class classpar : classPars)
{
sBulider.append(classpar.getName()).append(',');
}
if(classPars!=null && classPars.length!=0)
{sBulider.deleteCharAt(sBulider.length()-1);}
sBulider.append(')');
System.out.println(sBulider.toString());
}
下面代码是通过传递匿名内部类方式来获得Collection的代理。
Collection Proxy1 = (Collection)constructor.newInstance(new InvocationHandler()
{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
ArrayList target = new ArrayList();
//可以在方法之前加入其它功能
Object retVal = method.invoke(proxy, args);
//可以在方法之后加入功能
// TODO Auto-generated method stub
return retVal;
}
});
那么既然要实现动态代理,有没有更好的方法可以将这三个参数都传进一个方法中实现动态代理呢,这时候就用到Proxy.newProxyInstance(loader, interfaces, h)方法,这个方法需要传递三个参数,目标类加载器、要实现的接口的集合、实现InvocationHandler接口的参数。通过这个方法就可以实现一步创建代理。
以下代码是老师讲的实例,我认为非常容易理解。
将创建代理的方法抽取出来,名字为getProxy(),通过传入接口的实现类来对目标函数添加功能。
private static Object getProxy(final Object target,final Advice advice) {
Object Proxy3 = (Object)Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
//System.out.println(start);
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.AfterMethod(method);
return retVal;
}
}
);
return Proxy3;
}
}
以下代码是实现Advice接口的实现类和Advice接口 这种方式也叫做契约:
Spring中的面向切面的编程就是用代理实现的。
package com.itheima;
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long start=0;
@Override
public void AfterMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("执行方法之前的时间");
start = System.currentTimeMillis();
}
@Override
public void beforeMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("执行目标方法之后的时间");
long end = System.currentTimeMillis();
//System.out.println(end);
System.out.println(method.getName()+"end-start::"+(end-start));
}
}
package com.itheima;
import java.lang.reflect.Method;
public interface Advice {
void beforeMethod(Method method);
void AfterMethod(Method method);
}