Spring核心 ApplicationContext的加载过程

spring Bean加载过程

1、找准入口 ,使用ClassPathXmlApplicationContext加载配置文件,用于加载classPath下的配置文件

 

//第一行,执行完成之后就完成了spring配置文件的加载,刷新spring上下文
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(
                "classpath:spring-mvc.xml");
//获取实例Bean
Person person=context.getBean("person",Person.class);

ClassPathXmlApplicationContext的继承关系如下:

https://images2015.cnblogs.com/blog/801753/201702/801753-20170201125310058-568989522.png

2、现在开始仔细分析第一句,可以看出第一句就已经完成了spring配置文件的加载

 

ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(
                "classpath:spring-mvc.xml");

3、查看classPathXmlApplicationContext的源码,下面表格是对象

对象名 类 型 作 用 归属类
configResources Resource[] 配置文件资源对象数组 ClassPathXmlApplicationContext
configLocations String[] 配置文件字符串数组,存储配置文件路径 AbstractRefreshableConfigApplicationContext
beanFactory DefaultListableBeanFactory 上下文使用的Bean工厂 AbstractRefreshableApplicationContext
beanFactoryMonitor Object Bean工厂使用的同步监视器 AbstractRefreshableApplicationContext
id String 上下文使用的唯一Id,标识此ApplicationContext AbstractApplicationContext
parent ApplicationContext 父级ApplicationContext AbstractApplicationContext
beanFactoryPostProcessors List<BeanFactoryPostProcessor> 存储BeanFactoryPostProcessor接口,Spring提供的一个扩展点 AbstractApplicationContext
startupShutdownMonitor Object refresh方法和destory方法公用的一个监视器,避免两个方法同时执行 AbstractApplicationContext
shutdownHook Thread Spring提供的一个钩子,JVM停止执行时会运行Thread里面的方法 AbstractApplicationContext
resourcePatternResolver ResourcePatternResolver 上下文使用的资源格式解析器 AbstractApplicationContext
lifecycleProcessor LifecycleProcessor 用于管理Bean生命周期的生命周期处理器接口 AbstractApplicationContext
messageSource MessageSource 用于实现国际化的一个接口 AbstractApplicationContext
applicationEventMulticaster ApplicationEventMulticaster Spring提供的事件管理机制中的事件多播器接口 AbstractApplicationContext
applicationListeners Set<ApplicationListener> Spring提供的事件管理机制中的应用监听器 AbstractApplicationContext

4、从构造方法可以看出,加载spring配置文件实际调用的是如下构造方法:

 

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
        //设置父级的ApplicationContext,null
        super(parent);
        //1.设置配置文件的路径, 2. 将路径中的占位符${placeholder}使用系统的变量替换
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

5、进入setConfigLocations(configLocations);的源码,这个方法是父类AbstractRefreshableConfigApplicationContext中的方法

 

1. 设置配置文件的路径
2. 替换路径中的占位符`${placeholder}`为系统变量中的值

 

//locations : 配置文件路径-+
public void setConfigLocations(String[] locations) {
        if (locations != null) {
            //断言
            Assert.noNullElements(locations, "Config locations must not be null");
            //存储配置文件路径的数组,存储去掉占位符后的文件路径数组
            this.configLocations = new String[locations.length];
            //遍历locations,解析占位符
            for (int i = 0; i < locations.length; i++) {
                    //调用resolvePath解析占位符
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

6、进入resolvePath的源码可以知道,实际上执行的是AbstractPropertyResolverdoResolvePlaceholders方法,如下

 

/**
* text : 需要解析的路径
* PropertyPlaceholderHelper : 这个是解析系统占位符的辅助类,主要用来将占位符替换成系统的环境变量
*/
private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
        //调用PropertyPlaceholderHelper类中的replacePlaceholders方法
        return helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() {
            public String resolvePlaceholder(String placeholderName) {
                return getPropertyAsRawString(placeholderName);
            }
        });
    }

7、进入PropertyHelper中的replacePlaceholders方法,实际上调用org.springframework.util.PropertyPlaceholderHelper这个类的parseStringValue解析占位符

  1. 实际调用的是parseStringValue方法
  2. this.placeholderPrefix这个是占位符的前缀  {" ,placeholderSuffix="}",valueSeparator=":
  3. 使用parseStringValue方法递归解析占位符中的内容
  4. parseStringValue方法中使用两次递归
    1. placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);,这个是第一次,用来解析占位符中的placeholder是否还包含占位符,如果有占位符需要将其抽离出来,去掉${}
    2. propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); ,这个是第二次递归调用,用来解析propVal中的占位符

 

public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
        Assert.notNull(value, "Argument 'value' must not be null.");
        //调用的是parseStringValue方法
        return parseStringValue(value, placeholderResolver, new HashSet<String>());
    }

/**
* strVal  : 需要解析的字符串,就是配置文件的路径
* placeholderResolver : 策略接口,占位符解析器
* visitedPlaceholders : 存储已经访问过的占位符
**/
protected String parseStringValue(
            String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
        //将st
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值