Spring Bean生命周期-prepareRefresh(二)-阿里云开发者社区

开发者社区> 开发与运维> 正文

Spring Bean生命周期-prepareRefresh(二)

简介: 前面提到了ApplicationContext的实例化过程,实例化的时候会判断refresh标志,一般都是true的,在refresh方法中,第一个执行的方法就是prepareRefresh,今天一起看下这个方法内部都做了什么。

前面提到了ApplicationContext的实例化过程,实例化的时候会判断refresh标志,一般都是true的,在refresh方法中,第一个执行的方法就是prepareRefresh,今天一起看下这个方法内部都做了什么。

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            // 准备Context的刷新
            prepareRefresh();
            ....
        }
    }

prepareRefresh方法分析

  1. 首先看下ApplicationContext中的prepareRefresh方法内部。
/**
     * Prepare this context for refreshing, setting its startup date and
     * active flag as well as performing any initialization of property sources.
     * 准备刷新,设置应用开启的时间还有active标志,并且执行一些属性源的初始化工作
     */
    protected void prepareRefresh() {
        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
        // 初始化placeholder属性
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        // 验证所有的必须的属性。
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        // 允许应用启动之前的事件,当multicaster一旦可用的时候,可用立刻响应发布的事件。
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }

  1. initPropertySources,在应用启动之前替换一些属性占位符,这个方法再Spring的对象中一般都没有实现,应该是用来方便我们后期扩展使用的方法。

  2. validateRequiredProperties,Environment类的方法验证必须的属性是否正确。

// AbstractEnvironment 类

//private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
//  private final ConfigurablePropertyResolver propertyResolver =
            new PropertySourcesPropertyResolver(this.propertySources);
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
        this.propertyResolver.validateRequiredProperties();
    }

validateRequiredProperties代码分析

  1. 首先看方法内部。
// this.requiredProperties如果没有操作默认是空的LinkedList
// private final Set<String> requiredProperties = new LinkedHashSet<String>();
public void validateRequiredProperties() {
        MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
        for (String key : this.requiredProperties) {
            if (this.getProperty(key) == null) {
                ex.addMissingRequiredProperty(key);
            }
        }
        if (!ex.getMissingRequiredProperties().isEmpty()) {
            throw ex;
        }
    }
  1. PropertyResolver.getProperty
// PropertySourcesPropertyResolver类

  @Override
    public String getProperty(String key) {
        return getProperty(key, String.class, true);
    }

// 获取属性内部真正起作用的方法   
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
      //打日志
        if (logger.isTraceEnabled()) {
            logger.trace(String.format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName()));
        }
        
        // this.propertySources上面提到了,传进来的是个new MutablePropertySources(this.logger),可变的属性源
        if (this.propertySources != null) {
            for (PropertySource<?> propertySource : this.propertySources) {
                
                Object value;
                // 从propertySource.getProperty中获取对应的key,并且进行解析
                if ((value = propertySource.getProperty(key)) != null) {
                    Class<?> valueType = value.getClass();
                    
                    // 解析字符串类型的key
                    if (resolveNestedPlaceholders && value instanceof String) {
                        value = resolveNestedPlaceholders((String) value);
                    }
                    
                    // this.conversionService.canConvert转换获取的value
                    if (!this.conversionService.canConvert(valueType, targetValueType)) {
                        throw new IllegalArgumentException(String.format(
                                "Cannot convert value [%s] from source type [%s] to target type [%s]",
                                value, valueType.getSimpleName(), targetValueType.getSimpleName()));
                    }
                    return this.conversionService.convert(value, targetValueType);
                }
            }
        }
        if (debugEnabled) {
            logger.debug(String.format("Could not find key '%s' in any property source. Returning [null]", key));
        }
        return null;
    }   

可以看出PropertySourcesPropertyResolver获取key的过程是

  • 先通过PropertySource获取value
  • 再通过conversionService转换value为目标类型,默认是转换为String的是没有问题的。如果无法转换抛出异常

小结

ApplicationContext的准备刷新prepareRefresh逻辑不多,相对简单一些。不过其中涉及到的解析property的过程需要了解。

其它类

  • PropertyPlaceholderHelper ,parseStringValue方法

最后

一步一步来. 看似慢的方法也许是能最快实现目标的方法。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章