继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Spring Bean的生命周期-实例化ApplicationContext(一)

慕神8447489
关注TA
已关注
手记 1273
粉丝 174
获赞 956

Spring Bean的生命周期往深入去看,不是简单的几句话能讲完,早就想写相关的内容,但一直觉得工作量不会低,就没有动笔写。拆成几篇来写,这样也不好给自己太大的压力。

webp

image.png

主要分析,Spring容器的初始化过程,然后如何获取Bean,到最终销毁Bean整个过程经历了什么东西。

代码

主要为了分析,更多的是深入源代码中,代码写的就简单一些

//SpringApp.java文件public class SpringApp {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("app.xml");
        HelloWorld hello = (HelloWorld) applicationContext.getBean("hello");
        hello.sayHello();
        applicationContext.close();
    }
}//HelloWorld 文件public class HelloWorld {
    public void sayHello(){
        System.out.println("hello World");
    }
}//app.xml文件<?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.xsd">

    <bean id="hello" class="me.aihe.HelloWorld">

    </bean>
</beans>

文件结构就是这个简单,如下

webp

image.png

过程分析

  1. 新建ClassPathXmlApplicationContext实例的时候,最终实例化的构造方法如下

  • configLocations配置文件位置,支持字符串数组

  • refresh是否自动的刷新上下文,否则在配置之后要手动的调用refresh方法

  • parent 父级的上下文

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {        super(parent);
        setConfigLocations(configLocations);        if (refresh) {
            refresh();
        }
    }

其最终的实例化的父类为:

   //创建AbstractApplicationContext
    public AbstractApplicationContext() {        this.resourcePatternResolver = getResourcePatternResolver();
    }    public AbstractApplicationContext(ApplicationContext parent) {        this();
        setParent(parent);
    }    
    protected ResourcePatternResolver getResourcePatternResolver() {        return new PathMatchingResourcePatternResolver(this);
    }
  1. 设置配置文件的位置, setConfigLocation(String location)

   //支持可变参数,如果locations不存在,那么默认为null
    public void setConfigLocations(String... locations) {        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");            this.configLocations = new String[locations.length];            //处理配置文件的位置,稍作处理
            for (int i = 0; i < locations.length; i++) {                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }        else {            this.configLocations = null;
        }
    }
  1. 刷新Context, 调用refresh()方法,这里先贴出来整个方法, Refreash方法是容器中非常重要的一个方法,一时间这里不好完全讲说明白,先把每个方法的用途注释写上,接下来我们再一起看看其内部是怎么回事

public void refresh() throws BeansException, IllegalStateException {        synchronized (this.startupShutdownMonitor) {            // 准备刷新的Context.
            prepareRefresh();            // Tell the subclass to refresh the internal bean factory.
            // 告诉子类刷新内部的Bean Factory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            // Prepare the bean factory for use in this context.
            // 准备好Context使用的Bean Factory
            prepareBeanFactory(beanFactory);            try {                // Allows post-processing of the bean factory in context subclasses.
                // 设置Bean的 postPorcess
                postProcessBeanFactory(beanFactory);                // Invoke factory processors registered as beans in the context.
                // 调用BeanFactory的 postProcess
                invokeBeanFactoryPostProcessors(beanFactory);                // Register bean processors that intercept bean creation.
                // 注册Bean的PostProcess
                registerBeanPostProcessors(beanFactory);                // Initialize message source for this context.
                //对上下文中的消息源进行初始化
                initMessageSource();                // Initialize event multicaster for this context.
                //初始化上下文的事件机制
                initApplicationEventMulticaster();                // Initialize other special beans in specific context subclasses.
                //初始化其它特殊的beans
                onRefresh();                // Check for listener beans and register them.
                //检查这些Bean,并且向容器注册
                registerListeners();                // Instantiate all remaining (non-lazy-init) singletons.
                //实例化所有的非懒加载的 Singleton
                finishBeanFactoryInitialization(beanFactory);                // Last step: publish corresponding event.
                // 发布相关的事件
                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.
                // 销毁已经创建的singletons避免对资源产生不好的影响
                destroyBeans();                // Reset 'active' flag.
                //重置 active 标志
                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...
                //重置所有的caches
                resetCommonCaches();
            }
        }
    }
涉及到类
  • PathMatchingResourcePatternResolver

  • StandardEnvironment

TODO
  • AbstractRefreshableConfigApplicationContext.resolvePath,其中涉及到了Environment.resolveRequiredPlaceholders(String path)

最后

读代码,如果条理清晰,是一件比较爽的工作,尽量不要急功近利,我们一步一步来,压力都会比较小一点。



作者:Real_man
链接:https://www.jianshu.com/p/2ce01125564f


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP