背景
项目中为了统一管理项目的配置,比如接口地址,操作类别等信息,需要一个统一的配置管理中心,类似nacos。
我根据项目的需求写了一套分布式配置中心,测试无误后,改为单体应用并耦合到项目中。项目中使用配置文件多是取配置文件(applicatoion.yml)的值,使用@Value获取,为了秉持非侵入性的原则,我决定写一套自定义注解,以实现最少的代码量实现业务需求。
思路
需要实现类似springboot @Value注解获取配置文件对应key的值的功能。但区别在于 我是从自己写的自动配置中获取,原理就是数据库中查询所有的配置信息,并放入一个对象applicationConfigContext,同时创建一个bean交给spring托管,同时写了个aop,为被注解的属性赋入applicationConfigContext的对应的值。
换句话说,自定义的这个注解为类赋值的时间线大概是
spring bean初始化 —-> 第三方插件初始化 --> 我写的自动配置初始化 ---- 用户调用某个方法,触发aop机制,我通过反射动态改变了触发aop的对象的bean的属性,将值赋值给他。
难点
本项目的难点在于如何修改对象的值。看似简单,其实里面的文章很多。
自动配置代码
配置映射数据库pojo
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @Describtion config bean
* @Author yonyong
* @Date 2020/7/13 15:43
* @Version 1.0.0
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder(toBuilder = true)
public class TblConfig {
private Integer id;
/**
* 配置名称
*/
private String keyName;
/**
* 默认配置值
*/
private String keyValue;
/**
* 分类
*/
private String keyGroup;
/**
* 备注
*/
private String description;
/**
* 创建时间
*/
private Date insertTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 创建人
*/
private String creator;
private Integer start;
private Integer rows;
/**
* 是否是系统自带
*/
private String type;
/**
* 修改人
*/
private String modifier;
}
创建用于防止配置信息的对象容器
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Describtion config container
* @Author yonyong
* @Date 2020/7/13 15:40
* @Version 1.0.0
**/
@Data
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
public class ConfigContext {
/**
* config key-val map
*/
private List vals;
/**
* env type
*/
private String group;
/**
* get config
* @param key
* @return
*/
public String getValue(String key){
final List collect = vals.stream()
.filter(tblConfig -> tblConfig.getKeyName().equals(key))
.collect(Collectors.toList());
if (null == collect || collect.size() == 0)
return null;
return collect.get(0).getKeyValue();
}
}
创建配置,查询出数据库里配置并创建一个容器bean
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;