欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring IOC

程序员文章站 2022-10-16 14:16:50
前言 Spring框架为什么如此流行? 原来Spring框架解决了一个很关键的问题,它可以把对象之间的依赖关系转为用配置文件来管理,也就是它的依赖注入机制。IOC容器用来管理这些Bean,管理Bean的关系以及生命周期,然而这与之前将应用程序主动new对象不同,Spring实现使用IOC容器创建对象 ......

前言

Spring框架为什么如此流行?

原来Spring框架解决了一个很关键的问题,它可以把对象之间的依赖关系转为用配置文件来管理,也就是它的依赖注入机制。IOC容器用来管理这些Bean,管理Bean的关系以及生命周期,然而这与之前将应用程序主动new对象不同,Spring实现使用IOC容器创建对象,对象的获取方式反转了,所以IOC容器也称为控制反转。面对繁琐的依赖关系,我们不用一个一个去new对象,直接使用IOC创建好的对象,这也正是IOC的方便之处。

Spring 核心组件:Bean Context,Core

Bean

Bean组件在org.springframework.beans包下,这个包下所有的类解决了Bean的定义,创建以及解析。

1.Bean的定义:主要有BeanDefinition描述,也可以说Spring中的Bean就是BeanDefinition的实例。Spring成功解析一个<bean/>节点后,在Spring的内部它就被转化为BeanDefinition对象。

Spring IOC

 

2.Bean的创建:.Spring Bean的创建是典型的工厂设计模式,*接口是BeanFactory

Spring IOC

3.Bean的解析:Bean的解析主要是对配置文件的解析

Spring IOC

Context

context组件在org.framework.context包下,主要就是Bean关系的集合。给Spring提供了一个运行时环境用于存储对象的状态。ApplicationContext是*的父类

Spring IOC

ApplicationContext继承了BeanFactory说明了Spring容器运行的主要对象是Bean

ApplicationContext实现了ResourceLoader接口说明ApplicationContext可以访问到外部资源。

Core

core组件就是发现,建立和维护每个Bean之间关系所需要的一系列工具。core组件其中一个重要的组成部分就是定义了资源的访问方式。

Spring IOC

 

 

IOC的工作原理

下面我们看看IOC是怎样工作的呢?

先来一个小demo

MessageService.java

public interface MessageService {
    String getMessage();
}

MessageServiceImpl.java

public class MessageServiceImpl implements MessageService {
    public String getMessage() {
        return "hello world";
    }
}  

application.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
    <bean id="messageService" class="com.kristin.spring.ioc.MessageServiceImpl"/>
</beans>  

TestMessage.java

public class TestMessage {
    public static void main(String[] args) {
        // 用我们的配置文件来启动一个 ApplicationContext
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

        System.out.println("context 启动成功");

        // 从 context 中取出我们的 Bean,而不是用 new MessageServiceImpl() 这种方式
        MessageService messageService = context.getBean(MessageService.class);
        // 这句将输出: hello world
        System.out.println(messageService.getMessage());
    }
}  

运行结果:

Spring IOC

IOC运行分析  

从上面代码可以发现,IOC的入口就是ClassPathXmlApplicationContext的构造方法,下面我们看看源码是怎样写的

ClassPathXmlApplicationContext.java

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
        throws BeansException {

    super(parent);
    setConfigLocations(configLocations);    //根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
    if (refresh) {
        refresh();  //这里是核心代码
    }
}  

下面我们看一下refresh()

ClassPathXmlApplicationContext.java

@Override
public void refresh() throws BeansException, IllegalStateException {
    //这里加锁,防止多个线程同时refresh()时出现问题
    synchronized (this.startupShutdownMonitor) {
        // 为刷新准备新的context,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
        prepareRefresh();

        // 刷新所有BeanFactory的子容器
        // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
        // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
        // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 准备BeanFactory,设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
        prepareBeanFactory(beanFactory);

        try {
            // 这里是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化
            // 具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类或做点什么事
            postProcessBeanFactory(beanFactory);

            // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
            // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
            // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
            registerBeanPostProcessors(beanFactory);

            // 初始化message source
            initMessageSource();

            // 初始化 event multicaster
            initApplicationEventMulticaster();

            // 刷新由子类实现的方法
            onRefresh();

            // 注册事件监听器,监听器需要实现 ApplicationListener 接口。
            registerListeners();

            // 初始化所有的 singleton beans
            finishBeanFactoryInitialization(beanFactory);

            // 最后,广播事件,ApplicationContext 初始化完成
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}  

refresh函数主要包含了以下几个步骤:

1.构建BeanFactory,以便于产生所需的"演员"

2.注册可能感兴趣的事件

3.创建Bean实例对象

4.触发被监听的事件

 

创建BeanFactory的时序图:

Spring IOC

 继续看一看refresh()函数中调用的函数吧

AbstractApplicationContext.java

protected void prepareRefresh() {
    // 记录启动时间,将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);

    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    // Initialize any placeholder property sources in the context environment
    initPropertySources();

    // 校验 xml 配置文件
    getEnvironment().validateRequiredProperties();

    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

AbstractApplicationContext.java

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
    refreshBeanFactory();
    // 返回刚刚创建的 BeanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

AbstractRefreshableApplicationContext.java

@Override
protected final void refreshBeanFactory() throws BeansException {
    // 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
    // 注意,应用中BeanFactory本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前ApplicationContext是否有BeanFactory
    if (hasBeanFactory()) {
        destroyBeans();
        closeBeanFactory();
    }
    try {
        // 初始化一个 DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 用于 BeanFactory 的序列化
        beanFactory.setSerializationId(getId());
        // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
        customizeBeanFactory(beanFactory);
        // 加载 Bean 到 BeanFactory 中,这个方法很重要
        loadBeanDefinitions(beanFactory);   
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

此时已经获得了BeanFactory

后面会陆续更新,暂时先整理到这里...

 

 

对了,以上文章整理自

https://javadoop.com/post/spring-ioc

《深入分析Java Web技术内幕》

感谢两位大神的文章及书籍