zoukankan      html  css  js  c++  java
  • Spring IOC

    前言

    Spring框架为什么如此流行?

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

    Spring 核心组件

    Bean

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

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

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

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

    Context

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

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

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

    Core

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

    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());
        }
    }  

    运行结果:

    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的时序图:

     继续看一看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技术内幕》

  • 相关阅读:
    java中CyclicBarrier的使用
    java并发中CountDownLatch的使用
    java中Locks的使用
    java 中的fork join框架
    java中ThreadPool的介绍和使用
    java中的daemon thread
    java中interrupt,interrupted和isInterrupted的区别
    java中的Atomic类
    怎么在java中关闭一个thread
    java中join的使用
  • 原文地址:https://www.cnblogs.com/Hangtutu/p/9391330.html
Copyright © 2011-2022 走看看