编码列出动态类中的所有构造方法和参数签名
编码列出动态类中的所有方法和参数签名
package javatribe.fts.proxy;
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;
/*
* 用JAVA API创建一个动态类,动态类要接收一个InvocationHander对象,并让动态类去创建一个实例对象
*/
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//Proxy.getProxyClass返回代理类的 java.lang.Class 对象
//Collection.class.getClassLoader()返回类加载器
Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("~~~~~~~~~~~~~取出构造方法的开端~~~~~~~~~~~");
//得到$Proxy0代理类的所有构造方法
Constructor[] constructors=clazzProxy1.getConstructors();
//增强for循环,迭代器取出数据
for(Constructor constructor : constructors){
String name=constructor.getName();
System.out.println("获取到的构造方法名称是:"+name);
StringBuilder sBuilder=new StringBuilder(name);
sBuilder.append('[');
//取出$Proxy0此构造方法有哪些参数值
Class[] classParams=constructor.getParameterTypes();
for(Class classParam :classParams){
System.out.println("构造方法的参数为:"+classParam.getName());
sBuilder.append(classParam.getName()).append(',');
}
//去掉最后一个参数后面的逗号
if(classParams!=null&&classParams.length!=0){
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(']');
System.out.println(sBuilder.toString());
}
System.out.println("~~~~~~~~~~~~~取出构造方法的结束~~~~~~~~~~~");
System.out.println("~~~~~~~~~~~~~取出方法开端~~~~~~~~~~~");
//取出所有代理类的方法
Method[] methods=clazzProxy1.getMethods();
for(Method method : methods){
//取出方法的参数值
String name=method.getName();
//用StringBuilder拼凑出类似add(java.lang.Object)的类型出来
StringBuilder sBuilder=new StringBuilder(name);
sBuilder.append('(');
//得到方法的参数值
Class[] classParams=method.getParameterTypes();
for(Class classParam :classParams){
//把取出的方法的参数值append到StringBuilder中去
sBuilder.append(classParam.getName()).append(',');
}
if(classParams!=null&&classParams.length!=0){
//如果方法有多个参数,则去掉参数最有一个多余的逗号
sBuilder.deleteCharAt(sBuilder.length()-1);
}
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
System.out.println("~~~~~~~~~~~~~取出所有方法结束~~~~~~~~~~~");
//开始创建实例对象
Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);
//方法一实现的方式
class MyInvocationHandler1 implements InvocationHandler{
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.getClass().getName());
//方法二用匿名内部类实现也可以
/* Collection proxy8= (Collection) constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});*/
System.out.println(proxy1);
//清除集合,没有报错,说明有值
proxy1.clear();
//size()方法有返回值,所以会报错
//proxy1.size();
//创建代理对象的第二种实现方式
Collection proxy3=(Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
);
//方法里面的内部类要访问局部变量,必须加上final修饰
final ArrayList target=new ArrayList();
Collection proxy2 = (Collection) getProxy(target,new MyAdvice());
//实现一个ADD方法,调用一次InvocationHandler中的invoke方法一次
proxy2.add("xxx");
//proxy2.add("aaa");的含义proxy2代理调用add方法传入的参数是"aaa"
proxy2.add("aaa");
proxy2.add("bbb");
proxy2.add("ccc");
System.out.println(proxy2.size());
System.out.println("代理的名称==="+proxy2.getClass().getName());
}
//target表示目标对象,advice表示的是系统功能
private static Object getProxy(final Object target,final Advice advice) {
Object proxy2=Proxy.newProxyInstance(
// target.getClass()得到目标类在内存的字节码,然后获得它的类加载器
target.getClass().getClassLoader(),
//new Class[]{Collection.class},
//得到目标类的接口
target.getClass().getInterfaces(),
new InvocationHandler(){
//proxy表示调用哪个代理对象,method表示调用代理对象的哪个方法,args表示代理对象中方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
//method.invoke(target, args);表示方法method正在执行的方法,
//在target代理对象执行的方法,这个方法传入的参数为args
//调用目标代码
Object retValue=method.invoke(target, args);
advice.afterMethod(method);
//retValue表示目标的方法返回的结果
return retValue;
}
}
);
return proxy2;
}
}
package javatribe.fts.proxy;
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long beginTime=0;
public void afterMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("~~~~~~~~~开始运行时间~~~~~~~");
long endTime=System.currentTimeMillis();
System.out.println(method.getName()+" 运行时间 "+(endTime-beginTime));
}
public void beforeMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("~~~~~~~~~结束运行时间~~~~~~~");
beginTime=System.currentTimeMillis();
}
}
package javatribe.fts.proxy;
import java.lang.reflect.Method;
public interface Advice {
void beforeMethod(Method method);
void afterMethod(Method method);
}
输出结果如下:
$Proxy0
~~~~~~~~~~~~~取出构造方法的开端~~~~~~~~~~~
获取到的构造方法名称是:$Proxy0
构造方法的参数为:java.lang.reflect.InvocationHandler
$Proxy0[java.lang.reflect.InvocationHandler]
~~~~~~~~~~~~~取出构造方法的结束~~~~~~~~~~~
~~~~~~~~~~~~~取出方法开端~~~~~~~~~~~
add(java.lang.Object)
hashCode()
clear()
equals(java.lang.Object)
toString()
contains(java.lang.Object)
isEmpty()
addAll(java.util.Collection)
iterator()
size()
toArray([Ljava.lang.Object;)
toArray()
remove(java.lang.Object)
containsAll(java.util.Collection)
removeAll(java.util.Collection)
retainAll(java.util.Collection)
isProxyClass(java.lang.Class)
getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
getInvocationHandler(java.lang.Object)
newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
wait()
wait(long,int)
wait(long)
getClass()
notify()
notifyAll()
~~~~~~~~~~~~~取出所有方法结束~~~~~~~~~~~
这是一个代理的名称====$Proxy0
null
~~~~~~~~~结束运行时间~~~~~~~
~~~~~~~~~开始运行时间~~~~~~~
add 运行时间 17
~~~~~~~~~结束运行时间~~~~~~~
~~~~~~~~~开始运行时间~~~~~~~
add 运行时间 1
~~~~~~~~~结束运行时间~~~~~~~
~~~~~~~~~开始运行时间~~~~~~~
add 运行时间 0
~~~~~~~~~结束运行时间~~~~~~~
~~~~~~~~~开始运行时间~~~~~~~
add 运行时间 0
~~~~~~~~~结束运行时间~~~~~~~
~~~~~~~~~开始运行时间~~~~~~~
size 运行时间 0
4
代理的名称===$Proxy1
通过以上程序分析分析动态生成的类的内部代码
动态生成的类实现了Collection接口(可以实现若干接口),生成的类有Collection接口中的所有方法和一个如上接受InvocationHandler参数的构造方法。
构造方法接受一个InvocationHandler对象,接受对象了要干什么用呢?该方法内部的代码会是怎样的呢?
实现Collection接口的动态类中的各个方法的代码又是怎样的呢?InvocationHandler接口中定义的invoke方法接受的三个参数又是什么意思?图解说明如下:
分析为什么动态类的实例对象的getClass()方法返回了正确结果呢?
调用调用代理对象的从Object类继承的hashCode, equals, 或toString这几个方法时,代理对象将调用请求转发给InvocationHandler对象,对于其他方法,则不转发调用请求。
怎样将目标类传进去?
直接在InvocationHandler实现类中创建目标类的实例对象,可以看运行效果和加入日志代码,但没有实际意义。
为InvocationHandler实现类注入目标类的实例对象,不能采用匿名内部类的形式了。让匿名的InvocationHandler实现类访问外面方法中的目标类实例对象的final类型的引用变量。将创建代理的过程改为一种更优雅的方式,eclipse重构出一个getProxy方法绑定接收目标同时返回代理对象,让调用者更懒惰,更方便,调用者甚至不用接触任何代理的API。
将系统功能代码模块化,即将切面代码也改为通过参数形式提供,怎样把要执行的系统功能代码以参数形式提供?
把要执行的代码装到一个对象的某个方法里,然后把这个对象作为参数传递,接收者只要调用这个对象的方法,即等于执行了外界提供的代码!为bind方法增加一个Advice参数。