文章目录
前言
有时项目中需要使用各种文件:sql文件、lua脚本文件、json文件、js文件…。
需要对这些文件的内容进行注入到应用,转换为对象封装到Bean属性中进行处理。
这里使用@Value进行扩展,支持从类路径上的文件转为我们想要的Java 对象。
一、@Value注入原理
@Value由AutowiredAnnotationBeanPostProcessor进行处理。
AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor继承了MergedBeanDefinitionPostProcessor,可以合并BeanDefinition,在合并BeanDefinition过程中的钩子方法中,查找bean的所有依赖,包装为InjectionMetadata。
在postProcessProperties()方法中,通过InjectionMetadata注入,分为AutowiredFieldElement、AutowiredMethodElement,注入的底层是借助BeanFactory去查找依赖的bean或属性。
最终调用到DefaultListableBeanFactory#resolveDependency()。
这里会使用到TypeConverter来对@Value的依赖项进行属性注入,所以我们可以在这里扩展。
"classpath: xxx文件"
-> Java Object
有三种方式扩展
- 自定义PropertyEditor
- 自定义Converter
- 自定义Formmater
二、扩展PropertyEditor
自定义PropertyEditor
public class FileToJsonObjectEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
this.setValue(JSONObject.parseObject(StreamUtils.copyToString(new DefaultResourceLoader().getResource(text).getInputStream(), Charset.defaultCharset())));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
注册自定义PropertyEditor
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(Collections.singletonMap(JSONObject.class, FileToJsonObjectEditor.class));
return configurer;
}
三、扩展Converter
自定义Converter
public class FileToJsonObjectConverter implements Converter<String, JSONObject> {
@Override
public JSONObject convert(String source) {
try {
return JSONObject.parseObject(StreamUtils.copyToString(new DefaultResourceLoader().getResource(source).getInputStream(), Charset.defaultCharset()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
注册自定义Converter
@Bean("conversionService")
public ConversionServiceFactoryBean fonversionServiceFactoryBean() {
ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();
factoryBean.setConverters(Collections.singleton(new FileToJsonObjectConverter()));
return factoryBean;
}
四、扩展Formmater
自定义Formmater
public class FileToJsonObjectFormatter implements Formatter<JSONObject> {
@Override
public JSONObject parse(String text, Locale locale) {
try {
return JSONObject.parseObject(StreamUtils.copyToString(new DefaultResourceLoader().getResource(text).getInputStream(), Charset.defaultCharset()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public String print(JSONObject object, Locale locale) {
return object.toJSONString();
}
}
注册自定义Formmater
@Bean("conversionService")
public FormattingConversionServiceFactoryBean formattingConversionServiceFactoryBean() {
FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean();
factoryBean.setFormatters(Collections.singleton(new FileToJsonObjectFormatter()));
return factoryBean;
}
五、效果
总结
以.json文件为例,介绍了从classpath: xxx文件
-> Java Object
的Bean属性注入数据转换。
Sping支持3种转换方式,PropertyEditor,Converter,Formmater:
- PropertyEditor 是java bean规范的一部分。只能用于字符串和Java对象的转换,不适用于任意两个Java类型之间的转换;在类型转换时不能利用上下文信息(如注解、宿主类结构)实施高级转换逻辑。
- Converter 是一种简单通用的类型转换机制,可以将一种类型转换成另一种类型。
从某种程度上,Converter包含Editor。如果出现需要从string转换到其他类型。首选Editor。
- Formmater 则是主要是针对 Client / Server 之间的对象互相转换。