【黑马程序员】技术加强之代理与动态加载类

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------


         首先总结下代理,本人理解的代理就是客户端和访问目标之间的中介,例如,客户端要访问一个对象,可以通过代理来访问,而不用直接访问对象,但是代理需要和目标对象实现相同的接口,这属于一种规范,只有实现相同的接口,代理才能知道目标对象都有什么方法,因为他们都要实现接口中的所有方法。

如何创建代理,java虚拟机(jvm)提供了一个创建代理的方法,通过Proxy.getProxyClass()方法获得代理类,这个方法需要传入两个参数,一个是需要实现的类加载器,第二个参数是目标的字节码文件。通过反射机制可以获得代理的构造函数和方法,发现代理只有一个有参构造函数,参数类型是需要实现InvocationHandler接口。而InvocationHandler接口需要实现一个invoke方法。所以这时候就想到用匿名内部类的方式来传入实现InvocationHandler接口的匿名内部类。

具体实现代码

以下代码是获得代理的构造函数以及方法的实现。

下面例子是获得Collection集合的代理,可以通过这个例子来了解代理的使用方法。

Class classProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
Constructor[] constructors = classProxy1.getConstructors();
		for(Constructor constructor : constructors)
		{
			String nameC = constructor.getName();
			StringBuilder sBulider = new StringBuilder(nameC);
			sBulider.append('(');
			Class[] classPars = constructor.getParameterTypes();
			for(Class classpar : classPars)
			{
				sBulider.append(classpar.getName()).append(',');
			}
			if(classPars!=null && classPars.length!=0)
			sBulider.deleteCharAt(sBulider.length()-1);
			sBulider.append(')');
			System.out.println(sBulider.toString());
		}
Method[] methods = classProxy1.getMethods();
		for(Method method : methods)
		{
			String nameC = method.getName();
			StringBuilder sBulider = new StringBuilder(nameC);
			sBulider.append('(');
			Class[] classPars = method.getParameterTypes();
			for(Class classpar : classPars)
			{
				sBulider.append(classpar.getName()).append(',');
			}
			if(classPars!=null && classPars.length!=0)
			{sBulider.deleteCharAt(sBulider.length()-1);}
			sBulider.append(')');
			System.out.println(sBulider.toString());
		}

下面代码是通过传递匿名内部类方式来获得Collection的代理。

 Collection Proxy1 = (Collection)constructor.newInstance(new InvocationHandler()
	  {

		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			ArrayList target = new ArrayList();
			//可以在方法之前加入其它功能
			Object retVal = method.invoke(proxy, args);
			//可以在方法之后加入功能
			// TODO Auto-generated method stub
			
			return retVal;
		}
		  
	  });

那么既然要实现动态代理,有没有更好的方法可以将这三个参数都传进一个方法中实现动态代理呢,这时候就用到Proxy.newProxyInstance(loader, interfaces, h)方法,这个方法需要传递三个参数,目标类加载器、要实现的接口的集合、实现InvocationHandler接口的参数。通过这个方法就可以实现一步创建代理。

以下代码是老师讲的实例,我认为非常容易理解。

将创建代理的方法抽取出来,名字为getProxy(),通过传入接口的实现类来对目标函数添加功能。

private static Object getProxy(final Object target,final Advice advice) {
		Object Proxy3 = (Object)Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				  target.getClass().getInterfaces(),
				  new InvocationHandler() {
				
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						// TODO Auto-generated method stub
					    //System.out.println(start);
						advice.beforeMethod(method);
					    Object retVal = method.invoke(target, args);
					    advice.AfterMethod(method);
						return retVal;
					}
				}
				  );
		return Proxy3;
	}

}

以下代码是实现Advice接口的实现类和Advice接口 这种方式也叫做契约:

Spring中的面向切面的编程就是用代理实现的。

package com.itheima;

import java.lang.reflect.Method;

public class MyAdvice implements Advice {
	long start=0;
	@Override
	public void AfterMethod(Method method) {
		// TODO Auto-generated method stub
		System.out.println("执行方法之前的时间");
	    start = System.currentTimeMillis();
	}

	@Override
	public void beforeMethod(Method method) {
		// TODO Auto-generated method stub
		System.out.println("执行目标方法之后的时间");
		long end = System.currentTimeMillis();
	    //System.out.println(end);
	    System.out.println(method.getName()+"end-start::"+(end-start));
	}

}

package com.itheima;

import java.lang.reflect.Method;

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




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值