依赖注入的方式(DI)
阅读原文时间:2023年07月13日阅读:1

方式:

  1. 接口注入;
  2. setter方法注入;
  3. 构造方法注入;
接口注入:

public class ClassA {

private InterfaceB clzB;

public void doSomething() {

Ojbect obj = Class.forName(Config.BImplementation).newInstance(); 

clzB = (InterfaceB)obj; 

clzB.doIt();  

}

……

}

解释一下上述的代码部分,ClassA依赖于InterfaceB的实现,我们如何获得InterfaceB的实现实例呢?传统的方法是在代码中创建 InterfaceB实现类的实例,并将赋予clzB.这样一来,ClassA在编译期即依赖于InterfaceB的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码。我们根据预先在配置文件中设定的实现类的类名(Config.BImplementation),动态加载实现类,并通过InterfaceB强制转型后为ClassA所用,这就是接口注入的一个最原始的雏形。

setter注入:

setter注入模式在实际开发中有非常广泛的应用,setter方法更加直观,我们来看一下spring的配置文件:

<!-- 使用spring管理对象的创建,还有对象的依赖关系 -->   

<bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/>   

<bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/>   

<bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl">   

    <!-- (1)userManager使用了userDao,Ioc是自动创建相应的UserDao实现,都是由容器管理-->   

    <!-- (2)在UserManager中提供构造函数,让spring将UserDao实现注入(DI)过来 -->   

    <!-- (3)让spring管理我们对象的创建和依赖关系,必须将依赖关系配置到spring的核心配置文件中 -->   

    <property name="userDao" ref="userDao4Oracle"></property> 

    <property name="id" value="123"></property>   

</bean>   

接着我们来看一下,setter表示依赖关系的写法:

public class UserManagerImpl implements UserManager{

private UserDao userDao;

private int id;

//使用设值方式赋值   

public void setUserDao(UserDao userDao) {   

    this.userDao = userDao;   

}

//使用设值方式赋值   

public void setId(int id) {   

    this.userDao = id;   

}   

@Override   

public void addUser(String userName, String password) {   

    userDao.addUser(userName, password);   

}   

}

构造器注入:

构造器注入,即通过构造函数完成依赖关系的设定。我们看一下spring的配置文件:

    <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/>   

    <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/>   

    <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl">   

        <!-- (1)userManager使用了userDao,Ioc是自动创建相应的UserDao实现,都是由容器管理-->   

        <!-- (2)在UserManager中提供构造函数,让spring将UserDao实现注入(DI)过来 -->   

        <!-- (3)让spring管理我们对象的创建和依赖关系,必须将依赖关系配置到spring的核心配置文件中 -->   

        <constructor-arg ref="userDao4Oracle"/>   

    </bean>

我们再来看一下,构造器表示依赖关系的写法,代码如下所示:

public class UserManagerImpl implements UserManager{

    private UserDao userDao;   

    //使用构造方式赋值   

    public UserManagerImpl(UserDao userDao) {   

        this.userDao = userDao;   

    }   

    @Override   

    public void addUser(String userName, String password) {   

        userDao.addUser(userName, password);   

    }   

} 
接口注入<>setter注入<>构造器注入   比较

接口注入:

接口注入模式因为具备侵入性,它要求组件必须与特定的接口相关联,因此并不被看好,实际使用有限

Setter 注入:

对于习惯了传统 javabean 开发的程序员,通过 setter 方法设定依赖关系更加直观。如果依赖关系较为复杂,那么构造子注入模式的构造函数也会相当庞大,而此时设值注入模式则更为简洁。如果用到了第三方类库,可能要求我们的组件提供一个默认的构造函数,此时构造子注入模式也不适用。

构造器注入:

在构造期间完成一个完整的、合法的对象。所有依赖关系在构造函数中集中呈现。依赖关系在构造时由容器一次性设定,组件被创建之后一直处于相对“不变”的稳定状态。只有组件的创建者关心其内部依赖关系,对调用者而言,该依赖关系处于“黑盒”之中。