锁定老帖子 主题:Spring学习笔记:1、概念理解
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-02-18
一、Spring的IoC(Inversion of Control)。 这是Spring中得有特点的一部份。IoC又被翻译成“控制反转”,也不知道是谁翻译得这么别扭,感觉很深奥的词。其实,原理很简单,用一句通俗的话来说:就是用XML来定义生成的对象。IoC其实是一种设计模式,Spring只是实现了这种设计模式。 这种设计模式是怎么来的呢?是实践中逐渐形成的。 第一阶段:用普通的无模式来写Java程序。一般初学者都要经过这个阶段。 第二阶段:频繁的开始使用接口,这时,接口一般都会伴随着使用工厂模式。 第三阶段:使用IoC模式。工厂模式还不够好:(1)因为的类的生成代码写死在程序里,如果你要换一个子类,就要修改工厂方法。(2)一个接口常常意味着一个生成工厂,会多出很多工厂类。 可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java的“反射”编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。 IoC中最基本的Java技术就是“反射”编程。反射又是一个生涩的名词,通俗的说反射就是根据给出的类名(字符串)来生成对象。这种编程方式可以让对象在生成时才决定要生成哪一种对象。我在最近的一个项目也用到了反射,当时是给出一个.properties文本文件,里面写了一些全类名(包名+类名),然后,要根据这些全类名在程序中生成它们的对象。反射的应用是很广泛的,象Hibernate、String中都是用“反射”做为最基本的技术手段。 在过去,反射编程方式相对于正常的对象生成方式要慢10几倍,这也许也是当时为什么反射技术没有普通应用开来的原因。但经SUN改良优化后,反射方式生成对象和通常对象生成方式,速度已经相差不大了(但依然有一倍以上的差距)。 所以要理解IoC,你必须先了解工厂模式和反射编程,否则对它产生的前因后果和实现原理都是无法理解透彻的。只要你理解了这一点,你自己也完全可以自己在程序中实现一个IoC框架,只不是这还要涉及到XML解析等其他知识,稍微麻烦一些。 IoC最大的好处是什么?因为把对象生成放在了XML里定义,所以当我们需要换一个实现子类将会变成很简单(一般这样的对象都是现实于某种接口的),只要修改XML就可以了,这样我们甚至可以实现对象的热插拨(有点象USB接口和SCIS硬盘了)。 IoC最大的缺点是什么?(1)生成一个对象的步骤变复杂了(其实上操作上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观。(2)对象生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高。(3)缺少IDE重构操作的支持,如果在Eclipse要对类改名,那么你还需要去XML文件里手工去改了,这似乎是所有XML方式的缺憾所在。 总的来说IoC无论原理和实现都还算是很简单的。一些人曾认为IoC没什么实际作用,这种说法是可以理解的,因为如果你在编程中很少使用接口,或很少使用工厂模式,那么你根本就没有使用IoC的强烈需要,也不会体会到IoC可贵之处。有些人也说要消除工厂模式、单例模式,但是都语焉不详、人云亦云。但如果你看到IoC模式和用上Spring,那么工厂模式和单例模式的确基本上可以不用了。但工厂模式和单例模式消失了吗?没有!Spring的IoC实现本身就是一个大工厂,其中也包含了单例对象生成方式,只要用一个设置就可以让对象生成由普通方式变单一实例方式,非常之简单。 总结: (1)IoC原理很简单,作用的针对性也很强,不要把它看得很玄乎。 (2)要理解IoC,首先要了解“工厂、接口、反射”这些概念。 二、Spring的MVC 如果你已经熟悉Struts,那么不必把MVC做为重点学习内容。基本上我认为Spring MVC是一个鸡肋,它的技术上很先进,但易用性上没有Struts好。而且Struts有这么多年的基础了,Spring很难取代Struts的地位。这就是先入为主的优秀,一个项目经理选用一种框架,不能单纯的从它的技术上考虑,还有开发效率,人员配置等都是考虑因素。但做为研究性的学习,Spring的MVC部份还是蛮有价值的。 三、数据库层的模板 Spring主要是提供了一些数据库模板(模板也是一种Java设计模式),让数据部分的代码更简洁,那些try...catch都可以不见了。这个的确是个好东东。 四、AOP AOP又称面向方面编程,它的实现原理还是用了反射:通过对某一个种类的方法名做监控来实现统一处理。比如:监控以“insert”字符串开头的方法名,在这种方法执行的前后进行某种处理(数据库事务等)。但这里我有一个疑问?不一定所有以insert开头的方法都是数据库操作,哪么当某个insert开头的方法不是数据库操作,你又对它进行了数据事务的操作,这样的错误如何防止???我对这方面了解不深,还是只知道一个大概。 曾看过一个程序员发出这样的感慨:"框架一个接一个,学也学不完,而且有必要吗?这样一层层的加上框架,还不如直接写JSP来得直接,效率还高。" 我想这种困惑很多人都有吧?但如果你经过的项目渐多,就会发现,维护项目要比开发项目更艰难,代价更大。那种用JSP直接来写,层次又不清楚的开发,往往最后得到一个不可再修改的软件,一团乱麻,移一发而动全身。但软件不象电视机,做好了就不会改动了,软件是一个变化的事物,用户的需求随时会改变,这时你会体会到分层和使用框架的好处了,它们为你做了软件中很多和业务无关的工作,你可以只关注业务,并减少代码量。唯一缺点就是有一个学习的代价,框架配置上也较麻烦。 学习框架,我认为应该:第一步,了解这个框架中的一些关键概念,它的具体含义是什么。第二步,了解这个框架的精华在哪里,它能对开发起到什么样的作用,最好能对它的原理有一定的了解。第三步,用这个框架来写几个例子,实际体会一下。我现在还是刚刚大概完成了前两步,这几天会再看看Spring的文档并用Spring写几个例子,到时一起发出来。 另外,很赞赏<Spring开发指南>的作者夏昕的观点,将自已的经验写成文档公开出来,不过一个人的力量终究太弱。最好能够形成一个组织,对一种新技术,由一两个人出一个大纲,大家把它分了,更写一章,然后由两三个人总集起。我个人感觉,由于英文语言的关系,新技术引进到国内的还是太慢了,至少要比国外慢上一年以上,成立一个开源文档组织还是很有意义的事。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2005-02-18
既然是概念理解。就要说说概念错误的地方
ioc绝对不是 引用 就是用XML来定义生成的对象 只能说,设计成ioc的程序可以很容易用ioc容器装配起来。而ioc容器通过读取配置文件进行装配。spring常用的是用xml格式的配置文件
|
|
返回顶楼 | |
发表时间:2005-02-18
我在春节前看了“程序员”05年第二期上的一篇文章,看了好几天,才有一些领悟,那篇文章大概讲的是人们如何认识动态代理(Dynamic Proxy)的历程,涉及了很多时下比较流行的概念,有很多问题,希望能够一起交流。
第一个阶段大概就是从JDK1.3开始DP(Dynamic Proxy)出现,但是很少有人明白如何使用 DP是这样一个类:可以在运行的时候、在创建这个类的时候才指定它(DP)所实现的接口,这些被DP实现的接口叫“代理接口”(Dynamic interface);代理类的实例叫“代理实例”(Proxy Instance),注意,每个“代理实例”都有一个对应的“调用处理器”(Invocation handler)对象,这个对象实现了java.lang.reflect.InvocationHandler接口。 当用户通过“代理接口”调用“代理实例”的方法时,该方法调用会被分发到该“代理实例”对应的“调用处理器”的invoke(...)方法,该方法的参数有三个,分别是:1。“代理接口” 2。java.lang.reflect.Method对象 3。被调用方法的参数数组 “调用处理器”可以在invoke(...)方法中对接收到的方法调用进行相应处理,该方法(invoke)的返回结果应该是“代理实例”被调用得到的结果 第二个阶段是,JBOSS的架构师Rickard Oberg发现了DP的用处 只有在实际的使用中才能发现问题,Oberg在设计JBoss容器时发现一些规律性的东西,“RMI访问的途径”,因为所有的EJB对象(如果想要被远程访问)都需要继承RemoteObject,并且实现不同的业务接口,最后还要绑定到RMI命名服务。而这正是DP的优势! 第三个阶段是,Oberg再接再厉,总结哪些事情是不断重复的,可以被DP解决。答案是:日志、安全、事务等等一些基础设施(infrastructure)功能。其实这些基础设施就是EJB容器的功能。同时,缺点就是业务对象必须实现容器特有的接口,这样对业务对象造成入侵,不再纯洁。而且,如果容器没有实现某种你所需要的功能,你就没有办法使用。 第四个阶段是Jon Tirsen考虑如何不使用代码生成技术实现AOP 最早在一些科研机构出现了一种叫“横切”(crosscut)的技术,来解决复用基础设施的方案。其中AspectJ是比较有名的,但是缺点是业务代码和aspect代码混合,不宜调试。Tirsen发现了Oberg的方法,那就是基于动态代理的AOP实现! 下班了,明天继续... |
|
返回顶楼 | |
发表时间:2005-02-19
pikachu 写道 既然是概念理解。就要说说概念错误的地方
ioc绝对不是 引用 就是用XML来定义生成的对象 只能说,设计成ioc的程序可以很容易用ioc容器装配起来。而ioc容器通过读取配置文件进行装配。spring常用的是用xml格式的配置文件你的说法比较准确。说到底还是Java反射运用。 |
|
返回顶楼 | |
发表时间:2005-02-19
引用 只有在实际的使用中才能发现问题,Oberg在设计JBoss容器时发现一些规律性的东西,“RMI访问的途径”,因为所有的EJB对象(如果想要被远程访问)都需要继承RemoteObject,并且实现不同的业务接口,最后还要绑定到RMI命名服务。而这正是DP的优势!
这里有一点不清楚,要理解动态代理,就要明白为什么要用它,它有什么作用。如果仅仅是为了EJB的.....,我觉得还是没有讲透。我对动态代理理解不深,在系统设计时只用过代理模式,创建一个代理类或接口。但为什么一定要动态生成一个接口,这个就不明白了,在Hibernate用到动态代理的地方也挺多。 不知道wanghongbin,您是否在系统设计中用到了动态代理。如果用到了能否拿出来一起分享一些,谈谈为什么。 |
|
返回顶楼 | |
发表时间:2005-02-19
IOC模式应该和IOC容器种使用xml进行装配区别开来,如同wanghongbin所说,可以在论坛收索ajoo的帖子。
你说的IOC的优点和缺点其实都应该算在“IOC容器装配各组件”身上。 其实还有个缺点:无法编译纠错,:( 运行时的错误需要经验才能看出来出错的原因。 AOP的作用可以简单如下所说:“在一个组件的前后加上一些固定的内容。” 抛开AOP不说,我们自己如果想要写这东西,无非两种方式,一个是proxy实现,然后在proxy的前后添加内容;还有一种就是template实现。 所以在我看来,数据库层的模板其实也算是一种“AOP”。 不知道有没人对此有些意见和评述? “不一定所有以insert开头的方法都是数据库操作” 那么你就自己别用insert做其他用途啊,这还不简单,他提供了正则表达式,:) 你自己爱怎么自己配吧 |
|
返回顶楼 | |
发表时间:2005-02-20
glchengang 写道 引用 只有在实际的使用中才能发现问题,Oberg在设计JBoss容器时发现一些规律性的东西,“RMI访问的途径”,因为所有的EJB对象(如果想要被远程访问)都需要继承RemoteObject,并且实现不同的业务接口,最后还要绑定到RMI命名服务。而这正是DP的优势!
这里有一点不清楚,要理解动态代理,就要明白为什么要用它,它有什么作用。如果仅仅是为了EJB的.....,我觉得还是没有讲透。我对动态代理理解不深,在系统设计时只用过代理模式,创建一个代理类或接口。但为什么一定要动态生成一个接口,这个就不明白了,在Hibernate用到动态代理的地方也挺多。 不知道wanghongbin,您是否在系统设计中用到了动态代理。如果用到了能否拿出来一起分享一些,谈谈为什么。 动态代理一般运用在系统框架中 ,利用动态代理 ,系统框架 对应用提供的类不需要依赖于特定的业务接口。使得既可以使 得用户随意扩展,又使得整个系统框架顺利构建。 这个可以 具体参考spring里的 对于 事务 管理提供得 代理。 |
|
返回顶楼 | |
发表时间:2005-02-20
IOC的核心是对于依赖性管理的思想,最好的一句话还是好莱坞原则(当然如果用“依赖注入”更容易理解),反射、动态代理只是实现的工具。
|
|
返回顶楼 | |
发表时间:2005-02-20
引用 其实还有个缺点:无法编译纠错,:( 运行时的错误需要经验才能看出来出错的原因。
这基本是各种用XML的通用的缺点,象Struts、Hibernate,都差不多。 IoC生成对象速度慢一点,是不是也算个缺点。比如一个WEB应用,最常的就是用工厂模式取得一个数据库操作类(这个类包括各个模块读写数据库的方法)。现在,如果取消工厂模式,改用IoC将数据库操作类注入,这时效率的损耗会有多大?因为生成数据库操作类对象太频繁了,这样的损耗能否接受?不知道真正用IoC做过项目实践的同行是怎么考虑这个问题的。 引用 那么你就自己别用insert做其他用途啊,这还不简单,他提供了正则表达式,:) 你自己爱怎么自己配吧
看来这点除了自己小心注意,没有其他很好的避免方法了。 firebody:你在设计系统时用过动态代理吗? 我估计一般的系统设计中很少会用到吧,看来也只能去看Spring的源码才能体会了。谢谢。 引用 IOC的核心是对于依赖性管理的思想,最好的一句话还是好莱坞原则(当然如果用“依赖注入”更容易理解),反射、动态代理只是实现的工具。
我是学数学的,数学概念一般都艰深生涩,对于概念的学习,一般是先知道这个概念的具体定义(这时一般还是理解不深),然后是做习题运用这个概念并体会这个概念,第三步是用自己的语言归纳总结这个概念。我还是喜欢用通俗化、具体化、形象化来描述概念,个人喜好的原因。 |
|
返回顶楼 | |
发表时间:2005-02-20
引用 IOC模式应该和IOC容器种使用xml进行装配区别开来,如同wanghongbin所说,可以在论坛收索ajoo的帖子。
ajoo的那个帖看完了。http://forum.iteye.com/viewtopic.php?t=6778&postdays=0&postorder=asc&highlight=ajoo&start=0 ajoo在那个帖子表达的意思我的理解是两个: (1)IoC是一个设计思路,Spring(也就所谓的IoC容器)等是实现了这个设计思路 (2)尽量在系统中把Spring等的代码限制到最小。 第(1)点没什么好谈的,接近于常识。 第(2)点,我赞同。因为曾经用Hibernate做过一个项目,代码遍布生成Session,关闭Session的代码,Hibernate和系统代码结合得很紧密。后来因为一些其他原因,差点要替换掉Hibernate,当时我头皮都麻了,因为业务层和数据库层的代码都要重新修改。所以将一个框架在系统中的影子缩到最小是有必要的。 怎么缩小Spring框架的影响,就IoC部份谈谈我的想法: 因为IoC主要的作用是对象的组装(通俗来说就是对象生成),我的思路是在Spring的IoC代码之后再封装一层,将它和Spring的代码和业务代码分隔开来。 以下是常用的一个Spring中的取对象代码。这是业务代码中的一个片断。 ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");; Human human = null; human = (Human); ctx.getBean("chinese");; 这样的问题就是在业务代码里会遍布ApplicationContext 等的影子,假设以后要求不用Spring了,你会怎么办??慢慢改去吧。 所以要把ApplicationContext剔除出去。这无非是取得对象,封装一个工厂方法好了。 Factory factory=new Factory();; Human human = null; human = (Human); factory.getBean("chinese");; public class Factory{ public Object getBean(String beanName);{ ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");; if (beanName.equre("chinese"););{ return ctx.getBean("chinese");; }else if ....... ....... } } 这样在业务代码里看起来还是象一个普通的工厂模式,只不过在工厂里的对象装配上是用了Spring的IoC现实。如果以后不用IoC了,在工厂里还是象以前那样写死对象生成方法好了。前面的业务方法则都不用修改。 |
|
返回顶楼 | |