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


先看 mergeProperties() 吧

再看第二句




怎样解析的 @Value 注解
还记的昨天讲的 AutowiredAnnotationBeanPostProcessor 吗,它实现了 MergedBeanDefinitionPostProcessor 接口,
MergedBeanDefinitionPostProcessor 接口作用:在完成bean的实例化之后,填充数据(populateBean)之前,可自定义的修改beanDefinition内容
但是 AutowiredAnnotationBeanPostProcessor 并没有修改 bd 的内容,而是将其中的 @Autoviewed 和 @Value 注解进行了解析,放进了 matedata 中。
我们一起看一下吧:
在对象刚刚创建出来会调用这个方法:

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



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