以下是我网上找的资料,感谢原著。但我还是搞不明白spring.net 带来的好处,可能真是像网上说的那样,超大项目才能体会。
你现在只是学习阶段不能体会到spring真正的好处
如果你开发一个项目的话(加入给予SSH框架的) ,项目中的类是巨多了,有许多的aciton类、actionform类 有许多的业务逻辑层类 有DAO
当然如果你不用spring去配置也行,用到某个类时可以直接new,但是这样做出来的项目维护起来很难,首先两个之间你用new的话
那么这两个类之间的耦合度就高了
而用spring以后,你不用在关心这等等的一切 ,他全部给你摆到配置文件中
你有一个UserAction ,OK!在spring中你就只要配置一下
<bean id="userAction" class="*.UserAction"></bean>
如果UserAction类中用到UserManager类的话,你也不用直接在程序中new了 ,你只需在程序中提供一个UserManager的set方法
然后在配置文件中直接配置下就完成了
<bean id="userManager" class="*.UserManager">
<property name="userManager" ref="UserManager"/>
</bean>
Spring就可以给你同意管理这些所有的aciton 类 所有的业务逻辑类 等等
当你项目写好部署到服务器运行时,服务器一启动,就会自动读取spring的配置文件,然后把你配置的这些类全部实例化好..
把你写的对象类全部给导出成数据库表,而不向你学hibernate的时候 写好的对象类还要自己写一个导出程序 给他导出成数据库表
如果你写过项目就能体会到他的妙处,很强大 .....................
————————————————————————————————————————————————————————————————————————
在SSH框架中使用Spring的好处
struts负责控制Service(业务逻辑处理类),从而控制了Service的生命周期,这样层与层之间的依赖很强,属于耦合。这时,使用spring框架就起到了控制Action对象(Strus中的)和Service类的作用,两者之间的关系就松散了,Spring的Ioc机制(控制反转和依赖注入)正是用在此处。
Spring的Ioc(控制反转和依赖注入)
控制反转:就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控
依赖注入:组件之间的依赖关系由容器在运行期决定 ,由容器动态的将某种依赖关系注入到组件之中 。
从上面我们不难看出:从头到尾Action仅仅是充当了Service的控制工具,这些具体的业务方法是怎样实现的,他根本就不会管,也不会问,他只要知道这些业务实现类所提供的方法接口就可以了。而在以往单独使用Struts框架的时候,所有的业务方法类的生命周期,甚至是一些业务流程都是由Action来控制的。层与层之间耦合性太紧密了,既降低了数据访问的效率又使业务逻辑看起来很复杂,代码量也很多。,Spring容器控制所有Action对象和业务逻辑类的生命周期,由于上层不再控制下层的生命周期,层与层之间实现了完全脱耦,使程序运行起来效率更高,维护起来也方便。
使用Spring的第二个好处(AOP应用):
事务的处理:
在以往的JDBCTemplate中事务提交成功,异常处理都是通过Try/Catch 来完成,而在Spring中。Spring容器集成了TransactionTemplate,她封装了所有对事务处理的功能,包括异常时事务回滚,操作成功时数据提交等复杂业务功能。这都是由Spring容器来管理,大大减少了程序员的代码量,也对事务有了很好的管理控制。Hibernate中也有对事务的管理,hibernate中事务管理是通过SessionFactory创建和维护Session来完成。而Spring对SessionFactory配置也进行了整合,不需要在通过hibernate.cfg.xml来对SessionaFactory进行设定。这样的话就可以很好的利用Sping对事务管理强大功能。避免了每次对数据操作都要现获得Session实例来启动事务/提交/回滚事务还有繁琐的Try/Catch操作。这些也就是Spring中的AOP(面向切面编程)机制很好的应用。一方面使开发业务逻辑更清晰、专业分工更加容易进行。另一方面就是应用Spirng AOP隔离降低了程序的耦合性使我们可以在不同的应用中将各个切面结合起来使用大大提高了代码重用度
ioc是一种类的实现方法,而不是关于接口设计的方法。
它的关注点是 我怎么实现这个类最简单灵活 。
而不关注别人如何调用我的模块最简单明了。
设计模块A的实现,当它需要从另外一个模块得到功能B的时候,基本有两种选择:
1。直接静态地找到实现B的模块。自己用new创建B的对象,或者通过一个静态工厂,service locator。都属于这个范畴。
这种情况其实很常见。比如,我内部需要一个查找表,自己直接new一个HashMap就好了,谁耐烦从外界ioc进来一个Map这么麻烦?
或者,大家平时都自己new一个StringBuffer吧?没人从外面ioc吧?
采用这个方法的前提是:
a. 自己具体选取哪个模块对外界完全透明。比如,我用HashMap还是TreeMap,只影响效率,但是不影响我这个模块对调用者承诺的语义。
b. 或者,实现这个功能的B模块已经是一个100%的标准。
这两个前提满足任何一个,都没必要也不应该ioc。
2。从外界动态接收一个实现功能B的实例。
这就是ioc了。不过,ioc本身并不规定注射进来的就必须是一个接口。注射一个具体类,抽象类也是ioc。只不过一般来说,根据接口编程原则,用接口更加好。
采用它的前提是:
a. 不同的B的实现会影响A的语义。而在设计A的时候我们不能决定选择哪个实现。
b. 或者,实现B的模块没有一个标准,考虑到移植性的问题,可以用ioc来把责任推诿到其它模块。
采用ioc的几个注意点:
a. 最好是要ioc进来的组件是immutable的,没有状态。这样的ioc最简单。
b. 如果需要状态变化,那么关于状态变化的语义一定要定义清楚。调用者和被调用者各自改变组件的状态都有什么结果要明确。
c. 如果模块内部需要自己控制对象的生命期,此时就要ioc进来一个工厂。(注意,工厂也是一个普通的java对象,自然也可以ioc。同理,工厂的工厂,工厂的工厂的工厂,都可以ioc。不要一看见工厂字样就觉得和ioc抵触。工厂不过是一个有着一个create()函数的对象而已)
d. 不要杞人忧天,想着别人如何把这个对象给你。OO是一个职责分配的体系。你该关心的是如何用这个组件实现你自己的功能,至于组件怎样来,不是你的责任,你不要管也不应该管。
e. 要学会偷懒和推卸责任。通过把寻找对象的职责推诿出去,你可以保证少挨骂。如果组装者组装了一个错误的组件,那么责任在他,你大可以跳起脚来骂。而如果你自己越俎代庖弄错了,责任则全部在你。
f. 即使组装者也是你自己,ioc至少保证了改正错误或者扩展功能的代价最小化。你需要修改的只是组装部分,而不是包含者业务逻辑的业务对象。
好了。说完怎么用ioc实现模块。再来说怎么使用一个ioc设计的模块。
正如frankensteinlin所说,调用者直接调用一个ioc模块并不是最简单最直观的。
new AImpl(new BImpl()).f()
明显比new DefaultAImpl().f()要麻烦。
但是,很多时候调用者自己也不必惹这个麻烦的。我的模块C如果需要A的功能,大可以继续推诿责任,让别人给我一个A的实例就是。
如此,创建C的时候就变成:
- new CImpl(new AImpl(new BImpl(););););;
这样层层推诿,最终会有一个组装者,他把所有的对象组装责任接过来,他的唯一责任就是组装各个组件,而没有业务逻辑方面的职责。
不过,我要反对age0以及很多其它人的是:
ioc并不是说系统只能有一个终极对象组装者(比如配置文件什么的)。
系统是模块套模块的。有时候模块A不能决定,推诿出去,模块B不能决定,也推诿出去,但是模块C可能发现此时选择AImpl1, 还是AImpl2, 选择BImpl1还是BImpl2对它要实现的语义来说已经符合上面说的不用ioc的前提了,那么此时,对象C就可以作为局部的A和B的组装者,没必要把这个职责再推诿出去了。
而这些组装策略也不是一言堂。根据不同的组装者的需要,可以选择直接new,静态工厂,service locator,或者配置文件。
这里面没有东风压倒西风的问题,完全是根据具体需要选择合适的组装方法。
最后,重提java.io。
当sun设计BufferedReader的时候,虽然从它的功能上你可以叫它decorator,但是它的设计方法却无疑是ioc的。
它从外界接受一个Reader实例,然后对之进行缓存处理。
它不对输入的Reader到底是哪个Reader做任何假设或者要求。它只是简单地在构造函数里宣称需要一个Reader。
然后,当我们的一个模块X使用BufferedReader的时候,可能我们已经知道需要给它一个什么Reader,此时,就没必要继续ioc了,在这个X模块里,ioc到此为止,我们直接组装对象就好了。
有没有可能一个Reader要在终极的配置文件里由deploymentor决定采用哪个实现呢?理论上应该也有可能,只不过,我至今还没有遇到过。
我们先后为某银行做了2套系统,等第二套快做完的时候,银行说虽然是2套,但我想用统一的用户管理,想想这也是合理,一个单位的员工没有必要在两个地方管理。所以就把有关用户/权限管理的数据单独拎出来了。
这时候我的系统就要访问2个数据源了,怎么办呢?
在Spring的配置里增加一个DataSource指向新的数据源,把有关用户数据访问的DAO的Datasource全改一遍,OK!十分钟搞定。
而前一套系统呢,2年多前做的了,设计得没有这么好,改动太大,最终只能放弃,还是把数据放在它那里,由后一套系统的Datasource指过去。
这大约就是IOC的好处了。
前面也有人说过了,在需要Ioc的地方才用,不能全都用,这也是一个原则。前面的讨论有时就险入以偏概全的问题,一说Ioc,好像就必须全部用似的。