`

Java基础十:JDK 动态代理类分析(java.lang.reflect.Proxy使用)

阅读更多
/**
 * JDK 动态代理类分析(java.lang.reflect.Proxy使用)
 * 
 * @author 张明学
 * 
 */
public class ProxyStudy {
	
	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {
		// 动态代理类:通用指定类加载器,和接口产生一类
		// getProxyClass()返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
		Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		System.out.println("动态产生的类名为:" + clazzProxy.getName());
		System.out.println("----------获取动态产生的类的构造方法---------");
		Constructor[] constructors = clazzProxy.getConstructors();
		int i = 1;
		for (Constructor constructor : constructors) {
			System.out.println("第" + (i++) + "个构造方法名:" + constructor.getName());
			Class[] parameterClazz = constructor.getParameterTypes();
			System.out.println("第" + (i++) + "个构造方法参数:" + Arrays.asList(parameterClazz));
		}
		System.out.println("----------获取动态产生的类的普通方法---------");
		Method[] methods = clazzProxy.getDeclaredMethods();
		for (int j = 0; j < methods.length; j++) {
			Method method = methods[j];
			System.out.println("第" + (j + 1) + "个普通方法名:" + method.getName());
			Class[] parameterClazz = method.getParameterTypes();
			System.out.println("第" + (j + 1) + "个普通方法参数:" + Arrays.asList(parameterClazz));
		}
		System.out.println("---------获取动态代理对象的构造方法---------");
		// 动态代理产生的对象的构造方法需要一个实现java.lang.reflect.InvocationHandler接口的对象,故不能通过
		// clazzProxy.newInstance();产生一个对象,可以根据构造方法产生一个对象
		// InvocationHandler 是代理实例的调用处理程序 实现的接口。
		Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);

		// 代理产生的对象
		Collection proxyBuildCollection = (Collection) constructor
				.newInstance(new InvocationHandler() {
					// 为什么这里选择ArrayList作为目标对象?
					// 因为这里的constructor是clazzProxy这个动态类的构造方法,clazzProxy是通过Proxy.getProxyClass()方法产生的,
					// 该方法有两个参数,一个是指定类加载器,一个是指定代理要实现的接口,这个接口我上面指定了Collection
					// 而ArrayList实现了Collection接口,固可以为该动态类的目标对象
					ArrayList target = new ArrayList();// 动态类的目标对象

					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						System.out.println("执行目标" + method.getName() + "方法之前:"
								+ System.currentTimeMillis());
						Object result = method.invoke(target, args);// 其实代理对象的方法调用还是目标对象的方法
						System.out.println("执行目标" + method.getName() + "方法之后:"
								+ System.currentTimeMillis());
						return result;
					}

				});
		proxyBuildCollection.clear();
		proxyBuildCollection.add("abc");
		proxyBuildCollection.add("dbc");
		System.out.println(proxyBuildCollection.size());
		System.out.println(proxyBuildCollection.getClass().getName());
		
		/**
		 * 动态代理:总结如下:
		 * 1,通过Proxy.getProxyClass(classLoader,interface)方法产生一个动态类的class字节码(clazz)
		 *    该getProxyClass()方法有两个参数:一个是指定该动态类的类加载器,一个是该动态类的要实现的接口(从这里可以看现JDK的动态代理必须要实现一个接口)
		 *    
		 * 2,通过第一步的获取的clazz对象可以获取它的构造方法constructor,那么就可以通用constructor的newInstance()方法构造出一个动态实体对象
		 *    但constructor的newInstance()方法需要指定一个实现了InvocationHandler接口的类handler,在该类中需要一个目标对象A和实现invoke方法
		 *    目标对象A要求能对第一步中的接口的实现,因为在invoke方法中将会去调用A中的方法并返回结果。
		 *    过程如下:调用动态代理对象ProxyObject的x方法 ————> 进入构造方法传进的handler的invoke方法 ————> invoke方法调用handler中的target对象
		 *    	      的x方法(所以要求target必须要实现构造动态代理类时指定的接口)并返回它的返回值。(其实如果我们代理P类,那么target就可以选中P类,只是要求P必需实现一个接口)
		 *    
		 *    那么上述中x方法有哪些呢?除了从Object继承过来的方法中除toString,hashCode,equals外的方法不交给handler外,其它的方法全部交给handler处理
		 *    如上面proxyBuildCollection.getClass().getName()就没有调用handler的getClass方法,而是调用自己的
		 *    
		 * 3,在handler的invoke方法中return method.invoke(target,args)就是将方法交给target去完成。那么在这个方法执行之前,之后,异常时我们都可以做一些操作,
		 *    并且可以在执行之前检查方法的参数args,执行之后检查方法的结果
		 */
		System.out.println("-------------------下面的写法更简便--------------------");
		
		// proxyBuildColl是对ArrayList进行代理
		Collection proxyBuildCollection2 = (Collection) Proxy.newProxyInstance(
				Collection.class.getClassLoader(),// 指定类加载器
				new Class[] { Collection.class },// 指定目标对象实现的接口
				// 指定handler
				new InvocationHandler() {
					ArrayList target = new ArrayList();

					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						System.out.println(method.getName() + "执行之前...");
						if (null != args) {
							System.out.println("方法的参数:" + Arrays.asList(args));
						} else {
							System.out.println("方法的参数:" + null);
						}
						Object result = method.invoke(target, args);
						System.out.println(method.getName() + "执行之后...");
						return result;
					}
				});
		proxyBuildCollection2.add("abc");
		proxyBuildCollection2.size();
		proxyBuildCollection2.clear();
		proxyBuildCollection2.getClass().getName();
		
		System.out.println("-------------------对JDK动态代理的重构--------------------");
		Set proxySet = (Set) buildProxy(new HashSet(), new MyAdvice());
		proxySet.add("abc");
		proxySet.size();
	}
	/**
	 * 构造一个目标对象的代理对象
	 * 
	 * @param target
	 *            目标对象(需要实现某个接口)
	 * @return
	 */
	public static Object buildProxy(final Object target,final AdviceInter advice) {
		Object proxyObject = Proxy.newProxyInstance(
				target.getClass().getClassLoader(),// 指定类加载器
				target.getClass().getInterfaces(), // 指定目标对象实现的接口
				// handler
				new InvocationHandler() {
					
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						advice.beforeMethod(target, method, args);
						Object result = method.invoke(target, args);
						advice.afterMethod(target, method, args);
						return result;
					}
				});
		return proxyObject;
	}
	
}

 

/**
 * 代理中执行目标方法之前之后的操作的一个实例
 * 
 * @author 张明学
 * 
 */
public class MyAdvice implements AdviceInter {

	public void afterMethod(Object target, Method method, Object[] args) {
		System.out.println("目标对象为:" + target.getClass().getName());
		System.out.println(method.getName() + "执行完毕!");
	}

	public void beforeMethod(Object target, Method method, Object[] args) {
		System.out.println(method.getName() + "开始执行");
		if (null != args) {
			System.out.println("参数为:" + Arrays.asList(args));
		} else {
			System.out.println("参数为:" + null);
		}
	}
}

 

/**
 * 代理中执行目标方法之前之后的操作
 * 
 * @author 张明学
 * 
 */
public interface AdviceInter {
	/**
	 * 目标方法执行之前
	 * 
	 */
	public void beforeMethod(Object target, Method method, Object[] args);

	/**
	 * 目标方法执行之后
	 * 
	 * @param target
	 *            目标对象
	 * @param method
	 *            方法
	 * @param args
	 *            参数
	 */
	public void afterMethod(Object target, Method method, Object[] args);
}

 

分享到:
评论
2 楼 dd_zhuang 2011-12-21  
写的很好
1 楼 zenghaijun 2011-09-27  
顶 说的很详细 不错呀

相关推荐

    UPS、蓄电池、空开、电缆配置计算方法.pptx

    5G通信行业、网络优化、通信工程建设资料

    node-v7.4.0.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    Unity mesh减面工具 Mesh Simplify 1.12

    Unity mesh减面工具 Mesh Simplify 1.12

    基于Springboot+Vue酒店客房入住管理系统-毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    JAVA扫雷游戏程序+源码

    扫雷游戏是一款经典的计算机游戏,它的目标是在一个方格矩阵中找出所有隐藏的地雷。玩家需要通过点击方格来揭示其内容,如果方格中有地雷,则游戏结束;如果没有地雷,则会显示周围8个方格中地雷的数量。玩家需要根据这些信息来判断哪些方格是安全的,并继续点击其他方格。 在JAVA扫雷游戏程序中,我们使用了一个二维数组来表示游戏的方格矩阵。每个方格可以包含以下三种状态之一:未被揭示、有地雷或安全。我们还使用了一些辅助变量来跟踪游戏中的状态,例如已揭示的方格数量和剩余的地雷数量。 当玩家点击一个方格时,程序会检查该方格是否已经被揭示。如果是,则不做任何操作;否则,程序会揭示该方格的内容,并根据其是否包含地雷来更新游戏状态。如果方格中有地雷,则游戏结束;否则,程序会递归地揭示周围的方格,直到遇到已经揭示的方格为止。 为了提高游戏的可玩性,我们可以添加一些额外的功能,例如计时器、难度级别选择和自定义方格大小等。此外,我们还可以使用图形用户界面(GUI)来美化游戏界面,使其更加友好和易于操作。

    python-3.8.19-amd64-full.exe

    仅供个人娱乐使用,不要乱用造成侵权,搬运自git删hub.co除m/ad中ang1345/Pyt文honW部ind分ows

    网络安全网络安全视频教程56讲全在线地址.txt

    【网络安全】网络安全视频教程56讲全在线地址.txt

    299-企业数字化转型方案20220804.pptx

    299-企业数字化转型方案20220804.pptx

    参考资料-人工智能对劳动力市场的影响机制研究.pdf

    参考资料-人工智能对劳动力市场的影响机制研究.pdf

    3D Facial Expressions

    3D Facial Expressions through Analysis-by-Neural-Synthesis

    AI设计工具-美图设计室:一键生成海报宣传画.txt

    AI设计工具-美图设计室:一键生成海报宣传画

    node-v10.12.0-linux-armv6l.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于Springboot+Vue的商业辅助决策系统的设计与实现-毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    5MHz 函数发生器使用说明书

    5MHz 函数发生器使用说明书

    大学生就业平台微信小程序+ssm后端毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    通信驻地网施工组织方案.doc

    5G通信、网络优化与通信建设

    管道顶管工程施工技术.doc

    5G通信、网络优化与通信建设

    Unity 穿墙挖洞-CSG

    Unity 穿墙挖洞——CSG

    基于Python的医院挂号系统带vue前后端分离毕业源码案例设计.zip

    网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。系统化是必要的,设计网上系统不仅会节约人力和管理成本,还会安全保存庞大的数据量,对于信息的维护和检索也不需要花费很多时间,非常的便利。 网上系统是在MySQL中建立数据表保存信息,运用SpringBoot框架和Java语言编写。并按照软件设计开发流程进行设计实现。系统具备友好性且功能完善。 网上系统在让售信息规范化的同时,也能及时通过数据输入的有效性规则检测出错误数据,让数据的录入达到准确性的目的,进而提升数据的可靠性,让系统数据的错误率降至最低。 关键词:vue;MySQL;SpringBoot框架 【引流】 Java、Python、Node.js、Spring Boot、Django、Express、MySQL、PostgreSQL、MongoDB、React、Angular、Vue、Bootstrap、Material-UI、Redis、Docker、Kubernetes

    199-实时数据仓库建设体系.pdf

    199-实时数据仓库建设体系.pdf

Global site tag (gtag.js) - Google Analytics