黑马程序员--基础加强--第八篇--代理

ASP.Net+Android+IOS开发.Net培训期待与您交流!

代理的介绍

为已存在的具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理,日志,计算方法的运行时间,事务管理等!

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

用一张图表示就是


1静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

静态代理类优缺点
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

2动态代理

编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法旁加上系统功能代码,要为系统中各个接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情,JVM在运行期间可以动态生成类的字节码,这种动态生成的类往往被用作代理类,代理类必须实现一个或多个接口,所以JVM生成的动态代理类只能为具有相同接口的目标类代理,这里就用到了CGLIB生成没有接口的类的代理类。

1)java.lang.reflect.Proxy
这是 Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。

 // 方法 1: 该方法用于获取指定代理对象所关联的调用处理器  
static InvocationHandler getInvocationHandler(Object proxy)   
  
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象  
static Class getProxyClass(ClassLoader loader, Class[] interfaces)   
  
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类  
static boolean isProxyClass(Class cl)   
  
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例  
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 

2)java.lang.reflect.InvocationHandler
这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理类对象时都要指定一个对应的调用处理器对象。

 //在代理实例上处理方法调用并返回结果。
 invoke(Object proxy, Method method, Object[] args)          

动态代理类程序

给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类

Class clazzCol = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);

b以调用处理器类型为参数,利用反射机制得到动态代理类的构造函数

Constructor[] cons = clazzCol.getConstructors();
		for(Constructor con : cons){
			String name = con.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			sBuilder.append("(");
			Class[] clazzParams = con.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);
		}

结果为


c以调用处理器类型为参数,利用反射机制得到动态代理类的方法

Method[] mets = clazzCol.getMethods();
		int i = 0;
		for(Method met : mets){
			String name = met.getName();
			StringBuilder sBuilder = new StringBuilder(name);
			sBuilder.append("(");
			Class[] clazzParams = met.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+""+(i++));
		}

结果为



d以调用处理器对象为参数,利用动态代理类的构造函数创建动态代理类对象,共有三种创建代理类对象的方法

Constructor constructor = clazzCol.getConstructor(InvocationHandler.class);
		//第一种方法产生代理类的对象
		class MyInvocationHandler1 implements InvocationHandler{
			ArrayList target = new ArrayList();
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				long startTime = System.currentTimeMillis();
				Object retVal = method.invoke(target, args);
				long eldTime = System.currentTimeMillis();
				System.out.println(method.getName()+"runing time is "+(eldTime-startTime));
				return retVal;
			}
			
		}
		Collection colInvoHand1 = (Collection) constructor.newInstance(new MyInvocationHandler1());
		System.out.println(colInvoHand1);
		
		//第二种产生代理类的对象
		Collection colInvoHand2 = (Collection) constructor.newInstance(new InvocationHandler(){
			ArrayList target = new ArrayList();
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// TODO Auto-generated method stub
				long startTime = System.currentTimeMillis();
				Object retVal = method.invoke(target, args);
				long eldTime = System.currentTimeMillis();
				System.out.println(method.getName()+"runing time is "+(eldTime-startTime));
				return retVal;
			}
			
		});
		System.out.println(colInvoHand2);
		
		//第三种产生带来类的对象
		Collection colInvoHand3 = (Collection) Proxy.newProxyInstance(
				Collection.class.getClassLoader(),
				new Class[] {InvocationHandler.class},
				new InvocationHandler(){
					ArrayList target = new ArrayList();
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						long startTime = System.currentTimeMillis();
						Object retVal = method.invoke(target, args);
						long eldTime = System.currentTimeMillis();
						System.out.println(method.getName()+"runing time is"+(eldTime-startTime));
						return retVal;
					}
					
				}
		);
		colInvoHand3.add("1");
		colInvoHand3.add("2");
		colInvoHand3.add("3");

而这样的代理只能代理一次,永久的为Collection的add方法提供代理,不能够面向对象,如要想要面向对象,需要进一步优化代码。

以第三种为例

创建对象 传入目标和封装新方法的对象

Collection colInvoHand3 = (Collection) getProxy(target,new MyAdvice());
写代理方法 

private static Object getProxy(final Object target,final Advice advice) {
		Object colInvoHand3 = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(),
				new InvocationHandler(){
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						advice.beforeMethod(method);
						Object retVal = method.invoke(target, args);
						advice.afterMethod(method);
						return retVal;
					}
					
				}
		);
		return colInvoHand3;
	}
将新方法写成一个实现接口的类

import java.lang.reflect.Method;

public class MyAdvice implements Advice {
	long startTime ;
	long eldTime ;

	@Override
	public void beforeMethod(Method method) {
		// TODO Auto-generated method stub
		startTime = System.currentTimeMillis();
		System.out.println("从黑马开始学习了");
	}

	@Override
	public void afterMethod(Method method) {
		// TODO Auto-generated method stub
		eldTime = System.currentTimeMillis();
		System.out.println(method.getName()+"runing time is"+(eldTime-startTime));
		System.out.println("从黑马毕业上班了");
	}

}


import java.lang.reflect.Method;

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

ASP.Net+Android+IOS开发.Net培训期待与您交流!




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值