依赖注入(DI)背后的基本原理是对象之间的依赖关系(即一起工作的其它对象)只会通过以下几种方式来实现:构造器的参数、工厂方法的参数,或给由构造函数或者工厂方法创建的对象设置属性。因此,容器的工作就是创建bean时注入那些依赖关系。相对于由bean自己来控制其实例化、直接在构造器中指定依赖关系或者类似服务定位器(Service Locator)模式这3种自主控制依赖关系注入的方法来说,控制从根本上发生了倒转,这也正是控制反转(Inversion of Control, IoC) 名字的由来。

      应用DI原则后,代码将更加清晰。而且当bean自己不再担心对象之间的依赖关系(甚至不知道依赖的定义指定地方和依赖的实际类)之后,实现更高层次的松耦合将易如反掌。DI主要有两种注入方式,即Setter注入和构造器注入。

    

Setter注入:

    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 setI(int i) {

          this.i = i;

       }

}

 

    <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"/>

 

     bean类中的setter方法与xml文件中配置的属性是一一对应的.

 

  构造器注入:

  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;

       }

   }

 

   <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"/>

 

       在xml bean定义中指定的构造器参数将被用来作为传递给类ExampleBean构造器的参数。

 

 

       采用static工厂方法返回对象实例,来替代构造器的方法:

   public class ExampleBean {

       // a private constructor

       private ExampleBean(...) {

         ...

      }

     /* a static factory method; the arguments to this method can be

     considered the dependencies of the bean that is returned,

     regardless of how those arguments are actually used.

     */

      public static ExampleBean createInstance (

            AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {

        ExampleBean eb = new ExampleBean (...);

        // some other operations...

        return eb;

     }

  }

 

 

  <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"/>

 

 

    请注意,传给static工厂方法的参数由constructor-arg元素提供,这与使用构造器注入时完全一样。而且,重要的是,工厂方法所返回的实例的类型并不一定要与包含static工厂方法的类类型一致。尽管在此例子中它的确是这样。非静态的实例工厂方法与此相同(除了使用factory-bean属性替代class属性外),因而不在此细述。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐