spring 配置
BeanDefinition
spring 容器中的每一个 bean 都会抽象为一个 BeanDefinition 对象,spring 容器启动后会把所有的bean 配置信息转化为 beanDefinition 对象。
spring 容器中bean 的配置方式一般有三种:
- 基于XML
- 基于 component service 注解
- java config 形式
BeanDefinitionRegistry
�beanDefinition 中,所有bean的定义都抽象为 BeanDefinitionRegistry 对象
PropertySource
用于存放Spring配置资源信息,例如spring项目中properties或者yaml文件配置信息均会保存在PropertySource对象中。Spring支持使用@PropertySource注解,將配置信息加载到Environment对象中
�
ConfigurationProperties
�可以将配置文件中的配置值直接映射到 java bean
ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar是一个接口,该接口的实现类作用于在Spring解析Bean配置生成BeanDefinition对象阶段。在Spring解析Configuration注解时,向Spring容器中增加额外的BeanDefinition。
BeanFactoryPostProcessorBean
工厂后置处理器,用于在BeanDefinition对象注册完成后,修改Bean工厂信息,例如增加或者修改BeanDefinition对象。
BeanDefinitionRegistryPostProcessor
它是一个特殊的BeanFactoryPostProcessor,用于在BeanDefinition对象注册完成后,访问、新增或者修改BeanDefinition信息。
PropertySourcesPlaceholderConfigurer
它是一个特殊的BeanFactoryPostProcessor,用于解析Bean配置中的${…}参数占位符。
BeanPostProcessor
Bean后置处理器,bean初始化方法调用前后,执行拦截逻辑,可以对原有的Bean进行包装或者根据标记接口创建代理对象。
Apollo 配置管理
EnableApolloConfig
springboot 集成 apollo 只需要使用注解:EnableApolloConfig
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ApolloConfigRegistrar.class)
public @interface EnableApolloConfig {
/**
* Apollo namespaces to inject configuration into Spring Property Sources.
*/
String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
/**
* The order of the apollo config, default is {@link Ordered#LOWEST_PRECEDENCE}, which is Integer.MAX_VALUE.
* If there are properties with the same name in different apollo configs, the apollo config with smaller order wins.
* @return
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
ApolloConfigRegistrar
我们主要看 ApolloConfigRegistrar 类,ApolloConfigRegistrar 实现了接口 ImportBeanDefinitionRegistrar,在spring 容器初始化的过程中,会额外的注入很多配置类
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata
.getAnnotationAttributes(EnableApolloConfig.class.getName()));
String[] namespaces = attributes.getStringArray("value");
int order = attributes.getNumber("order");
PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);
Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
// to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
propertySourcesPlaceholderPropertyValues.put("order", 0);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
PropertySourcesProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
ApolloAnnotationProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class);
BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
ApolloJsonValueProcessor.class);
}
}
bean 的注入
bean 的编程式注入spring 容器
public static boolean registerBeanDefinitionIfNotExists(BeanDefinitionRegistry registry,
String beanName,
Class<?> beanClass,
Map<String, Object> extraPropertyValues) {
if (registry.containsBeanDefinition(beanName)) {
return false;
}
String[] candidates = registry.getBeanDefinitionNames();
for (String candidate : candidates) {
BeanDefinition beanDefinition = registry.getBeanDefinition(candidate);
if (Objects.equals(beanDefinition.getBeanClassName(), beanClass.getName())) {
return false;
}
}
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanClass).getBeanDefinition();
if (extraPropertyValues != null) {
for (Map.Entry<String, Object> entry : extraPropertyValues.entrySet()) {
beanDefinition.getPropertyValues().add(entry.getKey(), entry.getValue());
}
}
registry.registerBeanDefinition(beanName, beanDefinition);
return true;
}
SpringValueProcessor
这个类的注释如下,主要做value注解和xml中通配符的方法或者成员变量的管理
Spring value processor of field or method which has @Value and xml config placeholders.
这个类间接实现了接口 BeanFactoryPostProcessor,BeanFactoryAware,BeanPostProcessor 接口在bean 的初始化前可以拿到spring的上下文,在bean初始化之前会执行 postProcessBeforeInitialization 方法
这个方法里面会过滤含有 value 注解的方法或者注释,覆盖原来的值
protected void processMethod(Object bean, String beanName, Method method) {
//register @Value on method
Value value = method.getAnnotation(Value.class);
if (value == null) {
return;
}
//skip Configuration bean methods
if (method.getAnnotation(Bean.class) != null) {
return;
}
if (method.getParameterTypes().length != 1) {
logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",
bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
return;
}
Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
if (keys.isEmpty()) {
return;
}
for (String key : keys) {
SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
springValueRegistry.register(beanFactory, key, springValue);
logger.info("Monitoring {}", springValue);
}
}
容器中的bean 初始化前都会执行 postProcessBeforeInitialization 方法,这个方法里面拿到了每个bean 的成员变量和方法,然后判断方法上是否存在 value 注解,如果存在会将属性值维护到下面的map, 属性值更新时,也是从这个map中获取
Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();
配置动态更新
如果应用在运行时,apollo 配置动态更新,会有listener 回调机制,最终会调用 AutoUpdateConfigChangeListener 的 updateSpringValue 方法,会定位到某个bean 的某个方法或者属性,
最终通过反射修改属性或者方法
public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
if (isField()) {
injectField(newVal);
} else {
injectMethod(newVal);
}
}
private void injectField(Object newVal) throws IllegalAccessException {
Object bean = beanRef.get();
if (bean == null) {
return;
}
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(bean, newVal);
field.setAccessible(accessible);
}
private void injectMethod(Object newVal)
throws InvocationTargetException, IllegalAccessException {
Object bean = beanRef.get();
if (bean == null) {
return;
}
methodParameter.getMethod().invoke(bean, newVal);
}
�