Spring之IOC核心模块详解

Posted czsy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之IOC核心模块详解相关的知识,希望对你有一定的参考价值。

Spring IOC简述

IOC称为控制反转,也有一种说法叫DI(依赖注入)。IOC也是spring最核心的模块,Spring的所有工作几乎都围绕着IOC展开。

什么是控制反转呢?简单的说,控制反转就是把我们要做的事情交给别人来做,就像是招了个小弟专门为我们做事情,我们需要做好的东西时直接去找小弟拿。

这里要做的事情就是new 一个对象。我们不再自己去new对象然后使用,而是spring容器帮我们去创建对象然后我们要用的时候直接去拿就行了。spring帮我们

生成对象就是控制反转,而我们要用对象从spring取对象就是依赖注入。

 

一切的开始要从spring容器的加载说起

我认为一切的开端要从spring 容器开始说起,所有工作都是围绕着Spring容器展开的。

这里只描述两种最常见的加载spring配置文件的方式,其余方式不做描述。

Spring容器是再spring配置文件被加载的一刻生成的。有两种常见加载方式,分别为使用BeanFactroy加载和使用AppilicationContext记载。

BeanFactory

BeanFactory加载spring配置文件又可以称为延迟加载,当BeanFactroy加载完配置文件后,bean并没有生成,而是当第一次使用bean的使用bean才创建。

Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Warehouse warehouse = beanFactory.getBean("warehouse",Warehouse.class);

ApplicationContext

而Applicationcontext加载方式是立即加载方式,BeanFactory有的功能它都有,而它有的功能BeanFactroy不一定有,所以是目前最主流的加载方式。

立即加载的意思就是当配置文件加载,spring容器创建的时候,我们配置好的bean就都创建了,这些bean与容器同生共死。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Warehouse warehouse = applicationContext.getBean("warehouse",Warehouse.class);

容器加载完后就得谈谈bean的创建了

bean有三种创建方式:

默认无参构造函数创建、静态工厂创建、实例工厂创建

默认无参创建方式

也是最常用的创建方式。我们定义一个实体类时默认有一个无参构造函数,可以不用创建。

//实体类
public
class User { private String name; private int age; //get set... }

//bean创建
<bean id="user" class="springIOCTest.User"/>

但是当我们定义的实体类有带参构造函数时就得显式的为其创建一个无参构造函数,否则bean创建失败

public class User {
    private String name;
    private int age;

    public User() {

    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // get set...
}

静态工厂创建bean

首先的先定义一个静态工厂类

public class StaticFactroy {
    private User user;
    public static User getUser() {
        return new User();
    }
}

在创建bean的时候类路径选择静态工厂类路径,指定factory-method

<bean id="user" class="springIOCTest.StaticFactroy" factory-method="getUser"/>

实例工厂创建bean

定义一个普通工厂类

public class InstanceFactory {
    private User user;
    public User getUser() {
        return new User();
    }
}

在创建bean的时候先创建工厂bean,再根据工厂bean创建我们需要的bean

<bean id="instanceFactroy" class="springIOCTest.InstanceFactory"/>
<bean id="user" factory-bean="instanceFactroy" factory-method="getUser"/>

虽然我们知道了如何创建一个bean,但是我们每个bean里面可能有很多属性,需要我们去注入。

接下来谈谈bean的注入方式

每当我们new一个对象的时候,经常需要给它里面的属性设值或者传递引用,spring也可以帮我们完成这项工作

比如我们要为上面的User类的name属性和age属性注入值。那么有两种方式注入:属性注入和构造函数注入

首先做下准备工作,为User类加个实体属性:

public class User {
    private String name;
    private int age;
    private UserSon mySon;
    // get set...
}

属性注入

属性注入就是我们平常new 一个对象后setxxx

<bean id="mySon" class="springIOCTest.UserSon"/>
<bean id="user" class="springIOCTest.User">
   <property name="name" value="张三"/>
   <property name="age" value="18"/>
   <property name="mySon" ref="mySon"/>
</bean>

可以看到属性中包含实体类的时候必须先创建一个该类的bean,然后通过ref的方式注入

 构造函数注入

public class User {
    private String name;
    private int age;
    private UserSon mySon;
    public User(String name, int age, UserSon mySon) {
        this.name = name;
        this.age = age;
        this.mySon = mySon;
    }
    // get set...
}
<bean id="mySon" class="springIOCTest.UserSon"/>
    <bean id="user" class="springIOCTest.User">
    <constructor-arg index="0" name="name" value="张三"/>
    <constructor-arg index="1" name="age" value="18"/>
    <constructor-arg index="2" name="mySon" ref="mySon"/>
</bean>

构造函数注入的前提时提供对应的构造函数,但是使用构造函数容易产生一个问题,那就是循环依赖问题

循环依赖问题

当使用构造函数注入的时候可能会出现一下一种情况

public class UserSon {
    private User father;

    public UserSon(User father) {
        this.father = father;
    }
    //get set..
}

User实体类需要注入UserSon实例,而UserSon实体类也需要注入User实例,那么在生成bean的时候会出现以下情况

<bean id="mySon" class="springIOCTest.UserSon">
    <constructor-arg index="0" name="father" ref="user"/>
</bean>
<bean id="user" class="springIOCTest.User">
   <constructor-arg index="0" name="name" value="张三"/>
   <constructor-arg index="1" name="age" value="18"/>
   <constructor-arg index="2" name="mySon" ref="mySon"/>
</bean>

这样就形成了死胡同,类时死锁,这时候就会报错。

解决办法很简单,改为属性注入方式即可。

因此,使用构造函数注入的时候可能会产生问题,又比较麻烦,所以实际场景中使用属性注入是比较常见的

 

到这里我们就讲完了如何完整的创建一个bean了,接下来就来谈谈bean的生命周期吧

bean的生命周期

未完待续。。。

以上是关于Spring之IOC核心模块详解的主要内容,如果未能解决你的问题,请参考以下文章

Spring图解核心,AOP切面编程,异步操作详解

30个类手写Spring核心原理之Ioc顶层架构设计

spring之ioc详解

Java开发Spring之IOC详解第一篇(xml开发常用APIben标签DI依赖注入)

《一头扎进Spring4》学习笔记Spring ioc 之详解

Spring之IOC原理及代码详解