1.生活中代理
在生活中有好多都用到了代理,比如:去商店买苹果,商店就好比是一个代理,否则,我们需要去苹果园那里买苹果。
2.动态代理类
对于接口:JVM运行生成代理类,必须有接口。
对于普通类:对于没有接口的类可以cglib一个库生成一个类的子类,子类来实现该类方法,子类可以继承父类的所有方法。
3.动态代理原理图解
4.动态代理理解代码
package com.jn.proxy;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyTest {
/**
* @param args
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
System.out.println("=====================begin constructors list ======================");
Class<?> clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy.getName());
Constructor[] constructors = clazzProxy.getConstructors();
for(Constructor constructor: constructors){
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
// 获取构造器中的参数
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam:clazzParams){
sBuilder.append(clazzParam.getName()).append(",");
}
// 构造器没有参数处理。
if(clazzParams != null && clazzParams.length != 0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(")");
System.out.println(sBuilder.toString());
}
System.out.println("=====================begin methods list ======================");
Method[] methods = clazzProxy.getMethods();
for(Method method: methods){
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
// 获取构造器中的参数
Class[] clazzParams = method.getParameterTypes();
for(Class clazzParam:clazzParams){
sBuilder.append(clazzParam.getName()).append(",");
}
// 构造器没有参数处理。
if(clazzParams != null && clazzParams.length != 0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(")");
System.out.println(sBuilder.toString());
}
System.out.println("=====================begin create instance proxy list ======================");
// clazzProxy.newInstance();
class myInvocationHandler1 implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// System.out.println("invoke");
return null;
}
}
// 这里获取带参数的构造器,InvocationHandler.class只是构造器的参数类型,
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
// 进行实例化,需要构造器中参数的真正实例。实例化方法1
Collection proxy1 = (Collection)constructor.newInstance(new myInvocationHandler1());
// 返回为null,对象为null或toString方法返回null,在这里是toString返回为null
System.out.println(proxy1);
// 调用clear方法,没有问题
proxy1.clear();
// 调用size方法,
// 错误原因:在调用invoke的时候返回null,将无效无法转换为整数。
/**
* Exception in thread "main" java.lang.NullPointerException
at $Proxy0.size(Unknown Source)
at proxy.jn.ProxyTest.main(ProxyTest.java:81)
*/
// proxy1.size();
// 利用匿名内部类来实现构造器的实例化 实例化方法2
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
proxy2.clear();
// 实例化方法3
Collection proxy3 = (Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
ArrayList target = new ArrayList();
Long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
Long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " running time = " +(endTime - startTime));
return retVal;
}
});
proxy3.add("aaa");
proxy3.add("bbb");
proxy3.add("ccc");
// 因为每次调用add,调用3次都会调用invoke方法,ArrayList会创建3个不同的,
// 调用size方法又会创建一个新的ArrayList,所以显示结果为0
System.out.println(proxy3.size());
/**
* add running time = 0
add running time = 0
add running time = 0
size running time = 0
0
*/
// 实例化方法4 创建一个ArrayList
Collection proxy4 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[] { Collection.class },
new InvocationHandler() {
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
Long endTime = System.currentTimeMillis();
System.out.println(method.getName()
+ " running time = " + (endTime - startTime));
return retVal;
// 按照下面这样写将出现死循环
// method.invoke(proxy4, args);
}
});
// Object obj = proxy4.add("aaa");//代理的返回值,实际就是invoke方法的返回值。
proxy4.add("aaa");
proxy4.add("bbb");
proxy4.add("ccc");
// 因为每次调用add,调用3次都会调用invoke方法,ArrayList会创建1个相同的,
// 调用size方法又会创建一个新的ArrayList,所以显示结果为3
System.out.println(proxy4.size());
System.out.println(proxy4.getClass().getName());
/**
* add running time = 0
add running time = 0
add running time = 0
size running time = 0
3
*/
// 1.分析InvocationHandler对象运行原理,
/**
* public $Proxy0{
* private InvocationHandler handler;
// * 构造器
* public $Proxy0(InvocationHandler handler){
* this.handler = handler;
* }
* add(Objcet object){
* retrun handler.invoke(
* Object proxy,//objProxy对象
* Method method,//add方法
Object[] args//add方法的参数
);
* }
* size(){
* return handler.invoke(this.getClass,getMethod("size"),null);
* }
* }
* 在代理实例上的 java.lang.Object 中声明的 hashCode、equals 或 toString 方法
* 的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序
* 的 invoke 方法,如上所述。传递到 invoke 的 Method 对象的声明类是 java.lang.Object。
* 代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用
* 行为与其对 java.lang.Object 实例的操作一样。
*/
// 实例化方法5 创建一个更一般的代理
final ArrayList target = new ArrayList();
Collection proxy5 = (Collection)getProxy(target,new AdviceImpl());
proxy5.add("jiangning");
proxy5.size();
}
/**
* 需要将目标抽取为一个参数
* 需要将系统功能抽取为一个对象,我要调用你,你的名字我不知道,是通过接口来进行调用的。
* 定义一个契约来进行调用。
* @param target 目标
* @param advice 系统功能
* @return
*/
private static Object getProxy(final Object target,final Advice advice) {
Object proxy5 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
//与target实现相同的接口
target.getClass().getInterfaces(),
//new Class[] { Collection.class },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethos(method);
return retVal;
}
});
return proxy5;
}
}
package com.jn.proxy;
import java.lang.reflect.Method;
public interface Advice {
public void beforeMethod(Method method);
public void afterMethos(Method method);
}
package com.jn.proxy;
import java.lang.reflect.Method;
public class AdviceImpl implements Advice {
Long startTime = 0L;
@Override
public void beforeMethod(Method method) {
startTime = System.currentTimeMillis();
System.out.println("beforeMethod");
}
@Override
public void afterMethos(Method method) {
Long endTime = System.currentTimeMillis();
System.out.println(method.getName()
+ " running time = " + (endTime - startTime));
System.out.println("afterMethod");
}
}

4079

被折叠的 条评论
为什么被折叠?



