java高新技术(五)

Java中利用代理(Proxy)可以在运行时创建一个实现了一组给定接口的新类spring用的就是这个原理,如何没有实现特定接口可以通过CGLIB库来创建。

 Proxy类的特性:

   1.代理(Proxy)类只有一个实例变量,即调用处理器(InvocationHandler)

   2.代理类需要的额外数据都必须存储在调用处理器中

   3.代理类一定是public和final.

   4.如果代理类实现的所有接口都是public,则代理类就不属于某个特定的包;否则所有的非公有接口都必须属于同一个包,代理类也属于这个包(此设定的目的是确定代理类的所属包)

public class ProxyTest {


	public static void main(String[] args) throws Exception{
		//创建代理类,通常用接口的那个类加载器
		Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		System.out.println(clazzProxy1.getName());
		
		System.out.println("----------begin constructors list----------");
		/*$Proxy0()代理类的名字
		$Proxy0(InvocationHandler,int)*/
		//得到所有的构造方法
		Constructor[] constructors = clazzProxy1.getConstructors();
		//用for循环加强逐一取出构造方法
		for(Constructor constructor : constructors){
			String name = constructor.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			//StringBuilder是线程不安全的,单线程下效率更高
			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----------");
		/*$Proxy0()
		$Proxy0(InvocationHandler,int)*/
		Method[] methods = clazzProxy1.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 object----------");
		//Object obj = clazzProxy1.newInstance();会调用不带参数的构造参数,但它没有,所以不能用这种方式
		Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);//需要接收一个InvocationHandler参数
		//一个空的实现
		class MyInvocationHander1 implements InvocationHandler{

			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
	
				return null;
			}
		
		}
		
		Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());
		//toString返回值为null
		System.out.println(proxy1);
		proxy1.clear();
		//不可以调用带有返回值的方法;因为invoke返回的是null而proxy1.size()要返回一个整数,将null转化成整数不成,所以报错
		//proxy1.size();
		
		Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
//匿名内部类,android应用开发中经常用到,方便快捷
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				return null;
			}
			
		});
		//演示如何通过自己写的获得动态代理的方法
		//方法里的内部类要访问局部变量,局部变量前必须加final
		final ArrayList target = new ArrayList();			
		Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
		proxy3.add("zxx");
		proxy3.add("lhm");
		proxy3.add("bxd");
		System.out.println(proxy3.size());
		//此处proxy从object继承的方法只有toString() hashCode() equals()才派发给handler 其它方法有自己的实现不交给handler
		System.out.println(proxy3.getClass().getName());
	}
//自己写的获得动态代理的方法
	private static Object getProxy(final Object target,final Advice advice) {
		//通过Proxy的加一个静态方法一步到位实现代理类
		Object proxy3 = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				/*new Class[]{Collection.class},*/
				target.getClass().getInterfaces(),
				new InvocationHandler(){
				//调用代理的三个要素:调用哪个代理,哪个方法及方法接收的参数
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {

						/*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;
	}

}

Advice接口:

public interface Advice {
	void beforeMethod(Method method);
	void afterMethod(Method method);
}

 

MyAdvice类:

public class MyAdvice implements Advice {
	long beginTime = 0;
	public void afterMethod(Method method) {
		System.out.println("从黑马毕业上班啦!");		
		long endTime = System.currentTimeMillis();
		System.out.println(method.getName() + " running time of " + (endTime - beginTime));

	}

	public void beforeMethod(Method method) {
		System.out.println("到黑马来学习啦!");
		beginTime = System.currentTimeMillis();
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值