Spring IOC(控制反转)的三种依赖注入方式

1)、什么是依赖注入(DI)和控制反转(IOC)

依赖注入和控制反转是对同一件事情的不同描述,从某个方面来讲,就是他们描述的角度不同。

依赖注入是从应用程序的角度在描述,应用程序依赖容器创建并注入它所需要的外部资源;

控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

当某个角色(一个java实例,调用者)需要另外一个角色(另外一个java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者,实例的工作通常由Spring容器来完成,然后注入调用者,英雌也成为依赖注入。

spring IOC的三种依赖注入方式

a)接口注入

b)setter方法注入

c)构造方法注入

接口注入

public class ClassA {  
  private InterfaceB clzB;  
  public void doSomething() {  
    Ojbect obj = Class.forName(Config.BImplementation).newInstance();  
    clzB = (InterfaceB)obj;  
    clzB.doIt();   
  }  
……  
}

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

setter方法注入

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

<?xml version="1.0" encoding="UTF-8"?>    
<beans xmlns="http://www.springframework.org/schema/beans"    
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
         xmlns:aop="http://www.springframework.org/schema/aop"    
         xmlns:tx="http://www.springframework.org/schema/tx"    
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd    
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd    
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">    
    
    <!-- 使用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>    
    </bean>    
        
</beans>  

setter表示依赖关系的写法

import com.tgb.spring.dao.UserDao;    
    
public class UserManagerImpl implements UserManager{    
    
    private UserDao userDao;    
    
    //使用设值方式赋值    
    public void setUserDao(UserDao userDao) {    
        this.userDao = userDao;    
    }    
        
    @Override    
    public void addUser(String userName, String password) {    
    
        userDao.addUser(userName, password);    
    }    
}  

构造器注入,即通过构造函数完成依赖关系的设定。Spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>    
    <beans xmlns="http://www.springframework.org/schema/beans"    
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
             xmlns:aop="http://www.springframework.org/schema/aop"    
             xmlns:tx="http://www.springframework.org/schema/tx"    
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd    
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd    
               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">    
        
        <!-- 使用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>    
            
    </beans>

构造器表示依赖关系的写法

import com.tgb.spring.dao.UserDao;    
        
    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方法注入:通过setter方法设定依赖关系更加直观。如果依赖关系较为复杂,那么构造自注入模式的构造函数也会相当庞大,而此时设置注入模式则更为简洁。如果用到了第三方类库,可能要求我们的组件提供一个默认的构造函数,此时构造子注入也相当不适用。

a)、设置注入需要该bean包含这些树形的set方法

b)、与传统的javaBean的写法更加相似,程序开发人员更加容易理解,接收。通过stter方法设定依赖关系显得更加明显

c)、对复杂的依赖关系,如果采用构造注入,会导致构造器臃肿,难以阅读。Spring在创建Bean实例时,需要同时实例化构造器依赖的全部实例,因而导致性能下降,而使用setter注入,则能避免这些问题。

d)、尤其是在某些属性可选的情况下,多参数的构造器显得更加笨重

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

a)、构造器注入需要该Bean包含带有这些属性的构造器

b)、构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。例如,组件中其他依赖关系的注入,常常要依赖于DataSource的注入。采用构造注入,可以在代码中清晰的决定注入顺序。

c)、对于依赖关系无需变化的Bean构造注入更加由用处,因为没有setter方法,所有的依赖关系全部在构造器内设定。无需担心后续代码对依赖关系产生破坏。

d)、依赖关系只有在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更加符合高内聚的元素。












猜你喜欢

转载自blog.csdn.net/qq_35504206/article/details/80935821