程序员社区

Spring 框架源码解读11


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

Spring 框架源码解读11插图
Spring 框架源码解读11插图1

先看 mergeProperties() 吧

Spring 框架源码解读11插图2

再看第二句

Spring 框架源码解读11插图3
Spring 框架源码解读11插图4
Spring 框架源码解读11插图5
Spring 框架源码解读11插图6

怎样解析的 @Value 注解

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

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

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

我们一起看一下吧:

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

Spring 框架源码解读11插图7

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

Spring 框架源码解读11插图8
Spring 框架源码解读11插图9
Spring 框架源码解读11插图10

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

赞(0) 打赏
未经允许不得转载:IDEA激活码 » Spring 框架源码解读11

一个分享Java & Python知识的社区