Blog信息 |
blog名称:小鸟吹烟 日志总数:157 评论数量:424 留言数量:-1 访问次数:1252918 建立时间:2006年10月23日 |

| |
[Spring 学习专区]setter注入 与 构造器注入 文章收藏, 网上资源, 软件技术
tone 发表于 2007/9/14 9:24:09 |
<1>新的bean作用域Spring上个版本的IoC容器支持两个不同的bean作用域(单例与原型)。Spring 2.0改进了这一点,不仅提供了一些依赖于Spring部署环境(比如说,在web环境中的request和session作用域bean)的额外的作用域,而且提供了所谓的'钩子'('hooks')(因为找不到更好的表达)使Spring用户可以创造自己的作用域。
应该注意的是,即使单例与原型作用域beans的基本(内在)实现发生了变化,上述变化对最终用户来说是透明的...现有的配置不需要改变或放弃。
<2>org.springframework.beans及org.springframework.context包是Spring IoC容器的基础。BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能。ApplicationContext是BeanFactory的扩展,功能得到了进一步增强,比如更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对web应用的WebApplicationContext)。
简而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext则增加了更多支持企业核心内容的功能。ApplicationContext完全由
BeanFactory扩展而来,因而BeanFactory所具备的能力和行为也适用于ApplicationContext。
<3>bean之间的关系,即协作 (或者称依赖)。在对bean进行定义时,除了使用id属性来指定名称之外,为了提供多个名称,需要通过alias属性来加以指定。<alias name="componentA-dataSource" alias="componentB-dataSource"/><alias name="componentA-dataSource" alias="myApp-dataSource" />
class属性主要有两种用途:在大多数情况下,容器将直接通过反射调用指定类的构造器来创建bean(这有点等类似于在Java代码中使用new操作符);在极少数情况下,容器将调用类的静态工厂方法来创建bean实例,class属性将用来指定实际具有静态工厂方法的类(至于调用静态工厂方法创建的对象类型是当前class还是其他的class则无关紧要)。
<4>如何在构造器注入和Setter注入之间进行选择?
由于大量的构造器参数可能使程序变得笨拙,特别是当某些属性是可选的时候。因此通常情况下,Spring开发团队提倡使用setter注入。而且setter DI在以后的某个时候还可将实例重新配置(或重新注入)(JMX MBean就是一个很好的例子)。
尽管如此,构造器注入因为某些原因还是受到了一些人的青睐。一次性将所有依赖注入的做法意味着,在未完全初始化的状态下,此对象不会返回给客户代码(或被调用),此外对象也不可能再次被重新配置(或重新注入)。
对于注入类型的选择并没硬性的规定。只要能适合你的应用,无论使用何种类型的DI都可以。对于那些没有源代码的第三方类,或者没有提供setter方法的遗留代码,我们则别无选择--构造器注入将是你唯一的选择。
<5>循环依赖
当你主要使用构造器注入的方式配置bean时,很有可能会产生循环依赖的情况。
比如说,一个类A,需要通过构造器注入类B,而类B又需要通过构造器注入类A。如果为类A和B配置的bean被互相注入的话,那么Spring IoC容器将在运行时检测出循环引用,并抛出 BeanCurrentlyInCreationException异常。
对于此问题,一个可能的解决方法就是修改源代码,将构造器注入改为setter注入。另一个解决方法就是完全放弃使用构造器注入,只使用setter注入。
<6><bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested <ref/> element --> <property name="beanOne"><ref bean="anotherExampleBean"/></property>
<!-- setter injection using the neater 'ref' attribute --> <property name="beanTwo" ref="yetAnotherBean"/> <property name="integerProperty" value="1"/></bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/><bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean
{
private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i;
public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; }
public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; }
public void setIntegerProperty(int i) { this.i = i; } }正如你所看到的,bean类中的setter方法与xml文件中配置的属性是一一对应的。
接着是构造器注入的例子。以下是xml配置代码以及相对应的java类代码。
<bean id="exampleBean" class="examples.ExampleBean"> <!-- constructor injection using the nested <ref/> element --> <constructor-arg><ref bean="anotherExampleBean"/></constructor-arg> <!-- constructor injection using the neater 'ref' attribute --> <constructor-arg ref="yetAnotherBean"/> <constructor-arg type="int" value="1"/></bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/><bean id="yetAnotherBean" class="examples.YetAnotherBean"/>public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean( AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; }}
<7><beans><bean id="parent" abstract="true" class="example.ComplexObject"> <property name="adminEmails"> <props> <prop key="administrator">administrator@somecompany.com</prop> <prop key="support">support@somecompany.com</prop> </props> </property></bean><bean id="child" parent="parent"> <property name="adminEmails"> <!-- the merge is specified on the *child* collection definition --> <props merge="true"> <prop key="sales">sales@somecompany.com</prop> <prop key="support">support@somecompany.co.uk</prop> </props> </property></bean><beans>在上面的例子中,childbean的adminEmails属性的<props/>元素上使用了merge=true属性。当child bean被容器实际解析及实例化时,其 adminEmails将与父集合的adminEmails属性进行合并。
administrator=administrator@somecompany.comsales=sales@somecompany.comsupport=support@somecompany.co.uk
<8>Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的
bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。典型情况下,DAO不会被配置成prototype,因为一个典型的DAO不会持有任何会话状态,因此应该使用singleton作用域。
http://ricardo-flu.spaces.live.com/Blog/cns!448FCFE483AC8D88!156.entry |
|
|