我对控制反转以及依赖注入的认识

简介: IOC诞生的历史 在没有IoC时,关联不同模块是通过类实例实现的,代码可能是这样子的: // 代码清单1 public interface YourService { void func1(); void func2(); } // 代码清单2 public class.

IoC诞生的历史

在没有IoC时,关联不同模块是通过类实例实现的,代码可能是这样子的:

// 代码清单1
public interface YourService {
    void func1();
    
    void func2();
}

// 代码清单2
public class MyServiceImpl {
    private YourServiceImpl yourServiceImpl;
    
    public MyServiceImpl() {
        this.yourServiceImpl = new YourServiceImpl();
    }
    
    public void process() {
        // do something
        this.yourServiceImpl.func1(...);
        // do something
        this.yourServiceImpl.func2(...);
    }
}
// 代码清单3
public class MyServiceImpl {
    private YourService yourService;
    
    public MyServiceImpl(YourService yourService) {
        this.yourService = yourService;
    }
    
    public void process() {
        // do something
        this.yourService.func1(...);
        // do something
        this.yourService.func2(...);
    }
}

当YourServiceImpl的接口不变时,只需要根据业务需要更换不同的YourService实现类即可。一旦更换实现类时(如将yourServiceImpl更换为NewServiceImpl),MyServiceImpl中所有引用YourService的代码都要替换为NewServiceImpl,这严重违背了面向对象设计中DIP(Dependence Inversion Principle)原则。

* 上层业务应该依赖抽象,抽象定义了"要做什么",而不应依赖实现细节"怎么做"。
* 模块间通过接口建立依赖关系
* 实现类依赖接口或抽象类

IOC实现的原理

IoC: Inversion of Control(依赖反转), 是针对之前模块间通过实现类建立关联而言,反转指"模块实现依赖实现类"->"模块实现依赖(实现类的)接口"。

执行IoC原则后,模块内原本生成实例的语句被替换成接口调用(代码清单3)。我们知道JVM是在运行时才申请内存并生成类实例对象的,运行时系统怎么知晓具体接口对应的实现是什么呢?

这时候就轮到反射和DI登场了。DI(Dependency injection)依赖注入,在运行时根据spring的xml配置文件(有实现类的全路径名称)选择适当的时机构造依赖对象实例并注入到依赖实现类接口的模块中。而如何完成依赖实例对象的构造以及初始化是Spring DI的核心。

// 代码清单4
    <bean id="userDAO" class="dao.impl.UserDAOImpl">
        <property name="sellerDAO" ref="sellerDAO" />
    </bean>
    
    <bean id="sellerDAO" class="dao.impl.SellerDAOImpl" />

代码清单4中演示了spring的bean配置代码。Spring解析bean的xml文件,拿到bean的类全路径名称后调用Class.forName(String className)方法从对应的类加载器中获取类信息,并调用Class.newInstance()方法生成类实例。

此时类实例并未完成初始化,还需要注入类实例的依赖项。Spring解析bean下的property条目,以property name为优先查找实例类的set方法并匹配入参,如果有则调set方法注入property。此时给模块返回完整的依赖对象。

注入方法

set方法注入

该方式要求被注入的属性在实现类里有set方法。set注入支持简单类型和引用类型。

构造函数注入

// 代码清单5
/**
 * Created by fujianbo on 2018/6/17.
 *
 * @author fujianbo
 * @date 2018/06/17
 */
public class UserDAOImpl implements UserDAO {
    private SellerDAO sellerDAO;
    
    public void setSellerDAO(SellerDAO sellerDAO) {
        this.sellerDAO = sellerDAO;
    }
    
    public UserDAOImpl() {
    }
    
    public UserDAOImpl(SellerDAO sellerDAO) {
        this.sellerDAO = sellerDAO;
    }
}

// 代码清单6
<bean id="sellerDAO" class="dao.impl.SellerDAOImpl" />
<bean id="userDAO" class="dao.impl.UserDAOImpl">
    <constructor-arg ref="sellerDAO"/>
</bean>

当有多个constructor-arg时,Spring根据传入的依赖参数找到对应的构造函数而并不关心书写顺序。但如果构造函数只是入参顺序不同,定义constructor-arg时需要加index参数,否则Spring创建类实例失败。

// 代码清单7
public class User {
    private String userName;
    private Integer age;

    public User(int age, String userName) {
        this.age = age;
        this.userName = userName;
    }

    public User(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

...
// yourConfig.xml
<bean id="user" class="..." >
    <constructor-arg index="0" value="Jack"/>
    <constructor-arg index="1" value="26"/>
</bean>

IoC & DI

以下个人对于这两个兄弟的理解,如有谬误还请指正!

IoC

1、IoC(控制反转)是模块间拜托对类实例依赖的桥梁,它统一管理了类实例对象的创建、初始化、注入以及销毁过程。

2、模块间依赖实现类的接口,从调用者角度来看,多数情况无需关注细节以及感知实现细节的变化,只需关注接口入参和返回值,将OOP上升到面向接口、面向切面编程的层次,是工厂模式的升华(参考引用2)。每个模块相当于一个垂直业务,IoC抽象了模块内部创建类实例的代码,依托反射和DI,给出了类实例类型识别解析、初始化、对象管理(spring容器)的解决方案。

3、当模块间不再显示创建类实例总得有人接下这项"苦差事"吧,这人就是Spring。Spring通过bean配置文件或者@Autowired, @Component, @Resource(J2EE提供), @Service, @Repository等注解,结合java反射原理生成类实例对象并给模块间的接口赋值。

DI

Spring提供的传递模块间依赖的接口的实例的方法,是IoC解决方案的一部分。

引用

目录
相关文章
|
6月前
|
XML Java 数据格式
依赖注入~
依赖注入~
|
7月前
|
XML 开发框架 Java
Spring框架IoC控制反转
Spring是与2003年兴起的一个轻量级的Java开发框架,它是为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IOC)和面向切面编程(AOP)。Spring是可以在Java SE/EE中使用的轻量级开源框架。 Spring的主要作用就是为代码"解耦",降低代码间的耦合度。就是让对象和对象(模板和模板)之间关系不是使用代码关联,而是通过配置来说明。即在Spring中说明对象(模块)的关系。 Spring根据代码的功能特点,使用IOC降低业务对象之间耦合度。IOC使得主业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了,而是由Spring容器统一
52 2
|
11月前
|
设计模式 Java Spring
|
12月前
|
Java Maven
SpringFrame-ioc 依赖注入
SpringFrame-ioc 依赖注入
|
SQL 开发框架 安全
3.1依赖注入
传统开发中,对象都是开发者创建组装,开发者必须了解各类的使用方法且某些类的耦合度较高,例如想把sql serve数据库改为MySql数据库则需要更改某些代码。控制反转的目的是让框架完成对象的创建和组装。从“我创建对象”编程“我要对象”
|
JavaScript uml 容器
Ioc——控制反转
Ioc——控制反转
168 0
Ioc——控制反转
|
程序员 容器
控制反转与依赖注入
控制反转与依赖注入
102 0
控制反转与依赖注入
|
Java 程序员 数据库
依赖注入IOC
依赖注入IOC
|
自动驾驶 小程序 Java
什么是控制反转(IOC)?什么是依赖注入?
什么是控制反转(IOC)?什么是依赖注入?
什么是控制反转(IOC)?什么是依赖注入?
|
XML 架构师 关系型数据库