实例说明Spring的2种注入方式

来源:互联网 发布:主题医院 mac 编辑:程序博客网 时间:2024/06/15 03:12

1、依赖注入

以往3种自主控制依赖关系注入的方式有:由bean自己来控制其实例化、直接在构造器中指定依赖关系、类似服务定位器模式。

DI主要有2种注入方式,即Setter注入和constructor注入。

1setter注入:在java类中为属性添加set方法,在配置文件配置

Company类定义如下:

public class Company {    private int id;    private String name;    private Boolean chinese;    private Person CEO;….   get/set function …  }

Person类如下所示:

public class Person {    private Integer id;    private String name;    private Integer age;    private String email;….   get/set function …  }

对应的XML文件applicationContext.xml配置如下所示:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans><bean id="person"class="org.shirdrn.entity.Person" abstract="false"   singleton="true" lazy-init="default"autowire="default"   dependency-check="default">   <property name="id">      <value>1001</value>   </property>   <property name="name">      <value>Shirdrn</value>   </property>   <property name="age">      <value>26</value>   </property>   <property name="email">      <value>shirdrn@hotmail.com</value>   </property></bean><bean id="companyBean"class="org.shirdrn.entity.Company"   abstract="false" singleton="true"lazy-init="default"   autowire="default"dependency-check="default">   <property name="id">      <value>2008</value>   </property>   <property name="name">      <value>CNAET</value>   </property>   <property name="chinese">      <value>true</value>   </property>   <property name="CEO">      <ref bean="person" />   </property></bean></beans>

测试的程序代码如下:

public class Main {public static void main(String[] args){   ApplicationContext ctx = newFileSystemXmlApplicationContext("src/applicationContext.xml");   Company c = (Company)ctx.getBean("companyBean");   System.out.println("company's id         = "+c.getId());   System.out.println("company'sname        = "+c.getName());   System.out.println("company is Chinese    ="+c.getChinese());   System.out.println("--- the following is CEO's detail---");   System.out.println("CEO's id      ="+c.getCEO().getId());   System.out.println("CEO's name    ="+c.getCEO().getName());   System.out.println("CEO's age     ="+c.getCEO().getAge());   System.out.println("CEO's Email   ="+c.getCEO().getEmail());  }}

测试输出结果如下所示:

company's id          =2008
company's name        = CNAET
company is Chinese    = true
--- the following is CEO's detail ---
CEO's id      = 1001
CEO's name    = Shirdrn
CEO's age     = 26
CEO's Email   =

2、constructor注入

通过带参数的构造器实现,还可以通过给静态工厂方法传参数来构造bean,在配置文件配置。

    <1>构造器实现

<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;    }}

    <2>静态工厂实现

<bean id="exampleBean" class="examples.ExampleBean"      factory-method="createInstance">  <constructor-arg ref="anotherExampleBean"/>  <constructor-arg ref="yetAnotherBean"/>  <constructor-arg value="1"/> </bean><bean id="anotherExampleBean" class="examples.AnotherBean"/><bean id="yetAnotherBean" class="examples.YetAnotherBean"/>  

public class ExampleBean {    //私有的构造器    private ExampleBean(...) {... }    //静态工厂方法;方法参数由constuctor-arg元素提供,方法内对象的构造参数依赖于         工厂方法参数,但不必全部使用.    public static ExampleBean createInstance (            AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {        ExampleBean eb = new ExampleBean (...);        // some other operations...        return eb;    }} 

    【工厂方法返回的实例类型并不一定要与包含该静态方法的类类型一致!!

       如果是非静态的实例工厂方法,则配置bean时使用factory-bean而不是class属性,其余相同。】

二者如何选择:

<1>大量的constructor参数会使程序变得笨拙,特别是某些属性可选时。因此Spring开发团队提倡使用setter注入。而且setter注入在以后某个时候还可以对实例重新配置。

<2>constructor注入一次性将所有依赖注入的做法意味着在未完全初始化的状态下,此物件不会返回给客户代码(或被呼叫),此外物件也不可能再次被重新配置。

<3>由于setter注入提供set方法,所以不能保证相关的成员或资源在执行时期不会被更改设定,所以如果想要让一些成员或资源变为只读或私有,则使用constructor是简单的选择。对于没有原始码的第三方类,或者没有提供setter方法的遗留代码,只能使用constructor注入。