Spring 框架源码解读11

作者: 想54256 | 来源:发表于2020-04-20 14:58 被阅读0次

    title: Spring 框架源码解读11
    date: 2020/04/20 10:02


    本节内容 & 思考题

    @Value 注解的实现

    1、@Value 注解

    /**
     * Spring 中还可以放在 ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE 上,但是我好想都没用过
     *
     * @author yujx
     * @date 2020/04/20 14:27
     */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Value {
    
        /**
         * el 表达式
         */
        String value();
    }
    

    2、读取 Properties 的 BeanFactory 后置处理器

    public class PropertySourcesBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
        // 存放 properties 文件的位置
        // 理论上是 Spring 初始化这个对象的时候,会通过 set 方法依赖注入,但是为了省事,直接在这里写死
        private String[] locations = new String[]{
                "/Users/x5456/IdeaProjects/Summer/src/test/resources/value/test.properties"
        };
    
        /**
         * 向 bf 中添加一个 @Value 解析器
         */
        @Override
        public void postProcessBeanFactory(ListableBeanFactory beanFactory) {
    
            // 处理 locations 成 List<Properties>
            List<Properties> propertiesList = new ArrayList<>();
            for (String location : locations) {
    
                // 将文件读入 Properties 中
                try {
                    FileInputStream inputStream = new FileInputStream(location);
                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
                    Properties properties = new Properties();
                    properties.load(inputStreamReader);
                    propertiesList.add(properties);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
    
            // 创建一个 properties 解析器
            PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertiesList);
    
            // 将该解析器放进 beanFactory 中
            beanFactory.addEmbeddedValueResolver(propertyResolver);
        }
    
        public void setLocations(String... locations) {
            this.locations = locations;
        }
    }
    

    3、属性解析器

    public interface PropertyResolver {
    
        String getProperty(String key);
    
        <T> T getProperty(String key, Class<T> targetType);
    }
    
    public class PropertySourcesPropertyResolver implements PropertyResolver {
    
        // 在 Spring 中采用的是这个对象: private final PropertySources propertySources;
        private List<Properties> propertySources;
    
        public PropertySourcesPropertyResolver(List<Properties> propertySources) {
            this.propertySources = propertySources;
        }
    
        @Override
        public String getProperty(String key) {
            for (Properties propertySource : propertySources) {
                String value = (String) propertySource.get(key);
                if (StrUtil.isNotBlank(value)) {
                    return value;
                }
            }
            return null;
        }
    
        @Override
        public <T> T getProperty(String key, Class<T> targetType) {
            return ReflectUtils.string2BasicType(this.getProperty(key), targetType);
        }
    }
    

    4、BF 中增加方法

    default void addEmbeddedValueResolver(PropertyResolver propertyResolver) {
        }
    
    default List<PropertyResolver> getEmbeddedValueResolver() {
        return null;
    }
    
    ABF
    
    // 存放解析 @Value 注解的解析器
    private final List<PropertyResolver> embeddedValueResolver = new ArrayList<>();
    
    
    @Override
    public void addEmbeddedValueResolver(PropertyResolver propertyResolver) {
        embeddedValueResolver.add(propertyResolver);
    }
    
    @Override
    public List<PropertyResolver> getEmbeddedValueResolver() {
        return embeddedValueResolver;
    } 
    

    5、书写对 @Value 注解处理的 Bean 后置处理器

    /**
     * 只处理 @Value 注解
     *
     * @author yujx
     * @date 2020/04/20 14:21
     */
    public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
    
        private BeanFactory beanFactory;
    
        /**
         * 在bean的初始化后执行
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
    
            for (Field field : bean.getClass().getDeclaredFields()) {
                Value annotation = AnnotationUtil.getAnnotation(field, Value.class);
                if (ObjectUtil.isNotNull(annotation)) {
    
                    Object fieldValue = annotation.value();
                    String realValue = (String) fieldValue;
                    if (realValue.startsWith("${")) {
                        realValue = realValue.substring(2, realValue.length() - 1);
                    }
    
                    for (PropertyResolver propertyResolver : beanFactory.getEmbeddedValueResolver()) {
                        if (ObjectUtil.isNotNull(propertyResolver.getProperty(realValue))) {
                            fieldValue = propertyResolver.getProperty(realValue);
                            break;
                        }
                    }
    
                    ReflectUtil.setFieldValue(bean, field, fieldValue);
                }
            }
    
            return null;
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = beanFactory;
        }
    }
    

    5、AutowiredAnnotationBeanPostProcessor 注册到 BF 中

    6、PropertySourcesBeanFactoryPostProcessor 通过 AP 注册到 BF 中

    7、测试

    Spring 5.0

    怎样将 properties 文件加载到 Spring 中

    你猜一下是不是用的 BeanFactoryPostProcessor

    image image

    先看 mergeProperties() 吧

    image

    再看第二句

    image image image image

    怎样解析的 @Value 注解

    还记的昨天讲的 AutowiredAnnotationBeanPostProcessor 吗,它实现了 MergedBeanDefinitionPostProcessor 接口,

    MergedBeanDefinitionPostProcessor 接口作用:在完成bean的实例化之后,填充数据(populateBean)之前,可自定义的修改beanDefinition内容

    但是 AutowiredAnnotationBeanPostProcessor 并没有修改 bd 的内容,而是将其中的 @Autoviewed 和 @Value 注解进行了解析,放进了 matedata 中。

    我们一起看一下吧:

    在对象刚刚创建出来会调用这个方法:

    image

    它会找出所有类型是 MergedBeanDefinitionPostProcessor 的进行调用。

    image image image

    对 ${} 的解析在这个方法,还记得 embeddedValueResolvers 中的元素是在哪添加的吧。

    相关文章

      网友评论

        本文标题:Spring 框架源码解读11

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