码迷,mamicode.com
首页 > 其他好文 > 详细

高新技术:代理

时间:2015-04-09 23:47:54      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:

------- android培训java培训、期待与您交流! ----------


 一、概述


1、定义

什么是代理?代理就是对目标对象提供一种代理以控制对这个对象的访问,像这些术语什么的最讨厌了,虽然表述正确,但是很难记,还是用通俗的话来概括一下,

我认为代理就是通过一个类访问另外一个类。

代理类与目标类(委托类)有同样的接口,代理是为了给目标类提供额外的处理或者不同的操作,如异常处理、运行时间、日志、事物管理等。

代理类的对象本身并不真正实现服务,而是通过调用目标类/委托类对象的相关方法提供服务。

有没有想起设计模式中的代理模式,是的,今天要讲的代理其实和设计模式中的代理模式从本质上来讲是一样的。

2、用代理有什么好处?

使用代理的目的主要的目的是为了对目标类,进行精确的控制。

我们在调用某个类的某个方法时,不仅要的到方法调用后的结果,还想再调用方法前后加上自己定义的一段程序并执行,这时使用代理技术就很方便了。


3、代理构架图

技术分享


4、静态代理与动态代理

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

动态代理:在程序运行时,运用反射机制动态创建而成。 

也就是说,静态代理类运行前就有,动态代理类运行时才出现。

如果使用静态代理的话,我们就需要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情。

所以我们主要采用的是动态代理的方式。包括一些框架也是通过动态代理实现的。


 二、创建动态类及查看方法


1,动态代理类创建代码(这里以Collection类为例)

//返回代理类的Class对象,参数(类加载器,实现的接口)
		Class clazzProxy = Proxy.getProxyClass(
				Collection.class.getClassLoader(), Collection.class);

2,获取动态代理类的构造方法

	private static void CreatConstructor(Class clazzProxy) {

		Constructor[] cons = clazzProxy.getConstructors();

		for (Constructor constructor : cons) {
			String name = constructor.getName();

			StringBuilder sb = new StringBuilder(name);
			sb.append('(');
			Class[] cls = constructor.getParameterTypes();
			for (Class class1 : cls) {
				sb.append(class1.getName()).append(',');
			}
			sb.append(')');

			System.out.println(sb + "......");
		}
	}

3,获取动态代理类的一般方法

	private static void CreatMethod(Class clazzProxy) {

		Method[] methods = clazzProxy.getMethods();

		for (Method method : methods) {
			String name = method.getName();

			StringBuilder sb = new StringBuilder(name);
			sb.append('(');
			Class[] cls = method.getParameterTypes();
			for (Class class1 : cls) {
				sb.append(class1.getName()).append(',');
			}
			sb.append(')');

			System.out.println(sb + "......");
		}
	}

 三、创建动态代理类的实例对象及调用其方法


1,同过内部类方式实现

	private static void InstanceObj1(Class clazzProxy) throws Exception {
		// 根据creatConstructor()方法可知clazzProxy无构造方法
		//InvocationHandler:是代理实例的调用处理程序实现的接口。 仅包含一个方法invoke
		Constructor con = clazzProxy.getConstructor(InvocationHandler.class);
		//通过内部类形式实现该方法
		class MyInvocation implements InvocationHandler {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				//在这里写调用的Target(目标类)的具体操作
				return null;
			}
		}
		Collection proxy1 = (Collection) con.newInstance(new MyInvocation());
		System.out.println(proxy1);
	}


2,通过匿名内部类方式实现

/**
	 * 获得一个动态代理类,改写,通过匿名内部类
	 * 
	 */
	private static void InstanceObj2(Class clazzProxy) throws Exception {
		// 根据creatCOnstructor()方法可知clazzProxy无构造方法
		Constructor con = clazzProxy.getConstructor(InvocationHandler.class);
		Object proxy1 = con.newInstance(new InvocationHandler() {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {

				return null;

			}

		});
		System.out.println(proxy1);
	}

3,通过Proxy.newProxyInstance()方法

/**
	 * 获得一个动态代理类,通过Proxy.newProxyInstance()方法
	 */
	private static void InstanceObj3() {
		Collection proxy1 = (Collection) Proxy.newProxyInstance(
				Collection.class.getClassLoader(),//第一个参数,定义代理类的类加载器
				new Class[] { Collection.class},  //第二个参数,代理类要实现的接口列表
				new InvocationHandler() {		  //第三个参数,指派方法调用的调用处理程序
					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						ArrayList target = new ArrayList();
						
						return method.invoke(target, args);

					}
				});
		
	}


 四、动态代理类的实现原理


技术分享


这副图还是很形象的,在画圈的部分添加自己的代码,客户端通过调用动态代理类的某方法,通过InvocationHandler接口的invoke()方法调用Target(目标类)的同相同方法。



 五、编写通用的动态代理。


1,先定义一个接口

package cn.jinfulin.day3.Proxy;

import java.lang.reflect.Method;

public interface IAdvice {
	void beforMethod(Method method);
	void afterMethod(Method method);
}

2,实现这个接口

package cn.jinfulin.day3.Proxy;

import java.lang.reflect.Method;

public class MyAdvice implements IAdvice {
	
	long beginTime;
	@Override
	public void beforMethod(Method method) {
		beginTime = System.currentTimeMillis();
		System.out.println(method.getName() + "欢迎来学习动态代理,");
	}

	@Override
	public void afterMethod(Method method) {
		Long endTime = System.currentTimeMillis();
		System.out.println( method.getName() + "我已经学会了代理,用时" + (endTime - beginTime));
	}

}

3,编写动态代理类方法

/**
	 * 最终改写后的代理类
	 */
	private static Object finnalMethod(final Object target,final IAdvice advice) {
		
		Object proxy1 =  Proxy.newProxyInstance(//创建动态代理类的一个新实例
				target.getClass().getClassLoader(),//第一个参数,定义代理类的类加载器
				target.getClass().getInterfaces(), //第二个参数,代理类要实现的接口列表
				new InvocationHandler() {		  //第三个参数,指派方法调用的调用处理程序
					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						
						advice.beforMethod(method);//加上目标类的一个方法
						Object retval = method.invoke(target, args);
						advice.afterMethod(method);//在加上目标类的一个方法
						return retval;
//						return method.invoke(target, args);

					}
				});
		return proxy1;
		
	}

4,客户端调用

		ArrayList target = new ArrayList();			
		Collection proxy = (Collection)finnalMethod(target,new MyAdvice());
		proxy.add("金福林");//使用了一次方法,就相当于调用了一次invoke方法
		proxy.clear();\\第二次调用
		System.out.println(proxy.size());\\第三次调用
		


5,结果

技术分享



 六、最后


代理终于也写完了,以后要靠java吃饭,java基础学好了还是很有必要的,以后的开发也是在这些知识基础上,使用框架和API等做开发。毕竟万变不离其宗,掌握基础掌握原理才能更好的使用工具。



高新技术:代理

标签:

原文地址:http://blog.csdn.net/jinfulin/article/details/44967635

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!