------- android培训、java培训、期待与您交流! ---------
1.什么是代理?
一种用于转发请求,进行特殊处理的机制。“动态”指的是运行期。
2.为什么使用动态代理?
可以对请求进行任何处理
3.使用它有什么好处?
4.哪些地方需要动态代理?
不允许直接访问某些类,对访问要做特殊处理。
AOP面向方面的编程:
系统中存在许多交叉业务,一个交叉业务就是要切入到系统的一个方面。
同样的动作会在不同的模块中,这些动作就是模块的交叉业务。
可以把这些交叉业务都当做一个切面:
交叉业务的编程问题即为面向方面的编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采
用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:
使用代理技术可以解决aop的核心技术。
jvm可以在运行期动态生产出一个类,这种动态生成的类往往北用作代理,既动态代理。
动态类必须实现一个或多个接口。
CGLIB可以生成没有实现接口和类的动态代理。
package cn.jhc.day3;
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 ProxyTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//Proxy.getProxyClass(类加载器, 接口)
Class classProxy1 =
Proxy.getProxyClass(Collection.class.getClassLoader(),
Collection.class);
//System.out.println(classProxy1.getName());
System.out.println("----begin constructors list ----");
/*
* $Proxy0()
* $Proxy0(InvocationHandler,int)
* */
//获取类的所有构造方法。
Constructor[] constructors = classProxy1.getConstructors();
for (Constructor constructor : constructors) {
//得到构造方法名
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
//性能比buffer高
sBuilder.append('(');
//得到构造方法的参数
Class[] classParams = constructor.getParameterTypes();
for (Class classParam : classParams) {
sBuilder.append(classParam.getName()).append(',');
}
if(classParams.length != 0 && classParams != null)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
System.out.println("----begin methods list ----");
/*
* $Proxy0()
* $Proxy0(InvocationHandler,int)
* */
//得到所有方法
Method[] methods = classProxy1.getMethods();
for (Method method : methods) {
//得到方法名
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
//性能比buffer高
sBuilder.append('(');
//得到方法的参数
Class[] classParams = method.getParameterTypes();
for (Class classParam : classParams) {
sBuilder.append(classParam.getName()).append(',');
}
if(classParams.length != 0 && classParams != null)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
System.out.println("----begin create instance object ----");
//classProxy1.newInstance();
//得到构造方法
Constructor constructor = classProxy1.getConstructor(InvocationHandler.class);
//InvocationHandler是一个接口
// class MyInvocationHandler1 implements InvocationHandler{
//
// @Override
// public Object invoke(Object proxy, Method method, Object[] args)
// throws Throwable {
// // TODO Auto-generated method stub
// return null;
// }
//
// }
// Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
// System.out.println(proxy1);
// proxy1.clear();
// //proxy1.size();
//
//创建代理对象,创建匿名内部接口
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
//实现接口的invoke方法。
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
final ArrayList target = new ArrayList();
Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
proxy3.add("zxx");
proxy3.add("bxd");
proxy3.add("bad");
System.out.println(proxy3.size());
}
private static Object getProxy(final Object target,final Advice advice) {
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
// new Class[]{Collection.class},
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
// long beginTime = System.currentTimeMillis();
// Object retVal = method.invoke(target, args);
// long endTime = System.currentTimeMillis();
// System.out.println(method.getName() + " running time of " + (endTime - beginTime));
// return retVal;
//在目标前实现自己的方法
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
//在目标后实现自己的方法
advice.afterMethod(method);
return retVal;
}
});
return proxy3;
}
}
总结一下需要注意的地方:
目标方法要求返回的值类型与代理类返回的值类型应当保持一致;
newProxyInstance()方法可以得到一个动态代理类,它需要接受3个参数
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
Loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载。
Interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。
InvocationHandler中需要实现的invoke()方法接受三个参数
invoke(Object proxy, Method method,Object[] args)
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
这个invoke方法要用到这些参数的原因是:代理类要去找目标类的方法并调用,然后返回。