依赖注入(DI)的几种方式示例

本文介绍了Spring依赖注入的四种方式:属性注入、构造器注入、静态工厂方法注入和实例工厂方法注入,重点讨论了属性注入和构造器注入的优缺点。属性注入方便直观,适合依赖关系复杂的场景;而构造器注入在构造期就创建完整对象,有利于保持组件稳定性,降低外部破坏依赖关系的风险。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为本系列是为探究spring Ioc原理,故使用的spring版本为早期spring1.1.1版本,pom及相关依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.liusj</groupId>
  <artifactId>springSource</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>springSource Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>


    <!-- spring1.1.1 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
      <version>1.1.1</version>
    </dependency>

      <!-- log4j https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
      <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
      <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
      </dependency>


      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>RELEASE</version>
          <scope>test</scope>
      </dependency>
  </dependencies>
</project>

四种依赖注入方式

Spring 依赖注入有四种方式:属性(setter)注入,构造器注入,静态工厂方法注入,实例工厂方法注入。最常见的是属性注入和构造器注入。下面对这几种注入方法举例说明:

  • 属性(setter) 注入
<!-- setter-based dependency injection -->
    <bean id="exampleBean" class="dependency_injection.ExampleBean">
        <property name="beanOne"><ref bean="anotherBean"/></property>
        <property name="beanTwo"><ref bean="yetAnotherBean"/></property>
        <property name="integerProperty"><value>1</value></property>
    </bean>

<bean id="anotherBean" class="dependency_injection.AnotherBean"/>
<bean id="yetAnotherBean" class="dependency_injection.YetAnotherBean"/>
  • 构造器注入
<!-- constructor-based dependency injection -->
    <bean id = "exampleBean1" class="dependency_injection.ExampleBean">
        <constructor-arg index="0" type="dependency_injection.AnotherBean">
            <ref bean="anotherBean"></ref>
        </constructor-arg>
        <constructor-arg>
            <ref bean="yetAnotherBean"></ref>
        </constructor-arg>
        <constructor-arg>
            <value>3</value>
        </constructor-arg>
    </bean>
  • 静态工厂方法注入:
<!-- static factory method dependency injection-->
    <bean id = "exampleBean2" class="dependency_injection.MyFactoryBean"
        factory-method="getExampleBeanInstance">
    </bean>
    <bean id = "exampleBean3" class="dependency_injection.MyFactoryBean"
          factory-method="getExampleBeanWithParamInstance">
        <constructor-arg>
            <ref bean="anotherBean"></ref>
        </constructor-arg>
        <constructor-arg>
            <ref bean="yetAnotherBean"></ref>
        </constructor-arg>
        <constructor-arg>
           <value>2</value>
        </constructor-arg>
    </bean>
  • 实体工厂方法注入:
<!-- instance factory method dependency injection-->
    <bean id="myfacotory" class="dependency_injection.MyFactoryBean"></bean>
    <bean id="exampleBean4" factory-bean="myfacotory" factory-method="getExampleBean">
    </bean>

上述类具体实现:

ExampleBean.java

package dependency_injection;

/**
 * Created by Administrator on 2018/3/28 0028.
 */
public class ExampleBean {
    private AnotherBean beanOne;
    private YetAnotherBean beanTwo;
    private String integerProperty;

    public ExampleBean(){

    }
    public ExampleBean(AnotherBean anotherBean, YetAnotherBean yetAnotherBean,String integerProperty){
        this.beanOne = anotherBean;
        this.beanTwo = yetAnotherBean;
        this.integerProperty = integerProperty;
    }
    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public AnotherBean getBeanOne() {
        return beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public YetAnotherBean getBeanTwo() {
        return beanTwo;
    }

    public void setIntegerProperty(String integerProperty) {
        this.integerProperty = integerProperty;
    }

    public String getIntegerProperty() {
        return integerProperty;
    }

}

AnotherBean.java

package dependency_injection;

/**
 * Created by Administrator on 2018/3/28 0028.
 */
public class AnotherBean {
}

MyFactoryBean.java

package dependency_injection;

/**
 * Created by Administrator on 2018/3/28 0028.
 */
public class MyFactoryBean {
    public static ExampleBean exampleBean = null;

    public static ExampleBean getExampleBeanInstance(){
        if(exampleBean == null){
            exampleBean = new ExampleBean();
            return exampleBean;
        } else {
            return exampleBean;
        }
    }

    public static ExampleBean getExampleBeanWithParamInstance(AnotherBean anotherBean, YetAnotherBean yetAnotherBean,String integerProperty){
        if(exampleBean == null){
            exampleBean = new ExampleBean();
            exampleBean.setBeanOne(anotherBean);
            exampleBean.setBeanTwo(yetAnotherBean);
            exampleBean.setIntegerProperty(integerProperty);
            return exampleBean;
        } else {
            return exampleBean;
        }
    }

    public ExampleBean getExampleBean(){
        return exampleBean;
    }
}

YetAnotherBean.java

public class YetAnotherBean {
}

测试类 DI_Test.java

package dependency_injection;

import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

/**
 * Created by Administrator on 2018/3/28 0028.
 */
public class DI_Test {
    @Test
    public void testSetterDI() {
        ClassPathResource classPathResource = new ClassPathResource("di_beans.xml");
        XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);

        // setter di
        ExampleBean exampleBean = (ExampleBean) xmlBeanFactory.getBean("exampleBean");
        System.out.println("exampleBean: " + exampleBean);
        ExampleBean exampleBean_ = (ExampleBean) xmlBeanFactory.getBean("exampleBean");
        System.out.println("exampleBean_: " + exampleBean_);
        System.out.println("exampleBean == exampleBean_ " + (exampleBean == exampleBean_));

        // constructor di
        ExampleBean exampleBean1 = (ExampleBean) xmlBeanFactory.getBean("exampleBean1");
        System.out.println("exampleBean1: " + exampleBean1);
        ExampleBean exampleBean1_ = (ExampleBean) xmlBeanFactory.getBean("exampleBean1");
        System.out.println("exampleBean1 == exampleBean1_ " + (exampleBean1 == exampleBean1_));

        // static factory method di
        ExampleBean exampleBean2 = (ExampleBean) xmlBeanFactory.getBean("exampleBean2");
        System.out.println("exampleBean2: " + exampleBean2);
        ExampleBean exampleBean3 = (ExampleBean) xmlBeanFactory.getBean("exampleBean3");
        System.out.println("exampleBean3: " + exampleBean3);
        System.out.println("exampleBean2 == exampleBean3 " + (exampleBean2 == exampleBean3));



        // instance factory method di 实例工厂方法
        ExampleBean exampleBean4 = (ExampleBean) xmlBeanFactory.getBean("exampleBean4");
        System.out.println("exampleBean4: " + exampleBean4);
    }
}

属性注入和构造器注入的优缺点

设值注入的优势
1. 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直
观,更加自然。
2. 如果依赖关系(或继承关系)较为复杂,那么Type3模式的构造函数也会相当庞大(我们需
要在构造函数中设定所有依赖关系),此时Type2模式往往更为简洁。
3. 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts
中的Action),此时Type3类型的依赖注入机制就体现出其局限性,难以完成我们期望的功
能。

构造子注入的优势:
1. “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,Type3无疑是最好的
响应者。
2. 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,
更加易读。
3. 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处于
相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系
产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
4. 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。
对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的
层次清晰性提供了保证。
5. 通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量
依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的
先决条件是组件的DataSource及相关资源已经被设定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值