基于注解实现springboot支持自定义yaml配置载入
一、前置知识
阅读本篇文章时,具备以下知识会更便于理解:
- java中注解类的定义以及使用
- java反射的使用
- spring中bean的初始化流程
二、背景
@PropertySource
注解支持引入自己创建的配置文件,但是在spring新版本中仅支持.properties
格式的配置文件。总所周知,properties配置文件在遇到自定义的复杂对象属性时,阅读性差的跟个鬼一样。而yaml
格式的配置文件就很好的解决了这一问题。
国内技术博客现状,ctrl c + v,懂我意思吧。找不到通用性高的就自己手搓。
三、开整
1. 首先定义一个注解@YamlSource
与@PropertySource
用法保持一致,放在配置类上
/**
* @author tomshidi
* @date
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface YamlSource {
/**
* yaml配置文件路径
* @return 路径
*/
String path();
/**
* 字符编码,默认UTF-8,暂未实现
* @see StandardCharsets#UTF_8 etc.
* @return 字符编码
*/
String encoding() default "UTF-8";
}
2. 定义一个bean实例化处理器类
每一步的作用已经写在注释中了,如果看不懂,不要私信我,先看文档开始的那些知识点是不是都熟练运用了。
/**
* @author tomshidi
* @date
*/
@Component
public class ThirdPartYamlProcessor implements InstantiationAwareBeanPostProcessor, ApplicationContextAware {
/**
* spring环境上下文,用来获取环境参数存储对象
*/
private ApplicationContext applicationContext;
/**
* ApplicationContextAware接口中方法的实现,由spring框架在注册当前bean时自动执行
* @param applicationContext spring环境上下文
* @throws BeansException 异常
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* bean实例化前置处理方法,spring中每一个bean初始化都会走到这个方法
* 当然,我们自定义的bean也会进这里,这也就是我们的目的
*
* @param beanClass bean对象Class
* @param beanName bean的名字
* @return
* @throws BeansException 异常
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// 获取配置类上的@YamlSource注解
YamlSource yamlSource = beanClass.getAnnotation(YamlSource.class);
// 如果没找到,跳过后续逻辑
if (yamlSource == null) {
return null;
}
// 这个对象是用来解析yaml文件的
YamlPropertiesFactoryBean yamlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
// 将@YamlSource注解中path参数指定的文件当做资源载入
yamlPropertiesFactoryBean.setResources(new ClassPathResource(yamlSource.path()));
// 获取yaml文件解析的数据
Properties properties = yamlPropertiesFactoryBean.getObject();
// 获取spring的环境参数对象,也就是各种配置的大集合。
Environment environment = applicationContext.getEnvironment();
ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;
MutablePropertySources propertySources = configurableEnvironment.getPropertySources();
// 将我们自定义的yaml文件中的配置写入到spring环境参数中
// 这样在后面配置类bean属性赋值时,spring就能找到对应的值
propertySources.addFirst(new PropertiesPropertySource("defaultProperties", properties));
return null;
}
}
3. 编写自定义yaml配置文件third-part.yml
放在resources/config/third-part.yml这个路径,当然,这个路径与@PropertySource
中路径的使用方法保持一致。
这里定义了基础的String,Integer类型,还定义了一个List对象。
third:
name: tomshidi
age: 1000
nick-name:
- tom
- shi
- di
4. 定义一个配置类ThirdPartConfig
上面忙活了半天,现在来测试一下我们的注解好不好用。
/**
* @author tomshidi
* @date
*/
@Component
@YamlSource(path = "config/third-part.yml")
@ConfigurationProperties(prefix = "third")
public class ThirdPartConfig {
private String name;
private Integer age;
private List<String> nickName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List<String> getNickName() {
return nickName;
}
public void setNickName(List<String> nickName) {
this.nickName = nickName;
}
@Override
public String toString() {
return "ThirdPartConfig{" +
"name='" + name + '\'' +
", age=" + age +
", nickName=" + nickName +
'}';
}
}
5. 启动类
启动类中不需要任何操作,这里为便于查看结果,就手动获取配置类bean对象了。
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
ThirdPartConfig thirdPartConfig = applicationContext.getBean(ThirdPartConfig.class);
System.out.println(thirdPartConfig.toString());
}
}
6. 效果图
效果自然是非常奈斯