我的Pro Spring 学习笔记 之二 控制反转(IoC)和依赖注入(DI), Spring初步 对应原书第四章 这些概念的讨论的资料在网上非常之多。所以本节基本上是罗列一些较为权威的连接,以及一些观点的摘要。 也会研究一些简单的例子来加深对概念的理解。
第一:观点
提到IoC和DI就不能不提Martin Fowler(http://martinfowler.com)。他的Inversion of Control Containers and the Dependency Injection pattern(http://martinfowler.com/articles/injection.html)一文是无论 如何都必须要读过的。透明翻译的中文版的连接 http://gigix.blogdriver.com/diary/gigix/inc/DependencyInjection.pdf。 优快云上公布了Pro Spring书籍中文版的第四章http://book.youkuaiyun.com/bookfiles/48/100481401.shtml 。 当然,永远不要忘记Google。使用控制反转和依赖注入作为关键词可以搜索到数十万项条目。
第二:我的总结
1> 类似于Service Locator的依赖查找(非依赖注入) 这种方式使用之处是如此之多:JNDI, EJB, J2EE设计模式的Service Locator等。使用Spring的应用中也是以 这个方式根启动Spring 的BeanFactory/ApplicationContext的。但是。普遍的使用这种方式是不推荐的。 2>使用特定接口注入 因为其需实现特定的接口而有较强的侵入性,所以也不推荐。 3>构造器注入 4>Setter注入 关于上述两种注入方式的比较,在Martin的文章里讲了很多。Martin本身似乎更倾向于构造器注入。但事实上两 者的优缺点可以说是见仁见智。Spring的用户大多好像更倾向Setter注入。很明显,Pro Spring的作者也是倾向于 Setter注入的 Spring本身是既支持构建器注入,也支持Setter注入的。 Pro Spring中额外阐述了如下的Setter注入的优点 1>一个类在将他的依赖关系暴露给容器的同时,也希望自己保留一个缺省的依赖关系。(简单的说,就是在你不希 望容器注入依赖的时候,在配置中不申明依赖,在希望注入的时候申明依赖。而具体的类中,提供一个缺省的实现。) 2>允许商业接口中同时包含Setter以注入依赖。(这一段的翻译比较晦涩) 显然这一点是构造器注入无法达到的:但是也不能过度地使用这一特性。某种资源对于某一个特定的实现是必须的, 而对另一个特定的实现则并非必须。 Pro Spring书中提到的一些判断准则是: a>被动的配置参数。这些参数值是辅助完成某一个商业逻辑,而非一个完整的商业逻辑 b>是一些消息片断而非其它组件 c>是一些简单的值和值的组合。 归根到底,决定是否在商业逻辑的结构中定义Setter的依据是其对所有的实现必须,还是只对特别的实现必须。 3>能够在运行起替换依赖的实现。 此外本章也讨论了一些其它的一些基本的特性, 如BeanFactory嵌套,自动装配,配置继承,别名等等。请参见以 下例程的讨论.
第三:例程。
1> HelloWorldXmlWithDI.java 使用xml方式配置。 看点1:使用了XmlBeanFactory 看点2:使用bean标记申明Bean, 使用ref标记配置依赖。 2> HelloWorldXmlWithConstructorDI.java 使用构造器注入 看点1:使用构造器注入值和对象 注意:ch2项目中的MessageRenderer必须要修改,注释掉setMessageProvider。(这也佐证了我们上面的学习: 商业接口中的Setter,一定要深思熟虑之后再加入。) 3>ConstructorConfusion.java 看点:通过指定type 避免构造器的混淆. 4>BeanFactory的嵌套 HierarchicalBeanFactoryUsage.java 对此小结一下:如果同名的话,子工厂内的定义覆盖父工厂的定义,除非使用parent来指明。子工厂来没有的,可以 用<ref bean="injectBeanParent"></ref>引用父工厂内的定义。而local总是在子工厂中寻找定义,如果找不到,则抛出 异常 org.springframework.beans.factory.BeanDefinitionStoreException 关于这个方面,可以看一下这个讨论:http://www.iteye.com/topic/15057。 5>注入集合 CollectionInjection.java 看点:注入集合的时候,map, list, set, Properties 都有不同的标签支持 6>Bean命名和Bean别名 BeanNaming.java 看点:Bean可以通过id, name, class等三种方式取得.name支持多个别名。 7>单例/非单例/对象池 NonSingleton.java 传统单例模式的短处: 将单一对象的维护和查找混合到了一起。无法实现面对接口编程。不能比较容易地替换实现。 而Spring管理单例则没有这方面的缺点。 缺省地,Spring创建的bean都是单例。关于这一点,可以参见讨论http://www.iteye.com/post/192557 (翻译有一处错误。原文是 Your application code must always have explicit knowledge of the Singleton class in order to obtain the instance—completely removing the ability to code to interfaces. 译者翻译成了:你的应用程序代码必须知道单例类的确切信息才可以得到它的实例—完全地将这种能力转移到接口 的代码中。个人感觉上后半句应该译成:完全不符合依赖接口编程的良好习惯等。很明显这个误译和原文意思有点 相反了。code to interfaces是惯用语,不是code of interfaces.这本书总体上翻译不错,但第四章翻译质量不高。再者全书使用术语不 够统一,也算是个缺点) 非单例:对于非单例对象,Spring不能管理其生命周期,也就是说,两个生命周期事件不会被触发。(详见下一章) 8>自动组装 autowring/Target.java 四种自动组装模式:byName, byType, consturctor, autodetect. byType的组装方式, 如果有构造器的话,要求必须有一个缺省的无参构造器,否则报错。如果没有任何构造器的话, 不会报错。怀疑这是一个Spring的Bug,等网络恢复后查证。 autodetect则在byType和constructor方式之间做出选择。无任何构造器或者有一个缺省无参构造器的话,遵从byType。 否则遵从constructor。 9>申明依赖检查 关于依赖的两个配置属性。需要区分清楚。一个是depends-on。depends-on 反映的对象之间的依赖关系,即某个对象 必须在另一个对象之前完成初始化以提供必须的资源等. 另一个是dependency-check。这个是用来申明是否需要Spring来检查bean的每个属性在创建完成后都有对应的值。 simple: 只检查集合类和java内建类属性是否有值对应。 objects:只检查非内建类属性 all:检查全部 10>配置继承 依赖关系,单例模式,自动组装等不能被覆盖。
代码来源于书籍,略有改动
338

被折叠的 条评论
为什么被折叠?



