Spring学习笔记(一):Spring IoC 容器

花时间写了一下Spring的相关笔记,终于写的差不多了,整理了一下传了上来。

完整章节传送门:
Spring学习笔记(一):Spring IoC 容器
Spring学习笔记(二):Spring Bean 装配
Spring学习笔记(三): Spring 面向切面
Spring学习笔记(四): Spring 数据库编程
Spring学习笔记(五): Spring 事务管理

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 的关系如下图。

Spring学习笔记(一):Spring IoC 容器_第1张图片
springbean-ioc.jpg

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



    4.0.0

    com.wyk
    springdemo
    1.0-SNAPSHOT

    
        4.3.18.RELEASE
    

    
        
            org.springframework
            spring-beans
            ${spring.version}
        
        
            org.springframework
            spring-context
            ${spring.version}
        
    

在项目中添加一个实体类 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 。



    
        
        
        
    

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

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 。

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步:

  • Resource定位。Spring IoC根据开发者的配置定位资源,包括通过XML或者注解等。
  • BeanDefination 的载入。将Resource定位到的信息,保存到 Bean 定义中。
  • BeanDefination 的注册。 将 BeanDefination 中的信息发布到 Spring IoC 容器中。

三步完成后, 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容器控制,包括从初始化到销毁整个过程。

Spring学习笔记(一):Spring IoC 容器_第2张图片
springbean-life.png

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

  • 如果 Bean 实现了接口 BeanNameAware 的 setBeanName 方法,那么它就会调用这个方法。
  • 如果 Bean 实现了接口 BeanFactoryAware 的 setBeanFactory 方法,那么他就会调用这个方法。
  • 如果 Bean 实现了接口 ApplicationContextAware 的 setApplicatonContext 方法,且 Spring IoC 容器也必须是一个 ApplicationContext 接口的实现类,那么才会调用这个方法,否则不会调用。
  • 如果 Bean 实现了接口 BeanPostProcessor 的 postProcessBeforeInitialization 方法,那么它就会调用这个方法。
  • 如果 Bean 实现了接口 BeanFactoryPostProcessor 的 afterPropertiesSet,那么它会调用这个方法。
  • 如果 Bean 自定义了初始化方法,它就会调用已定义的初始化方法。
  • 如果 Bean 实现了接口 BeanPostProcessor 的 postProcessAfterInitialization 方法,完成了这些调用, Bean就完成了初始化。

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

  • 如果 Bean 实现了接口 DisposableBean 的 destory 方法,那么就会调用它。
  • 如果定义了自定义的销毁方法,那么就会调用它。

需要注意的一点是,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 和实体的初始化和销毁方法。



    
    
    
        
        
        
    
    
        
        
    

修改主程序进行测试。

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

你可能感兴趣的:(Spring学习笔记(一):Spring IoC 容器)