- 浏览: 294977 次
- 性别:
- 来自: 山东-东营-利津县
文章分类
- 全部博客 (155)
- J2SE (25)
- JavaScript (8)
- Linux (4)
- Struts (12)
- Mysql (8)
- Oracle (9)
- IT与生活 (12)
- EJB (7)
- JMS (1)
- Spring (5)
- Hibernate (6)
- Jsp&Servlet (4)
- 开发小技巧 (5)
- log4j (4)
- 面试题 (20)
- DWR (2)
- JBPM (1)
- iBATIS (4)
- 数据结构 (1)
- svn (1)
- 反编译 (1)
- DB2 (4)
- Tomcat (2)
- WebService (2)
- JBoss (5)
- jquery (1)
- HttpClient (1)
- jdom (1)
- mina (1)
最新评论
-
moment52:
为什么会选择用拦截器,不用action呢
使用ThreadLocal结合struts2的拦截器实现分页 -
wzk527:
很好
编程:编写一个截取字符串的函数,(网上流传的答案有的是错的)输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如“我ABC”4 -
shijian2292:
lz辛苦了,写的真详细,我正郁闷这些问题呢,学习了。
struts2复习笔记(version2.1.6)(01~06) -
fgh2011:
如果想要在虚拟机之外的 局域网机器中访问应用 ip需要设置成自 ...
使用secureCRT连接用VMWare虚拟机装的Linux系统 -
wangljr:
...
什么是声明式事务?什么是编程式事务?
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、创建动态类及查看其方法列表信息:
示例代码:
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();
//根据你传递的参数类型,返回相应的构造方法
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中创建代理对象的二个步骤合成一个 (用到内部类)
类提供的另一个静态方法:newProxyInstance
例子中:传递的对象是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,以便让他更有通用性
56、实现类似Spring可配置的Aop框架:
模拟目标:根据我传递的方法的名称来确认返回的是真实的一个对象,还是一个代理对象,
如果我传递的这个类是个ProxyFactory类型的一个类(instanceof)则返回该类的一个代理对象
否则直接返回所指定类的一个真实的对象。
这次我们新建一个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(); } }
发表评论
-
关于java读取properties文件的路径问题
2013-02-02 23:57 13140之前对于JAVA读取propertie ... -
StringBuffer与StringBuilder的区别
2012-07-23 16:08 0相信大家看到过很多比较String和StringBuffer区 ... -
java中Date与String的相互转化 (转)
2012-07-23 15:35 1282import java.text.DateFormat; ... -
使用eclipse fat插件制作可运行jar
2012-06-05 13:59 0转载自http://blog.csdn.net/jikeyzh ... -
使用eclipse fat插件制作可运行jar
2012-06-05 13:59 1085转载自http://blog.csdn.net/jikeyzh ... -
关于JAVA类中各个成分的初始化顺序(转载)
2012-04-28 23:30 829... -
关于J2SE一些细节问题的整理(如有错误,欢迎留言指正)
2011-10-23 16:03 10501、关于继承中private的 ... -
Java heap space[转]
2011-09-13 14:17 798PermGen space的全称是Permanent Gene ... -
super关键字与内存分布
2010-05-13 21:19 1202当我们new出一个子类对象的时候,这个子类对象内部肯定会包含一 ... -
继承中的构造方法
2010-05-13 21:12 10361、子类的构造过程中必须调用其基类的构造方法。 2、子类在自 ... -
关于方法的重载
2010-05-12 16:41 848public class Person { publ ... -
成员变量和局部变量的一点不同
2010-05-12 12:25 901在java中,如果你在class中定义了一个成员变量然 ... -
环境变量中的系统环境变量和用户环境变量有什么区别?
2010-05-10 21:31 2850系统环境变量的意思是无论你是用那个用户帐号登陆后都能够共 ... -
final关键字到底修饰了什么
2010-05-05 22:55 1052final使得被修饰的变量"不变",但是由 ... -
synchronized 的语法:(转载)
2010-04-15 21:53 1203synchronized 的语法: synchronize ... -
System.getProperty(String name)的常用值总结(转载)
2010-03-29 15:41 1049常用的System.getProperty(),这里贴一下,省 ... -
各种进制之间的转换(转载)
2010-03-24 11:59 1882各种进制转换 计算机中常用的数的进制主要有:二进制、八进制、十 ... -
Class.forName(String name)的作用(转载)
2010-03-22 23:08 1308Class.forName(xxx.xx.xx) 返回的是一个 ... -
ClassLoader的加载机制相关
2010-03-22 23:05 994面试题:能不能自己写个类叫java.lang.String让泪 ... -
张孝祥J2SE加强自学笔记(41-47)
2010-03-22 22:46 133441、自定义泛型方法的练习与类型推断总结: (1)编写一个方 ...
相关推荐
3. 多态(Polymorphism):多态是指同一个接口可以有不同的实现方式,即子类可以重写父类的方法,使得相同的操作可以作用于不同的对象,增强了代码的灵活性。Java中的方法重写(Override)和接口实现是多态的重要...
详细解释了html语言、css、javascript语法、dom对象编程、正则表达式,介绍了网页脚本编程的其他技术和知识。(由于上传限制,故将本教程分为6个部分上传,请全部下载后解压)
【张孝祥_高级j2se代码】这个资源包含了张孝祥老师精心编写的J2SE(Java 2 Standard Edition)高级代码示例,旨在帮助开发者深入理解和掌握Java核心技术。J2SE是Java平台的核心部分,它提供了丰富的类库和API,支持...
张孝祥课程学习笔记,包括JAVA基础,JAVA高级,JavaScript全部的笔记,适合初学者。
ed2k://|file|[张孝祥JAVA视频教程!(1-5课)].lesson01.[XiDong.Net].rmvb|555980477|1954514FA6C5757740064027D85826C1|h=EDKWEPSDDPS42DLGMONDGZPTQ7VF5BWX|/ ………………省略部分………… 第二部分 ed2k://|...
详细解释了html语言、css、javascript语法、dom对象编程、正则表达式,介绍了网页脚本不编程的其他技术和知识。(由于上传限制,故将本教程分为6个部分上传,请全部下载后解压)
详细解释了html语言、css、javascript语法、dom对象编程、正则表达式,介绍了网页脚本编程的其他技术和知识。(由于上传限制,故将本教程分为6个部分上传,请全部下载后解压)
张孝祥Java邮件开发详解-高清扫描版-part1 绝对是精品 张孝祥的好书 。很大,分为2部分。
j2se基础加强_张孝祥版ppt,对于java的基础提升是很有帮助的。
传智播客-------张孝祥老师--------------- javaMail开发PPT
【Java基础加强】张孝祥的Java教学视频涵盖了Java编程语言的基础到进阶知识,旨在帮助学习者巩固和提升Java编程技能。以下是根据教程笔记整理的一些关键知识点: 1. **Java简介**:Java是一种跨平台的面向对象的...
张孝祥Java邮件开发详解-高清扫描版-part2
jAVA基础+高新+7K知识点总结.chm 需要的可以下载
Java基础加强--张孝祥版 传智播客
java 教程 下载 -张孝祥java视频教程56集
### 张孝祥Java多线程与并发库高级应用笔记概览 #### 一、Java多线程技术的重要性与挑战 Java线程技术是软件工程领域不可或缺的一部分,尤其在底层编程、Android应用开发以及游戏开发中,其重要性不言而喻。然而,...
### 张孝祥老师讲课笔记:深入理解Windows程序运行机制 #### Windows程序设计与传统DOS方式的区别 张孝祥老师的讲课笔记强调了Windows程序设计与传统的DOS方式有着本质的不同,尤其体现在程序运行机制上。Windows...
张孝祥交通灯管理系统笔记 面试题视频教程笔记