----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
Blog14_1分析代理类的作用
(1) 动态代理类
动态代理类:在运行时能动态的生成一个实现了指定接口的类。
注意事项:动态代理中的实现并不是真正的实现。真正实现接口还得写一个类,而这个类产生的对象,我们叫做“目标对象”。
(2) 动态代理的作用
作用:使得我们在使用目标类的同时能增加附属的功能。
例子:别人提供一个加密的class文件给我们,我们想在调用它其中的任何方法时都能附加上我们自己特有的东西,这时就可以使用动态代理了。
Blog14_2 JVM动态生成类
(3) 创建一个实现Collection接口的动态类
使用Proxy类的getProxyClass()方法可以获取实现一个接口的动态类,如下:
Class clazz=Proxy.getProxyClass(null,Collection.class);
(4) 写代码获取此动态类的所有方法和此类的构造方法
Constructor[] constructors = clazz.getConstructors();
System.out.println("-------------------构造方法列表----------------");
for (Constructor constructor : constructors) {
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name + "(");
Class[]praraClazz = constructor.getParameterTypes();
for (Class praraName: praraClazz) {
sb.append(praraName.getName());
}
sb.append(")");
System.out.println(sb);
}
System.out.println("-------------------方法列表----------------");
Method[]methods = clazz.getMethods();
for (Method method :methods) {
String name = method.getName();
StringBuilder sb = new StringBuilder(name + "(");
Class[]paraName = method.getParameterTypes();
for (ClassparaNameClazz : paraName) {
sb.append(paraNameClazz.getName());
}
sb.append(")");
System.out.println(sb);
}
输出结果为:
-------------------构造方法列表----------------
com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
-------------------方法列表----------------
add(java.lang.Object)
remove(java.lang.Object)
equals(java.lang.Object)
toString()
hashCode()
clear()
contains(java.lang.Object)
isEmpty()
size()
toArray()
toArray([Ljava.lang.Object;)
addAll(java.util.Collection)
iterator()
containsAll(java.util.Collection)
removeAll(java.util.Collection)
retainAll(java.util.Collection)
isProxyClass(java.lang.Class)
getInvocationHandler(java.lang.Object)
getProxyClass(java.lang.ClassLoader[Ljava.lang.Class;)
newProxyInstance(java.lang.ClassLoader[Ljava.lang.Class;java.lang.reflect.InvocationHandler)
wait(longint)
wait(long)
wait()
getClass()
notify()
notifyAll()
---------------------------------------------------------------------------
由上面的输出结果分析可知,生成的动态类,具备了Collection和其父类的所有方法,而且还有一个带参数的构造方法,构造函数的参数为InvocationHandler类型的一个实例对象,查找ApI发现InvocationHandler是一个接口,故传递的对象为此接口的子类实现类的实例对象。
Blog14_3 JVM创建动态类的实例对象
(1)首先使用字节码文件对象,获取构造器对象
由上面的列子我们可知动态类的构造方法为:com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
传递的参数为InvocationHandler对象,故获取构造器对象时传递的参数应该是 InvocationHandler.class如下:
Constructor con=clazz.getConstructor(InvocationHandler.class);
(2)然后使用构造器对象调用newInstance创建对象。如下:
Collection collect=(Collection)con.newInstance(newInvocationHandler );但此时发现InvocationHandler是接口,不能直接创建对象,故我们使用匿名内部类的方法创建接口InvocationHandler的对象。代码如下:
Constructor con= clazz.getConstructor(InvocationHandler.class);
Collection collect=(Collection)con.newInstance(new InvocationHandler(){
ArrayList arr=new ArrayList();
@Override
public Object invoke(Objectproxy, Method method, Object[] args)
throws Throwable {
Object obj=method.invoke(arr,args);
return obj;
}
});
上面创建动态类实例对象的过程是:先得到Proxy类的字节码文件对象,利用字节码文件对象得到构造器对象,使用构造器对象调用
newInstance()方法得到代理对象。
(5) 另外一种创建动态类实例对象的简便方法
使Proxy类提供的静态方法:
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
代码如下:
Collection coll=(Collection)Proxy.newProxyInstance(null, new Class[]{Collection.class}, new InvocationHandler() {
ArrayList arr=new ArrayList();
@Override
public Object invoke(Objectproxy, Method method, Object[] args)
throws Throwable {
System.out.println("增强啦。。。");
Object obj=method.invoke(arr, args);
return obj;
}
});
此种方法相比第一种方法更简单直接,提倡使用第二种方法。
(6) 使用动态代理对象调用动态类中的方法
如上面例子:
collect.add("动态代理1");
collect.add("动态代理2");
collect.add("动态代理3");
System.out.println(collect);
输出的结果为:
"增强啦。。。"
"增强啦。。。"
"增强啦。。。"
"增强啦。。。"
[动态代理1,动态代理2,动态代理3]
分析可知:每当动态代理对象每调用一次方法,都会先调用invoke方法。并且每次调用方法的返回值实际为invoke方法的返回值。
动态代理中invoke方法注意事项:
A. 每当动态代理对象每调用一次方法,都会先调用invoke方法;
B. 动态代理对象调用方法后返回值均为invoke方法的返回值;
C. 调用的方法实质上是目标对象当中的方法,而不是动态代理类中的(动态代理知识拥有了接口中的抽象方法,而并没有去实现它);
D. 利用A的原理,我们可以再invoke方法中加上附加的功能达到:调用所用的方法时都同时能使用我们自己的附加功能;
E.父类中带有native修饰的方法不会调用invoke方法。
Blog14_4 一个动态代理工厂的实现
需求:封装一个类,让这个类拥有一个创建代理对象的方法,当外界向这个类传递包含:目标对象、增强操作对象、接口的参数时,这个类能自动创建所需的动态代理对象,并且还具有增强的功能。
实现代码实现如下:
public class ProxyFactory {
private ClassLoader loader=ProxyFactory.class.getClassLoader();
private Class[]interfaces;
private Object target;
private Before before;
private After after;
public ProxyFactory(Class[]interfaces, Object target, Before before,After after) {
super();
this.interfaces = interfaces;
this.target = target;
this.before = before;
this.after = after;
}
public Object creatProxy(){
Objectobj=Proxy.newProxyInstance(
loader, //第一个参数
interfaces, //第二个参数
new InvocationHandler(){ //第三个参数
@Override
public Object invoke(Objectproxy, Method method, Object[] args)
throws Throwable {
before.beforShow();
//注意:动态代理的目标对象,必须是实现了接口的对象。
Object resultObj=method.invoke(target, args);
after.afterShow();
//System.out.println(resultObj);
return resultObj;
}
}
);
return obj;
}
如上面代码:创建这个类的对象,当向构造方法中传递需要实现的接口数组interfaces、实现接口的目标对象target、增强操作的对象Before before,After after。再调用creatProxy()方法就能创建实现这些接口的动态代理对象了。这样当动态代理对象调用接口中所拥有的方法时,还会在invoke的前面或者后面使用我们自己的增强功能。
----------------------- android培训、java培训、java学习型技术博客、期待与您交流! ----------------------
详情请查看: