spring 配置

BeanDefinition

spring 容器中的每一个 bean 都会抽象为一个 BeanDefinition 对象,spring 容器启动后会把所有的bean 配置信息转化为 beanDefinition 对象。
spring 容器中bean 的配置方式一般有三种:

  1. 基于XML
  2. 基于 component service 注解
  3. 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

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.TYPE)
  3. @Documented
  4. @Import(ApolloConfigRegistrar.class)
  5. public @interface EnableApolloConfig {
  6. /**
  7. * Apollo namespaces to inject configuration into Spring Property Sources.
  8. */
  9. String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};
  10. /**
  11. * The order of the apollo config, default is {@link Ordered#LOWEST_PRECEDENCE}, which is Integer.MAX_VALUE.
  12. * If there are properties with the same name in different apollo configs, the apollo config with smaller order wins.
  13. * @return
  14. */
  15. int order() default Ordered.LOWEST_PRECEDENCE;
  16. }

ApolloConfigRegistrar

我们主要看 ApolloConfigRegistrar 类,ApolloConfigRegistrar 实现了接口 ImportBeanDefinitionRegistrar,在spring 容器初始化的过程中,会额外的注入很多配置类

  1. public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
  2. @Override
  3. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  4. AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata
  5. .getAnnotationAttributes(EnableApolloConfig.class.getName()));
  6. String[] namespaces = attributes.getStringArray("value");
  7. int order = attributes.getNumber("order");
  8. PropertySourcesProcessor.addNamespaces(Lists.newArrayList(namespaces), order);
  9. Map<String, Object> propertySourcesPlaceholderPropertyValues = new HashMap<>();
  10. // to make sure the default PropertySourcesPlaceholderConfigurer's priority is higher than PropertyPlaceholderConfigurer
  11. propertySourcesPlaceholderPropertyValues.put("order", 0);
  12. BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
  13. PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);
  14. BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
  15. PropertySourcesProcessor.class);
  16. BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
  17. ApolloAnnotationProcessor.class);
  18. BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
  19. BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class);
  20. BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
  21. ApolloJsonValueProcessor.class);
  22. }
  23. }

bean 的注入

bean 的编程式注入spring 容器

  1. public static boolean registerBeanDefinitionIfNotExists(BeanDefinitionRegistry registry,
  2. String beanName,
  3. Class<?> beanClass,
  4. Map<String, Object> extraPropertyValues) {
  5. if (registry.containsBeanDefinition(beanName)) {
  6. return false;
  7. }
  8. String[] candidates = registry.getBeanDefinitionNames();
  9. for (String candidate : candidates) {
  10. BeanDefinition beanDefinition = registry.getBeanDefinition(candidate);
  11. if (Objects.equals(beanDefinition.getBeanClassName(), beanClass.getName())) {
  12. return false;
  13. }
  14. }
  15. BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanClass).getBeanDefinition();
  16. if (extraPropertyValues != null) {
  17. for (Map.Entry<String, Object> entry : extraPropertyValues.entrySet()) {
  18. beanDefinition.getPropertyValues().add(entry.getKey(), entry.getValue());
  19. }
  20. }
  21. registry.registerBeanDefinition(beanName, beanDefinition);
  22. return true;
  23. }

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 注解的方法或者注释,覆盖原来的值

  1. protected void processMethod(Object bean, String beanName, Method method) {
  2. //register @Value on method
  3. Value value = method.getAnnotation(Value.class);
  4. if (value == null) {
  5. return;
  6. }
  7. //skip Configuration bean methods
  8. if (method.getAnnotation(Bean.class) != null) {
  9. return;
  10. }
  11. if (method.getParameterTypes().length != 1) {
  12. logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",
  13. bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
  14. return;
  15. }
  16. Set<String> keys = placeholderHelper.extractPlaceholderKeys(value.value());
  17. if (keys.isEmpty()) {
  18. return;
  19. }
  20. for (String key : keys) {
  21. SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
  22. springValueRegistry.register(beanFactory, key, springValue);
  23. logger.info("Monitoring {}", springValue);
  24. }
  25. }

容器中的bean 初始化前都会执行 postProcessBeforeInitialization 方法,这个方法里面拿到了每个bean 的成员变量和方法,然后判断方法上是否存在 value 注解,如果存在会将属性值维护到下面的map, 属性值更新时,也是从这个map中获取

  1. Map<BeanFactory, Multimap<String, SpringValue>> registry = Maps.newConcurrentMap();

配置动态更新

如果应用在运行时,apollo 配置动态更新,会有listener 回调机制,最终会调用 AutoUpdateConfigChangeListener 的 updateSpringValue 方法,会定位到某个bean 的某个方法或者属性,
最终通过反射修改属性或者方法

  1. public void update(Object newVal) throws IllegalAccessException, InvocationTargetException {
  2. if (isField()) {
  3. injectField(newVal);
  4. } else {
  5. injectMethod(newVal);
  6. }
  7. }
  8. private void injectField(Object newVal) throws IllegalAccessException {
  9. Object bean = beanRef.get();
  10. if (bean == null) {
  11. return;
  12. }
  13. boolean accessible = field.isAccessible();
  14. field.setAccessible(true);
  15. field.set(bean, newVal);
  16. field.setAccessible(accessible);
  17. }
  18. private void injectMethod(Object newVal)
  19. throws InvocationTargetException, IllegalAccessException {
  20. Object bean = beanRef.get();
  21. if (bean == null) {
  22. return;
  23. }
  24. methodParameter.getMethod().invoke(bean, newVal);
  25. }