美文网首页
自定义PropertyPlaceholderConfigurer

自定义PropertyPlaceholderConfigurer

作者: sunpy | 来源:发表于2019-04-07 20:38 被阅读0次

介绍

spring的IOC容器提供了BeanFactoryPostProcessor接口在容器实际实例化任何其他的bean之前读取配置元数据并且还可以修改它。也可以控制执行顺序,通过实现Order接口。
BeanFactoryPostProcessor接口的核心方法就是postProcessBeanFactory方法,将配置封装到BeanFactory中。
加载自定义配置文件主要就是PropertyPlaceholderConfigurer,其实现了PropertyPlaceholderConfigurer类实现了BeanFactoryPostProcessor接口,完成了Properties文件的获取,类型转换,加载到BeanFactory。

PropertyPlaceholderConfigurer关键源码

PropertyPlaceholderConfigurer主要是从抽象父类PropertiesLoaderSupport继承得到的父类的模板方法

## 设置本地的Properties文件
    public void setProperties(Properties properties) {
        this.localProperties = new Properties[] {properties};
    }
## 将Properties文件解析,并加入到BeanFactory中
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        try {
            // 根据配置路径获取Properties实例
            Properties mergedProps = mergeProperties();

            // 将属性值转换并替换
            convertProperties(mergedProps);

            // 访问bean工厂中bean定义,替换${....}配置
            processProperties(beanFactory, mergedProps);
        }
        catch (IOException ex) {
            throw new BeanInitializationException("Could not load properties", ex);
        }
    }
## 根据配置路径获取Properties实例
    /**
     * Return a merged Properties instance containing both the
     * loaded properties and properties set on this FactoryBean.
     */
    protected Properties mergeProperties() throws IOException {
        Properties result = new Properties();

        if (this.localOverride) {
            // Load properties from file upfront, to let local properties override.
            loadProperties(result);
        }

        if (this.localProperties != null) {
            for (Properties localProp : this.localProperties) {
                CollectionUtils.mergePropertiesIntoMap(localProp, result);
            }
        }

        if (!this.localOverride) {
            // Load properties from file afterwards, to let those properties override.
            loadProperties(result);
        }

        return result;
    }
## 将属性值转换并替换
    protected void convertProperties(Properties props) {
        Enumeration<?> propertyNames = props.propertyNames();
        while (propertyNames.hasMoreElements()) {
            String propertyName = (String) propertyNames.nextElement();
            String propertyValue = props.getProperty(propertyName);
            String convertedValue = convertProperty(propertyName, propertyValue);
            if (!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) {
                props.setProperty(propertyName, convertedValue);
            }
        }
    }
## 访问bean工厂中bean定义,替换${....}配置
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
            throws BeansException {

        StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);

        this.doProcessProperties(beanFactoryToProcess, valueResolver);
    }

自定义配置

思路:
我们可以扩展加载配置文件的方法,其中可以重写原来的方法,或者在原来的方法上面包装一层。

  1. Properties文件加载工具类
public class SunpyPropertyUtils {
    
    private static Logger log = Logger.getLogger(SunpyPropertyUtils.class);  
    private static final String classpath_header = "classpath:";
    private static final String root_classpath_header = "classpath*:";
    
    
    /**
     * 根据spring配置的路径加载Properties文件
     * 优先级:类路径文件 > 文件系统空间文件
     * @param propertyPath
     * @return
     */
    public final static Properties getProperties(String propertyPath) {  
        if (StringUtils.isEmpty(propertyPath)) {  
            log.error("Properties File Path is null!");
            return null;  
        }
        
        if (propertyPath.startsWith(root_classpath_header)) {
            Properties prop = getClasspathProperties(propertyPath.substring(11));
            
            if (prop == null) {
                getFileSystemProperties(classpath_header+propertyPath.substring(11));
            }
        }
        
        if (propertyPath.startsWith(classpath_header)) {
            return getFileSystemProperties(propertyPath);
        }
        
        return null;
    }
    
    /**
     * 加载类路径上面的Properties文件
     * @param propertyPath
     * @return
     */
    public final static Properties getClasspathProperties(String propertyPath) {
        InputStream is = ClassLoader.getSystemResourceAsStream(propertyPath);
        Properties prop = new Properties();
        
        if (is == null) {
            return null;
        }
        
        try {
            prop.load(is);
            return prop;
        } catch (FileNotFoundException e) {
            log.error(e);
        } catch (IOException e) {
            log.error(e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                log.error(e);
            }
        }
        
        return null;
    }
    
    
    /**
     * 加载 文件系统路径上面的Properties文件
     * @param propertyPath(格式 classpath:xxx.properties)
     * @return
     */
    public final static Properties getFileSystemProperties(String propertyPath) {
        Properties prop = new Properties();
        FileInputStream fis = null;
        
        try {
            File file = ResourceUtils.getFile(propertyPath);
            fis = new FileInputStream(file);
            prop.load(fis);
        } catch (FileNotFoundException e) {
            log.error(e);
        } catch (IOException e) {
            log.error(e);
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                log.error(e);
            }
        }
        
        return prop;
    }
}
  1. 自定义PropertyPlaceholderConfigurer加载类
public class SunpyPropertyPlaceholder extends PropertyPlaceholderConfigurer{
    
    // spring动态配置资源文件路径
    private List<String> resourcePath;

    // 当spring实例化的时候,使用setter方式注入
    public void setResourcePath(List<String> resourcePath) {
        this.resourcePath = resourcePath;
    }

    // 获得配置
    @Override
    protected Properties mergeProperties() throws IOException {
        Properties props = new Properties();
        
        if (CollectionUtils.isEmpty(resourcePath)) {
            return null;
        }
        
        for (String path : resourcePath) {
            Properties prop = SunpyPropertyUtils.getProperties(path);
            
            if (prop != null) {
                props.putAll(prop);
            }
        }
        
        this.setProperties(props);
        return props;
    }
}
  1. 配置XML文件
    <beans:bean id="sunpyPropertyPlaceholder" class="cn.spy.single.common.SunpyPropertyPlaceholder">
        <beans:property name="resourcePath">
            <beans:list>
                <beans:value>classpath:config.properties</beans:value>
            </beans:list>
        </beans:property>
    </beans:bean>
  1. 启动调用成功


相关文章

网友评论

      本文标题:自定义PropertyPlaceholderConfigurer

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