美文网首页探索Spring
Spring Bean生命周期-prepareRefresh(二

Spring Bean生命周期-prepareRefresh(二

作者: Real_man | 来源:发表于2018-10-05 22:53 被阅读8次

    前面提到了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方法

    最后

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

    相关文章

      网友评论

        本文标题:Spring Bean生命周期-prepareRefresh(二

        本文链接:https://www.haomeiwen.com/subject/mgrcaftx.html