JVM动态生成的类演示和分析

    创建实现了Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数。
     编码列出动态类中的所有构造方法和参数签名

     编码列出动态类中的所有方法和参数签名


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参数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值