Spring IOC

欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot

前言

IOC 全称为 Inversion of Control(控制反转),通过反射技术,将 Bean 注入 IOC容器,由 Spring IOC 容器来负责管理对象的生命周期和对象之间的依赖关系

依赖注入(DI),就是由 IOC容器 在运行期间,动态地将某种依赖关系注入到对象之中

依赖注入(DI)和控制反转(IOC)是从不同的角度的描述同一件事情:通过将 Bean 引入 IOC容器,利用依赖关系注入的方式,实现对象之间的解耦

IOC 是把以前工厂方法里写死的对象生成代码,改变为由配置文件来定义,把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性

主要依赖源码是 spring-beans 和 spring-context 两个包

ContextLoaderListener

Spring 初始化的入口在 ContextLoaderListener。Spring 为我们提供的 IOC容器,需要指定容器的配置文件,然后由该监听器初始化并创建该容器。

Spring 通常可以在 web.xml 配置:

    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>/WEB-INF/applicationContext.xml</param-value>  
    </context-param> 

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

ContextLoaderListener 本质上是创建了一个 WebApplicationContext,自动装载 ApplicationContext 的配置信息。
ContextLoaderListener 是实现了 javax.servlet.ServletContextListener 接口的服务器端程序,
随 web 应用的启动而启动,只初始化一次,随 web 应用的停止而销毁。

Spring IOC 容器先根据监听初始化 WebApplicationContext,然后再初始化 web.xml 中其他配置的 servlet,
并加载其设置的配置信息和参数信息到上下文中(初始化上下文信息 servletContext),
然后将 WebApplicationContext 设置为 servletContext 的父容器。

依赖注入三种方法

构造器注入:

    index 是索引,指定注入的属性,从0开始
    type 是指该属性所对应的类型
    ref 是指引用的依赖对象
    value 当注入的不是依赖对象,而是基本数据类型时,就用value

    被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。

    YoungMan(BeautifulGirl beautifulGirl){
        this.beautifulGirl = beautifulGirl;
    }

    xml方式:

        <!-- 注册A -->
        <bean id="a" class="spring.A">
            <constructor-arg ref="b"></constructor-arg>

            <constructor-arg index="0">  
                <list>  
                    <ref bean="user1"/>  
                    <ref bean="user2"/>  
                    <value>张三</value>
                </list>  
            </constructor-arg>
        </bean>

        <!-- 注册B -->
        <bean id="b" class="spring.B"></bean>

    构造器注入方式比较直观,对象构造完毕后就可以直接使用。

    解决循环依赖问题:一个构造器注入,一个setter注入。


setter 方法注入:

    对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。
    通过set方法注入属性,那么Spring会通过默认的无参构造方法来实例化对象,
    所以如果在类中重写带有参数的构造方法,一定要把无参构造方法也写上,否则spring没有办法实例化对象,导致报错。

    public class YoungMan {
        private BeautifulGirl beautifulGirl;
        public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
            this.beautifulGirl = beautifulGirl;
        }
    }

    <!-- 注册A -->
    <bean id="a" class="spring.A">
        <!-- 写法一 -->
        <!-- <property name="UserName" ref="b"></property> -->
        <!-- 写法二 -->
        <property name="userName" ref="b"></property>

        <property name="cars">
            <list>
                <ref bean="car1"/>
            </list>
        </property>
    </bean>

    <!-- 注册B -->
    <bean id="b" class="spring.B"></bean>


基于注解的注入:

    bean的属性autowire,autowire主要有三个属性值:byName,byType。

        byName:
            被注入bean的id<名称>必须与set方法后半截匹配,并且id名称的第一个单词的首字母必须小写。

        byType:
            查找所有的set方法,将符合参数<类型>的bean注入。

    注册bean的注解有以下几种:

        @Component:用于注册所有的bean
        @Repository:用于注册dao层的bean
        @Controller:用于注册控制层的bean
        @Service:用于注册服务层的bean

    @Resource和@Autowired之间的区别

        @Resource(name="userDao"):
            java的注解,如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
            如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
            如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
            如果既没有指定name,又没有指定type,则自动按照byName方式进行装配,
            如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配

        @Autowired:
            spring注解,默认是以byType的方式去匹配类型相同的bean,
            如果匹配到一个,那么就直接注入该bean,
            如果byType查找到多个的话,使用@Qualifier("userDao")注解指定某个具体名称的bean,
            没有找到的话就抛出异常。
            依赖对象必须存在,如果允许null值,可以设置它的required属性为false(@Autowired(required=false))

启动 Spring 容器

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

FileSystemXmlApplicationContext:
    构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样。

AnnotationConfigApplicationContext:
    基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置。

ClassPathXmlApplicationContext 源码分析

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {

    //如果已经有 ApplicationContext,并需要配置成父子关系
    public ClassPathXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }

    public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        Assert.notNull(paths, "Path array must not be null");
        Assert.notNull(clazz, "Class argument must not be null");
        this.configResources = new Resource[paths.length];
        for(int i = 0; i < paths.length; ++i) {
            this.configResources[i] = new ClassPathResource(paths[i], clazz);
        }

        this.refresh();    //核心方法
    }
}

refresh() 初始化 Bean容器

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    /**
     * 初始化 Bean容器
     */
    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {

            //准备工作,准备新的上下文环境、记录下容器的启动时间、标记“已启动”状态、执行一些属性的初始化。
            this.prepareRefresh();

            /**
             * 创建 BeanFactory:DefaultListableBeanFactory
             * 读取 Spring 配置文件,验证配置文件的内容,并封装成 Resource,根据 Resource 加载 XML 配置文件,并解析成 Document 对象
             * 拿到 Document 中的根节点,遍历根节点和所有子节点。根据命名空间,进行不同的解析,将 bean 节点内容解析成 BeanDefinition
             * 加载到 BeanFactory 中(将 BeanDefinition 注册到注册表中(也就是beanDefinitionNames、beanDefinitionMap、aliasMap缓存))
             */

            /**
             * "加载到 BeanFactory 中"的内容主要指的是添加到以下3个缓存:
             *     beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合
             *     beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射
             *     aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。
             */
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

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

            try {
                this.postProcessBeanFactory(beanFactory);

                //BeanFactoryPostProcessor 是针对 BeanFactory 的扩展,主要用在 bean 实例化之前,读取 bean 的定义,并可以修改它。
                this.invokeBeanFactoryPostProcessors(beanFactory);

                //BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,允许开发者对 bean 实例进行修改。
                this.registerBeanPostProcessors(beanFactory);

                //初始化当前 ApplicationContext 的 MessageSource,用于国际化
                this.initMessageSource();

                /**
                 * 初始化当前 ApplicationContext 的事件广播器(ApplicationEvent),使用了一个标准的观察者模式:
                 *     对于applicationEventMulticaster内部的监听者applicationListeners,每次事件到来都会一一获取通知。
                 *     如果系统有需要广播的情况下,会发送一个 applicationEvent 事件,
                 *     注册的listener会根据自己关心的类型进行接收和解析。
                 */
                this.initApplicationEventMulticaster();

                //模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空(在实例化 singleton beans 之前)
                this.onRefresh();

                //注册监听器,与广播器是同时存在的。Spring初始化广播器,但是并没有为广播器绑定Listener。Spring在此方法中进行了绑定。
                this.registerListeners();

                //实例化所有的 singleton beans(lazy-init(懒加载)除外)
                this.finishBeanFactoryInitialization(beanFactory);

                //广播事件,表示 ApplicationContext 初始化完成
                this.finishRefresh();

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

                //销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源。
                this.destroyBeans();

                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }
        }
    }


    /**
     * 创建 Bean容器(Bean 并没有实例化)
     */
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

        this.refreshBeanFactory();    //关闭旧的 BeanFactory,创建新的 BeanFactory

        return this.getBeanFactory();    //返回刚刚创建的 BeanFactory
    }

    protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {

            this.destroyBeans();    //如果 ApplicationContext 中已经加载过 BeanFactory,销毁所有 Bean
            this.closeBeanFactory();    //关闭 BeanFactory
        }

        try {
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();    //创建并初始化BeanFactory实现类的实例

            beanFactory.setSerializationId(this.getId());    //序列化

            this.customizeBeanFactory(beanFactory);    //设置 BeanFactory 的两个配置属性:是否允许 BeanDefinition 覆盖、是否允许循环引用

            //BeanDefinition 中保存了 Bean 信息
            //比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean
            //初始化 Bean容器(配置文件的配置信息转换为一个个 BeanDefinition,然后注册各个 BeanDefinition 到 BeanFactory)
            this.loadBeanDefinitions(beanFactory);

            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }
}

详细过程

1. prepareRefresh  准备刷新容器

  (1) initPropertySources()  自定义属性设置,空方法,留给子类继承

  (2) this.getEnvironment().validateRequiredProperties()  首先获取环境配置,然后校验必需属性

  (3) this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners)  初始化事件监听器

  (4) this.earlyApplicationEvents = new LinkedHashSet()  初始化早期事件

2. obtainFreshBeanFactory  获取Bean工厂

  (1) this.refreshBeanFactory()  新建一个Bean工厂,类型为DefaultListableBeanFactory

  (2) this.getBeanFactory()  返回刚刚创建的Bean工厂

3. prepareBeanFactory  对Bean工厂做各种预处理设置

  (1) 在Bean工厂中设置类加载器、属性解析器等

  (2) 在Bean工厂中添加部分Bean后置处理器,例如ApplicationContextAwareProcessor、ApplicationListenerDetector

  (3) 在Bean工厂中设置忽略自动注入的接口

  (4) 设置自动装配规则

  (5) 在Bean工厂中注册一些Bean组件,例如环境配置ConfigurableEnvironment

4. postProcessBeanFactory  Bean工厂的后置处理工作

5. invokeBeanFactoryPostProcessors  执行Bean工厂后置处理器

  这一步是在Bean工厂的标准初始化(1-4)之后进行的,主要是执行BeanFactoryPostProcessor及其子接口的

  BeanFactoryPostProcessor的子接口主要是指BeanDefinitionRegistryPostProcessor:可以向容器中注册自定义的BeanDefinition

  (1) 从容器器中获取BeanDefinitionRegistryPostProcessor类型的Bean组件

  (2) 将BeanDefinitionRegistryPostProcessor类型的Bean组件按照顺序分类并排序,即是否实现了PriorityOrdered、Ordered接口

  (3) 依次执行实现了PriorityOrdered接口的、实现了Ordered接口的、
        没有实现任何顺序接口的Bean组件的postProcessBeanDefinitionRegistry(registry)方法

  (4) 执行所有BeanDefinitionRegistryPostProcessorBean的postProcessBeanFactory(beanFactory)方法

  (5) 从容器中获取其他的BeanFactoryPostProcessor类型的Bean组件,即不是BeanDefinitionRegistryPostProcessor类型的

  (6) 剩下的步骤跟上面类似,就是先按照实现的顺序接口分类,在每个类别下排序,然后依次执行它们的postProcessBeanFactory(beanFactory)方法

6. registerBeanPostProcessors  注册Bean后置处理器,这种处理器用于拦截bean的创建过程

      BeanPostProcessor有很多子接口,每种子接口的执行时机各有不同

      |-DestructionAwareBeanPostProcessor

      |-InstantiationAwareBeanPostProcessor  

      |-MergedBeanDefinitionPostProcessor

      |-SmartInstantiationAwareBeanPostProcessor

  (1) 获取所有的BeanPostProcessor的Bean名称

  (2) 将所有的Bean按优先顺序分为三类:

     |-实现了PriorityOrdered接口的列表priorityOrderedPostProcessors

     |-实现了Ordered接口的列表orderedPostProcessors

     |-没有实现任何顺序接口的列表nonOrderedPostProcessors

     |-MergedBeanDefinitionPostProcessor类型的,都放在internalPostProcessors中

  (3) 注册priorityOrderedPostProcessors

  (4) 注册orderedPostProcessors

  (5) 注册nonOrderedPostProcessors

  (6) 注册internalPostProcessors

  (7) 注册ApplicationListenerDetector,它的作用是在Bean实例化之后判断其是否为

      ApplicationListner类型,如果是,则将其添加进容器的监听器集合

7. initMessageSource  初始化消息源Bean,用于消息绑定、消息解析等功能,并且提供国际化解决方案

  (1) 获取beanFactory

  (2) 判断beanFactory中是否包含id为messageSource的Bean

  (3) 如果已存在,则赋值给容器的messageSource属性,这种情况是我们自己在容器中注册了这个Bean

  (4) 如果不存在,则新建一个DelegatingMessageSource,并赋值给容器的messageSource属性,

      然后在beanFactory中注册这个新Bean,并设置其id为messageSource

8. initApplicationEventMulticaster  初始化事件广播器

  (1) 获取beanFactory

  (2) 判断beanFactory中是否存在id为applicationEventMulticaster的Bean

  (3) 如果已存在,则赋值给容器的applicationEventMulticaster属性,这种情况是我们自己在容器中注册了这个Bean

  (4) 如果不存在,则新建一个SimpleApplicationEventMulticaster,并赋值给容器的

      applicationEventMulticaster属性,然后在beanFactory中注册这个新Bean,

      并设置其id为applicationEventMulticaster

9. onRefresh  没有任何操作,留给子类继承的,我们可以自定义子容器,在重写方法中做一些我们想要的操作

10. registerListeners  注册事件监听器

  (1) 获取容器的属性applicationListeners,这是一个事件监听器的集合,将集合中的每个元素都添加进事件广播器

  (2) 从容器中获取所有ApplicationListener类型的Bean,将这些Bean添加进事件广播器

  (3) 发布早期事件,即容器的earlyApplicationEvents属性,然后清空早期事件

11. finishBeanFactoryInitialization  完成剩下的单实例bean的实例化

  (1) 进入DefaultListableBeanFactory.preInstantiateSingletons()方法,获取容器中所有的Bean id列表

  (2) 遍历Bean id列表,对每个Bean,获取其Bean定义信息,即RootBeanDefinition

  (3) 从Bean定义信息中筛选掉抽象类、非单实例、懒加载的,这些bean在创建容器时并不实例化,

      另外还有工厂Bean,即实现了FactoryBean接口的,需要另外一套逻辑进行实例化

  (4) 从缓存中获取单实例Bean,即DefaultSingletonBeanRegistry类的singletonObjects属性,所有被创建过的

      单实例Bean都会被缓存在这个映射中;如果缓存中存在,说明这个Bean之前被创建过,直接返回

  (5) 如果缓存中不存在,则开始新建:AbstractBeanFactory.getBean(beanName)

     ① 将Bean标记为已创建,即将其id存入AbstractBeanFactory的alreadyCreated属性中

     ② 获取Bean的定义信息,即RootBeanDefinition

     ③ 从定义信息中获取该Bean依赖的Bean,如果存在,则重新从第11(4)步开始执行,创建这些依赖的Bean

     ④ 创建完依赖Bean(如果存在)之后,以下开始正式新建目标Bean

     ⑤ 给Bean后置处理器一个机会用代理对象代替目标对象,即执行InstantiationAwareBeanPostProcessor

        类型的Bean后置处理器的postProcessBeforeInstantiation、postProcessAfterInitialization方法

     ⑥ 执行MergedBeanDefinitionPostProcessor类型Bean后置处理器的postProcessMergedBeanDefinition方法

     ⑦ 执行AbstractAutowireCapableBeanFactory.populateBean(beanName, rootBeanDefinition, beanWrapper)方法,即属性赋值。

        在属性赋值之前,首先拿到InstantiationAwareBeanPostProcessor类型的Bean后置处理器,

        并执行postProcessAfterInstantiation、postProcessProperties、postProcessPropertyValues方法。

        然后才执行该类的applyPropertyValues方法,利用反射调用Bean的setter方法进行属性赋值

     ⑧ 执行以下三种aware接口的方法:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

     ⑨ 执行Bean后置处理器的初始化前方法,即BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName)

      ⑩ 执行Bean的初始化方法,即InitializingBean.afterPropertiesSet(),以及在容器中自定义的initMethod

      ⑪ 执行Bean后置处理器的初始化后方法,即BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)

      ⑫ 如果需要,注册Bean的销毁方法,例如在容器中自定义的destroyMethod。这里只是注册,并不调用

  (6) 通过第11(5)步,单实例Bean已经创建并初始化完成,接着,会调用AbstractBeanFactory的父类方法——

      DefaultSingletonBeanRegistry.getSingleton(beanName, false)方法,将新建的Bean存入singletonObjects属性中,即缓存

  (7) 回到DefaultListableBeanFactory.preInstantiateSingletons()方法(见第11(1)步)

      如果新建的Bean实现了SmartInitializingSingleton接口,则执行afterSingletonsInstantiated()回调方法

12. finishRefresh  完成容器刷新

  (1) 初始化生命周期处理器(LifecycleProcessor),先从BeanFactory中按类型获取,

      如果没有就新建一个DefaultLifecycleProcessor,并注册进BeanFactory

  (2) 获取上一步注册的生命周期处理器,回调其onRefresh()方法

  (3) 发布容器刷新事件,即ContextRefreshedEvent

BeanFactory

BeanFactory是个Factory:

    在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。

    它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

    BeanFactory只是个接口,并不是IOC容器的具体实现,
    Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。

    ApplicationContext接口由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,通常建议ApplicationContext优先

FactoryBean

FactoryBean是个特殊的Bean:

    FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式。

    它是一个能生产或者修饰对象生成的工厂Bean,为IOC容器中bean的实现提供了更加灵活的方式。

    它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象。
posted @ 2019-09-22 10:51  LittleDonkey  阅读(227)  评论(0编辑  收藏  举报