`

张孝祥J2SE加强自学笔记(48-56)

    博客分类:
  • J2SE
阅读更多
48、类加载器的一个高级问题的实验分析:
这次我们新建一个web项目然后新建一个servlet,在servet的doGet方法中我们循环的遍历出所有的类加载
器分别为:
WebappClassLoader
StandardClassLoader
AppClassLoader
ExtClassLoader

这样我们可以正常的访问该Servlet, 然后我们把这个servlet打成.Jar包放到jre/lib/ext/下面去让
ExtClassLoader去加载他,然后当我们再次的访问这个程序的时候就报错了:
原因:当ExtClassLoader加载改程序的时候,会首先让他的父亲去加载,由于父亲没有找到,所以就又交给他来加载
当他加载这个servlet的时候,他发现这个类extends HttpServlet所以就又去加载他,因为找不到所以就报错了,因为这个
jar包是由tomcat提供的,把tomcat lib中的servlet-api.jar页拷贝到ext目录下面就可以解决这个问题了。

web程序下类所使用的不同的类加载器





49、分析代理类的作用与原理及AOP概念
(1)AOP的概念:



(2)动态代理:



50、创建动态类及查看其方法列表信息:
示例代码:
public static void main(String[] args) {
		Class clazz = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		String clazzName = clazz.getName();	
		
		//打印所以的构造方法以及参数
		Constructor[] constructs = clazz.getConstructors();
		for(Constructor constructor : constructs) {
			String constructName = constructor.getName();
			StringBuilder sBuilder = new StringBuilder(constructName);
			sBuilder.append('(');
			Class[] clazzTypes = constructor.getParameterTypes();
			for(Class clazzType : clazzTypes) {
				sBuilder.append(clazzType.getName()).append(',');
			}
			if(clazzTypes != null && clazzTypes.length >0) {
				sBuilder.deleteCharAt(sBuilder.length() - 1);
			}
			sBuilder.append(')');
			System.out.println(sBuilder);
		}
		
		//打印这个接口所拥有的所有的方法以及他们的参数
		Method[] clazzMethods = clazz.getMethods();
		for(Method clazzMethod : clazzMethods) {
			String methodName = clazzMethod.getName();
			StringBuilder sBilder = new StringBuilder(methodName);
			Class[] methodTypes = clazzMethod.getParameterTypes();
			sBilder.append('(');
			for(Class methodType : methodTypes) {
				sBilder.append(methodType.getName()).append(',');
			}
			if(methodTypes != null && methodTypes.length >0) {
				sBilder.deleteCharAt(sBilder.length() - 1);
			}
			sBilder.append(')');
			System.out.println(sBilder);
		}
	}
	
	结果:
	$Proxy0(java.lang.reflect.InvocationHandler)
	add(java.lang.Object)
	hashCode()
	clear()
	equals(java.lang.Object)
	toString()
	contains(java.lang.Object)
	isEmpty()
	addAll(java.util.Collection)
	iterator()
	size()
	toArray([Ljava.lang.Object;)
	toArray()
	remove(java.lang.Object)
	containsAll(java.util.Collection)
	removeAll(java.util.Collection)
	retainAll(java.util.Collection)
	isProxyClass(java.lang.Class)
	getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
	getInvocationHandler(java.lang.Object)
	newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
	wait()
	wait(long,int)
	wait(long)
	getClass()
	notify()
	notifyAll()


1、细节注意:在上述例子中,Proxy的静态方法getProxyClass的第二个参数需要传递一个interfaces的Class的数组。而在上述程序中应该写成Collection.class.getInterfaces(),为什么写成Collection.class也行呢? 那是因为Collection本身就是一个接口,如果Collection不是一个接口而是一个实现了数组的类,则必须写成Collection.class.getInterfaces(),否则程序将报错。
2、生成的代理对象是没有参数为空的构造方法的,只有一个参数为InvocationHandler的构造方法,所以不能直接调用newInstance()方法直接创建一个实例,因为该方法会调用相关类的无参的构造方法。所以只能得到参数为InvocationHandler的构造方法,然后传递一个实现了InvocationHandler接口的类来创建一个对象,从而引出我们下面要讲解的动态代理内容。


51、创建动态类的实例对象及调用其方法
在上面类的基础上添加如下代码:
//无法用下面的方法创建对象,因为newInstance()默认调用的是无参的构造方法,而我们上面获得的是Proxy类的一份字节码,而这个类
//没有无参的构造方法,必须取得他的构造方法来构造对象
//Object object = clazz.newInstance();

//根据你传递的参数类型,返回相应的构造方法
Constructor construct = clazz.getConstructor(InvocationHandler.class);
	class myInvocationHandler implements InvocationHandler {
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			return null;
		}
	}
//要返回代理对象,必须要传递一个实现了InvocationHandler接口的类的一个对象
Collection proxy1 = (Collection)construct.newInstance(new myInvocationHandler());
//可以
proxy1.clear();
//报错
proxy1.size();

打印proxy1的结果是null,那并不代表proxy1就是null 是他的toString()方法是null,如果你调用它的clear()方法,不会报
NullPointException,但是返回的这个代理对象为什么只能调用没有返回值的方法,而如果调用有返回值的方法就会报空指针异常呢
因为每当你调用代理类的一个方法的时候,他就会去调用InvocationHandler中的Invoke方法,size的返回值是int,而return的是null

52、完成InvocationHandler对象的内部功能
我们可以把51中创建代理对象的二个步骤合成一个 (用到内部类)
Collection proxy2 = (Collection)construct.newInstance(new InvocationHandler() {

			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				return null;
			}
		});
		
在51 中我们创建一个代理对象是 得到字节码------>得到构造方法----->创建对象。我们能不能一步到位?这要利用Proxy
类提供的另一个静态方法:newProxyInstance
Collection proxy3 = (Collection)Proxy.newProxyInstance(
						//类加载器
						Collection.class.getClassLoader(), 
						//传入接口可能有多个,所以是数组
						new Class[]{Collection.class}, 
						
						new InvocationHandler() {
							//target就是我们要创建代理对象的那个真实的对象。
							ArrayList target = new ArrayList();
							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() + "方法运行时间为" + (beginTime -endTime));
								return retVal;
							}   
						}
		);
		
		proxy3.add("abc");
		proxy3.add("cde");
		System.out.println(proxy3.size());
		
总结:当调用代理对象的方法的时候,其实都会去调用InvocationHandler类的method.invoke()方法。invoke方法中有两个参数:(1)要调用的这个方法所属的对象。(2)这个方法所用到的参数。
例子中:传递的对象是target --new的一个真实ArrayLIst的对象,所以在程序后调用proxy2.add方法时,调用的是target的add方法。(每当调用一个代理对象的xx方法的时候,程序会自动将调用过程转交给InvocationHandler的invoke方法)按照这个规律:如果第一个参数传proxy3时,将会出现程序的死循环。
在上面的代码中我把AraryList target = new ArrayList()放到了Invoke方法前面,也就是成员变量,这个时候,
你用代理对象的时候操作的是同一个对象,所以上面的size()方法打印结果是2,但是如果你把target对象放到invoke方法
的内部,也就是局部变量的时候,在操作代理对象的时候,每调用代理对象的一个方法其实操作的是完全不同的对象
所以这个时候的结果是0

53、分析InvocationHandler对象的运行原理:
InvocationHandler原理分析



我们说如果我们调用代理类的一个方法,他会交给InvocationHandler的invoke方法去执行 返回的结果也是目标对象调用方法后的返回结果,那对于代理对象:
System.out.println(proxy3.getClass().getName()); 按照我们上面的理论,调用代理对象方法的时候会返回真实对象的返回结果,那应该是java.util.ArrayList
为什么会是$proxy0呢?
答案:调用代理对象的从Object继承的hashCode()  equals()  toString()这几个方法的时候才会把调用请求转发给InvocationHandler对象,而对于其他的方法
有自己的实现,所以getClass().getName()返回的是$proxy0

54、总结分析动态代理类的设计原理与结构
动态代理的工作原理图




55、编写可生成代理和插入通告的通用方法
模拟spring,将动态代理中的“切面”问题封装到一个类中,而不要硬编码到动态代理类中,动态代理类中的target
要改成Object,以便让他更有通用性
(1)切面问题接口
	public interface Advice {
		public void beforeMethod(Method method);
		public void afterMethod(Method method);
	}
	(2)切面问题实现
	public class MyAdvice implements Advice {
		long beginTime;
		public void afterMethod(Method method) {
			System.out.println("方法执行之后:");
			long endTime = System.currentTimeMillis();
			System.out.println(method.getName() + "方法运行时间为" + (beginTime - endTime));
			
		}

		public void beforeMethod(Method method) {
			System.out.println("方法执行之前:");
			beginTime = System.currentTimeMillis();
		}
	}
	(3)动态代理方法的封装
	private static Object getProxy(final Object target, final Advice advice) {
		Object proxy = Proxy.newProxyInstance(
						target.getClass().getClassLoader(), 
						target.getClass().getInterfaces(),
						new InvocationHandler() {
							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 proxy;
	}
	(4)测试运行
		ArrayList target = new ArrayList();
		Collection proxy = (Collection)getProxy(target, new MyAdvice());
		proxy.add("abc");

56、实现类似Spring可配置的Aop框架:
模拟目标:根据我传递的方法的名称来确认返回的是真实的一个对象,还是一个代理对象,
如果我传递的这个类是个ProxyFactory类型的一个类(instanceof)则返回该类的一个代理对象
否则直接返回所指定类的一个真实的对象。
(1)BeanFactory
	public class BeanFactory {
	
		static Properties props = new Properties();
		
		public BeanFactory(InputStream ips) {
			try {
				props.load(ips);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public static Object getBean(String name) {
			Object bean = null;
			try {
				//得到传递对象的字节码
				Class clazz = Class.forName(props.getProperty(name));
				//创建一个实例对象
				bean = clazz.newInstance();
				//如果创建的这个对象是一个ProxyFactoryBean类型的,就返回代理对象,否则返回真实的对象
			} catch (Exception e) {
				e.printStackTrace();
			}
			if(bean instanceof ProxyFactoryBean) {
				ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
				Object proxy = null;
			
				try {
					//得到目标类的对象
					Object target = Class.forName(props.getProperty(name + ".target")).newInstance();
					//得到解决“切面问题”类的对象
					Advice advice = (Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();
					proxyFactoryBean.setAdvice(advice);
					proxyFactoryBean.setTarget(target);
					proxy = proxyFactoryBean.getProxy();
				} catch (Exception e){
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				//将上述两个对象设置到代理对象中
				//返回代理对象
				return proxy;
			}
			//返回真实的对象
			return bean;
		}
	}
	
	(2)ProxyFactoryBean
	public class ProxyFactoryBean {
	
		private Object target;
		
		private Advice advice;
		
		public Object getTarget() {
			return target;
		}

		public void setTarget(Object target) {
			this.target = target;
		}

		public Advice getAdvice() {
			return advice;
		}

		public void setAdvice(Advice advice) {
			this.advice = advice;
		}

		public Object getProxy() {
			Object proxy = Proxy.newProxyInstance(
					target.getClass().getClassLoader(), 
					target.getClass().getInterfaces(),
					new InvocationHandler() {
						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 proxy;
		}
	}
	
	(3)所用到的配置文件:config.properties 注意:要与AopTest测试类位于同一个包下面(xxx.target所指定的类要与返回真实类对象所指定的类一样,否则就不一致了)
	#xxx=java.util.ArrayList
	xxx=cn.itcast.aop.framework.ProxyFactoryBean
	xxx.advice=cn.itcast.day2.MyAdvice
	xxx.target=java.util.ArrayList
	
	(4)AopTest测试类
	public class AopTest {

		public static void main(String[] args) {
			InputStream ips = AopTest.class.getResourceAsStream("config.properties");
			Object bean = new BeanFactory(ips).getBean("xxx");
			System.out.println(bean.getClass().getName());
			((Collection)bean).clear();
		}
	}
  • 大小: 57.9 KB
  • 大小: 77.9 KB
  • 大小: 32 KB
  • 大小: 106.7 KB
  • 大小: 43.6 KB
分享到:
评论

相关推荐

    [AB PLC例程源码][MMS_044666]Translation N-A.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    kolesar_3cd_01_0716.pdf

    kolesar_3cd_01_0716

    latchman_01_0108.pdf

    latchman_01_0108

    matlab程序代码项目案例:matlab程序代码项目案例MPC在美国高速公路场景中移动的车辆上的实现.zip

    matlab程序代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    pimpinella_3cd_01_0716.pdf

    pimpinella_3cd_01_0716

    petrilla_01_0308.pdf

    petrilla_01_0308

    [AB PLC例程源码][MMS_041452]Speed Controls in Plastic Extrusion.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    强化学习驱动下DeepSeek技术创新及其对AI发展的影响

    内容概要:本文档由张卓老师讲解,重点探讨DeepSeek的技术革新及强化学习对未来AI发展的重要性。文章回顾了AI的历史与发展阶段,详细解析Transformer架构在AI上半场所起到的作用,深入介绍了MoE混合专家以及MLA低秩注意机制等技术特点如何帮助DeepSeek在AI中场建立优势,并探讨了当前强化学习的挑战和边界。文档不仅提及AlphaGo和小游戏等成功案例来说明强化学习的强大力量,还提出了关于未来人工通用智能(AGI)的展望,特别是如何利用强化学习提升现有LLMs的能力和性能。 适用人群:本资料适宜对深度学习感兴趣的研究人员、开发者以及想要深入了解人工智能最新进展的专业人士。 使用场景及目标:通过了解最新的AI技术和前沿概念,在实际工作中能够运用更先进的工具和技术解决问题。同时为那些寻求职业转型或者学术深造的人提供了宝贵的参考。 其他说明:文中提到了许多具体的例子和技术细节,如DeepSeek的技术特色、RL的理论背景等等,有助于加深读者对于现代AI系统的理解和认识。

    有师傅小程序开源版v2.4.14+前端.zip

    有师傅小程序开源版v2.4.14 新增报价短信奉告 优化部分细节

    [AB PLC例程源码][MMS_047333]Motor Sequence Starter with timers to start.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    商城二级三级分销系统(小程序+后台含源码).zip

    商城二级三级分销系统(小程序+后台含源码).zip

    li_3ck_01b_0918.pdf

    li_3ck_01b_0918

    nicholl_3cd_01_0516.pdf

    nicholl_3cd_01_0516

    1995-2022年 网络媒体关注度、报刊媒体关注度与媒体监督相关数据.zip

    媒体关注度是一个衡量公众对某个事件、话题或个体关注程度的重要指标。它主要反映了新闻媒体、社交媒体、博客等对于某一事件、话题或个体的报道和讨论程度。 媒体监督的J-F系数(Janis-Fadner系数)是一种用于测量媒体关注度的指标,特别是用于评估媒体对企业、事件或话题的监督力度。J-F系数基于媒体报道的正面和负面内容来计算,从而为公众、研究者或企业提供一个量化工具,以了解媒体对其关注的方向和强度。 本数据含原始数据、参考文献、代码do文件、最终结果。参考文献中JF系数计算公式。 指标 代码、年份、标题出现该公司的新闻总数、内容出现该公司的新闻总数、正面新闻数全部、中性新闻数全部、负面新闻数全部、正面新闻数原创、中性新闻数原创、负面新闻数原创,媒体监督JF系数。

    [AB PLC例程源码][MMS_040315]Double INC and Double DEC of INT datatype.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_047773]Convert Feet to Millimeters.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    [AB PLC例程源码][MMS_042349]How to read-write data to-from a PLC using OPC in Visual Basic 6.zip

    AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    matlab程序代码项目案例:matlab程序代码项目案例论文代码 多篇RMPC 鲁棒模型预测控制Paper-code-implementation.zip

    matlab程序代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!

    lusted_3cd_02_0716.pdf

    lusted_3cd_02_0716

Global site tag (gtag.js) - Google Analytics