Java

Spring IoC 容器

2019-02-11  本文已影响1人  简单一点点

IoC 是控制反转的意思,简单来说,就是创建对象的时候不是你主动创建,而是由 Spring 框架负责控制对象的生命周期和对象间的关系。

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件,这些对象被称为 Spring Beans。

Spring IoC 容器的设计

Spring IoC 容器的设计主要是基于 BeanFactory 和 ApplicationContext 两个接口,其中 ApplicationContext 是 BeanFactory 的子接口。在绝大部分工作场景下,我们都是使用 ApplicationContext 作为 Spring IoC 的容器。

被称作 Bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的,可以通过XML或者注解创建。

Spring IoC 和 Bean 的关系如下图。

springbean-ioc.jpg

下面通过一个例子来加深理解。新建一个 Maven 项目,在 pom.xml 中添加 Spring 依赖。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wyk</groupId>
    <artifactId>springdemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>4.3.18.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

在项目中添加一个实体类 Drinks 。

package com.wyk.springdemo.pojo;

public class Drinks {
    private String fruit; //水果类型
    private String sugar; // 糖分描述
    private Integer size; // 型号

    public String getFruit() {
        return fruit;
    }

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public String getSugar() {
        return sugar;
    }

    public void setSugar(String sugar) {
        this.sugar = sugar;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "一杯型号为" + this.size + this.sugar + this.fruit;
    }
}

在 src/main/resources 下面创建一个XML配置文件 spring-cfg.xml 。在文件中定义一个和上面实体类相关的 bean 。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <bean id="orangeJuice" class="com.wyk.springdemo.pojo.Drinks">
        <property name="fruit" value="橙汁" />
        <property name="sugar" value="少糖的" />
        <property name="size" value="2" />
    </bean>
</beans>

创建一个主应用程序类,调用前面的实体类。运行程序,可以打印出实体类。

package com.wyk.springdemo;

import com.wyk.springdemo.pojo.Drinks;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        // 初始化ApplicationContext 
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
        // 获取bean
        Drinks orange = (Drinks)ctx.getBean("orangeJuice");
        System.out.println(orange);
    }

}

多个 bean 之间可以相互引用。 新建实体类 JuiceMaker 。

package com.wyk.springdemo.pojo;

public class JuiceMaker {
    private String beverageShop;
    private Drinks source;

    public String getBeverageShop() {
        return beverageShop;
    }

    public void setBeverageShop(String beverageShop) {
        this.beverageShop = beverageShop;
    }

    public Drinks getSource() {
        return source;
    }

    public void setSource(Drinks source) {
        this.source = source;
    }

    public String makeJuice() {
        String juice = "这是一杯由" + beverageShop + "饮品店, 提供的型号为" + source.getSize()
                + source.getSugar() + source.getFruit();
        return juice;
    }
}

在 spring-cfg.xml 中,添加新实体类的 bean , 并引用原来的 bean 。

<bean id="juiceMaker" class="com.wyk.springdemo.pojo.JuiceMaker">
    <property name="beverageShop" value="pig" />
    <property name="source" ref="orangeJuice" />
</bean>

在主程序中获取 bean 。

public class MainApp {
    public static void main(String[] args) {
        // 初始化ApplicationContext
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");

        JuiceMaker maker = (JuiceMaker)ctx.getBean("juiceMaker");
        System.out.println(maker.makeJuice());
    }
}

运行程序,可以查看结果。

[图片上传失败...(image-75819c-1549887547771)]

Spring IoC 容器初始化

Spring IoC 容器初始化包括2个步骤,即 bean 的定义和依赖注入。bean 的定义分成3步:

三步完成后, Bean就在 Spring IoC 容器中被定义了,但并没有被初始化。 Bean 有一个配置选项 lazy-init 。其含义是是否初始化 Spring Bean 。默认值为 false ,即默认会自动化初始 Bean。 如果将其设置为 true ,那么只有会在获取的时候才会完成依赖注入。

Spring Bean

Bean 中可以包含如下属性。

属性 描述
class 这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
name 这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。
scope 这个属性指定由特定的 bean 定义创建的对象的作用域。
constructor-arg 用来注入依赖关系的。
properties 用来注入依赖关系的
autowiring mode 用来注入依赖关系的。
lazy-initialization mode 延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
initialization 方法 在 bean 的所有必需的属性被容器设置之后,调用回调方法。
destruction 方法 当包含该 bean 的容器被销毁时,使用回调方法。

Spring Bean 生命周期

Spring Bean 的生命周期由 Spring IoC容器控制,包括从初始化到销毁整个过程。

springbean-life.png

具体步骤比较复杂,首先介绍下初始化的步骤。

当服务器正常关闭,或其它事件关闭 Spring IoC 容器,它就会销毁 Bean。

需要注意的一点是,BeanPostProcessor 接口针对所有的 Bean, 而其他接口只针对单个的 Bean。

下面修改前面的项目,进行测试。

创建 BeanPostProcessor 的实现类。

package com.wyk.springdemo.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class BeanPostProcessorImpl implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean,  String beanName)
        throws BeansException {
        System.out.println("[" + bean.getClass().getSimpleName() + "]对象" + beanName
            + "开始实例化");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean,  String beanName)
            throws BeansException {
        System.out.println("[" + bean.getClass().getSimpleName() + "]对象" + beanName
                + "实例化完成");
        return bean;
    }
}

修改 JuiceMaker 实体类, 添加相关接口。

package com.wyk.springdemo.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class JuiceMaker implements BeanNameAware, BeanFactoryAware, ApplicationContextAware,
        InitializingBean, DisposableBean {
    private String beverageShop;
    private Drinks source;

    public String getBeverageShop() {
        return beverageShop;
    }

    public void setBeverageShop(String beverageShop) {
        this.beverageShop = beverageShop;
    }

    public Drinks getSource() {
        return source;
    }

    public void setSource(Drinks source) {
        this.source = source;
    }

    public void init() {
        System.out.println("[" + this.getClass().getSimpleName() + "]执行自定义初始化方法");
    }

    public void myDestroy() {
        System.out.println("[" + this.getClass().getSimpleName() + "]执行自定义销毁方法");
    }

    public String makeJuice() {
        String juice = "这是一杯由" + beverageShop + "饮品店, 提供的型号为" + source.getSize()
                + source.getSugar() + source.getFruit();
        return juice;
    }

    public void setBeanName(String arg0) {
        System.out.println("[" + this.getClass().getSimpleName()
            + "]调用BeanNameAware接口的setBeanName方法");
    }

    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out.println("[" + this.getClass().getSimpleName()
                + "]调用BeanFactoryAware接口的setBeanFactory方法");
    }

    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        System.out.println("[" + this.getClass().getSimpleName()
                + "]调用ApplicationContextAware接口的setApplicationContext方法");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("[" + this.getClass().getSimpleName()
                + "]调用InitializingBean接口的afterPropertiesSet方法");
    }

    public void destroy() {
        System.out.println("调用DisposableBean的destroy方法");
    }
}

修改 Bean 的配置文件 spring-cfg.xml, 添加 beanPostProcessor 和实体的初始化和销毁方法。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- BeanPostProcessor定义 -->
    <bean id="beanPostProcessor" class="com.wyk.springdemo.pojo.BeanPostProcessorImpl" />
    <bean id="orangeJuice" class="com.wyk.springdemo.pojo.Drinks">
        <property name="fruit" value="橙汁" />
        <property name="sugar" value="少糖的" />
        <property name="size" value="2" />
    </bean>
    <bean id="juiceMaker" class="com.wyk.springdemo.pojo.JuiceMaker"
        init-method="init" destroy-method="myDestroy">
        <property name="beverageShop" value="pig" />
        <property name="source" ref="orangeJuice" />
    </bean>
</beans>

修改主程序进行测试。

package com.wyk.springdemo;

import com.wyk.springdemo.pojo.JuiceMaker;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        // 改为ClassPathXmlApplicationContext,方便后面关闭
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");

        JuiceMaker maker = (JuiceMaker)ctx.getBean("juiceMaker");
        System.out.println(maker.makeJuice());
        //关闭
        ctx.close();
    }
}

运行程序,查看控制台的输出。

二月 06, 2019 11:01:51 上午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@156ce6a: startup date [Wed Feb 06 11:01:51 CST 2019]; root of context hierarchy
二月 06, 2019 11:01:51 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring-cfg.xml]
[Drinks]对象orangeJuice开始实例化
[Drinks]对象orangeJuice实例化完成
[JuiceMaker]调用BeanNameAware接口的setBeanName方法
[JuiceMaker]调用BeanFactoryAware接口的setBeanFactory方法
[JuiceMaker]调用ApplicationContextAware接口的setApplicationContext方法
[JuiceMaker]对象juiceMaker开始实例化
[JuiceMaker]调用InitializingBean接口的afterPropertiesSet方法
[JuiceMaker]执行自定义初始化方法
[JuiceMaker]对象juiceMaker实例化完成
这是一杯由pig饮品店, 提供的型号为2少糖的橙汁
二月 06, 2019 11:01:52 上午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@156ce6a: startup date [Wed Feb 06 11:01:51 CST 2019]; root of context hierarchy
调用DisposableBean的destroy方法
[JuiceMaker]执行自定义销毁方法

Process finished with exit code 0
上一篇下一篇

猜你喜欢

热点阅读