Apollo源码--Spring注解集成

@EnableApolloConfig

java客户端集成Apollo只需要启动类加上@EnableApolloConfig,或者配合@Configuration一起使用即可

package com.ctrip.framework.apollo.spring.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ApolloConfigRegistrar.class)
public @interface EnableApolloConfig {
  /**
   * namespace的数组
   */
  String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};

  /**
   * 优先级,数字越小优先级越高
   * 默认是Integer最大值
   */
  int order() default Ordered.LOWEST_PRECEDENCE;
}

ApolloConfigRegistrar

package com.ctrip.framework.apollo.spring.annotation;

/**
 * @author Jason Song([email protected])
 */
public class ApolloConfigRegistrar implements ImportBeanDefinitionRegistrar {
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
    // 解析 @EnableApolloConfig 注解
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata
        .getAnnotationAttributes(EnableApolloConfig.class.getName()));
    String[] namespaces = attributes.getStringArray("value");
    int order = attributes.getNumber("order");
    
    // 添加到 PropertySourcesProcessor 中
    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);

    // 注册 PropertySourcesPlaceholderConfigurer 到 BeanDefinitionRegistry 中,替换 PlaceHolder 为对应的属性值,参考文章 https://leokongwq.github.io/2016/12/28/spring-PropertyPlaceholderConfigurer.html
    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesPlaceholderConfigurer.class.getName(),
        PropertySourcesPlaceholderConfigurer.class, propertySourcesPlaceholderPropertyValues);

    //【差异】注册 PropertySourcesProcessor 到 BeanDefinitionRegistry 中,因为可能存在 XML 配置的 Bean ,用于 PlaceHolder 自动更新机制
    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, PropertySourcesProcessor.class.getName(),
        PropertySourcesProcessor.class);

    // 注册 ApolloAnnotationProcessor 到 BeanDefinitionRegistry 中,解析 @ApolloConfig 和 @ApolloConfigChangeListener 注解。
    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloAnnotationProcessor.class.getName(),
        ApolloAnnotationProcessor.class);

    // 注册 SpringValueProcessor 到 BeanDefinitionRegistry 中,用于 PlaceHolder 自动更新机制
    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueProcessor.class.getName(), SpringValueProcessor.class);
    
    //【差异】注册 SpringValueDefinitionProcessor 到 BeanDefinitionRegistry 中,因为可能存在 XML 配置的 Bean ,用于 PlaceHolder 自动更新机制
    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, SpringValueDefinitionProcessor.class.getName(), SpringValueDefinitionProcessor.class);

    // 注册 ApolloJsonValueProcessor 到 BeanDefinitionRegistry 中,解析 @ApolloJsonValue 注解。
    BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, ApolloJsonValueProcessor.class.getName(),
            ApolloJsonValueProcessor.class);
  }
}

如果要在项目中解耦,不想使用@EnableApolloConfig,

可以实现BeanDefinitionRegistryPostProcessor

加上@Configuration

复写postProcessBeanDefinitionRegistry,在里面执行ApolloConfigRegistrar中的代码即可

可以自行加上一些控制代码

注解

@ApolloJsonValue

package com.ctrip.framework.apollo.spring.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@Documented
public @interface ApolloJsonValue {

  /**
   * The actual value expression: e.g. "${someJsonPropertyKey:someDefaultValue}".
   */
  String value();
}

将 Apollo 任意格式的 Namespace 的一个 Item 配置项,解析成对应类型的对象,注入到 @ApolloJsonValue 的对象中

具体解析参照ApolloJsonValueProcessor

@ApolloConfig

package com.ctrip.framework.apollo.spring.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface ApolloConfig {
  /**
   * Apollo namespace for the config, if not specified then default to application
   */
  String value() default ConfigConsts.NAMESPACE_APPLICATION;
}

将 Apollo Config 对象注入

具体解析参照ApolloAnnotationProcessor

@ApolloConfigChangeListener

package com.ctrip.framework.apollo.spring.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ApolloConfigChangeListener {
  /**
   * Apollo namespace for the config, if not specified then default to application
   */
  String[] value() default {ConfigConsts.NAMESPACE_APPLICATION};

  /**
   * The keys interested by the listener, will only be notified if any of the interested keys is changed.
   * <br />
   * If neither of {@code interestedKeys} and {@code interestedKeyPrefixes} is specified then the {@code listener} will be notified when any key is changed.
   */
  String[] interestedKeys() default {};

  /**
   * 当且仅当更改的key以任何listener监听的前缀开头时,才会通知listener。
   * The prefixes will simply be used to determine whether the {@code listener} should be notified or not using {@code changedKey.startsWith(prefix)}.
   * e.g. "spring." means that {@code listener} is interested in keys that starts with "spring.", such as "spring.banner", "spring.jpa", etc.
   * and "application" means that {@code listener} is interested in keys that starts with "application", such as "applicationName", "application.port", etc.
   * <br />
   * If neither of {@code interestedKeys} and {@code interestedKeyPrefixes} is specified then the {@code listener} will be notified when whatever key is changed.
   */
  String[] interestedKeyPrefixes() default {};
}

处理器

ApolloJsonValueProcessor

无参构造
  private final ConfigUtil configUtil;
  private final PlaceholderHelper placeholderHelper;
  private final SpringValueRegistry springValueRegistry;
  private ConfigurableBeanFactory beanFactory;

  public ApolloJsonValueProcessor() {
    configUtil = ApolloInjector.getInstance(ConfigUtil.class);
    placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class);
    springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class);
  }
processField
  @Override
  protected void processField(Object bean, String beanName, Field field) {
    ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(field, ApolloJsonValue.class);
    if (apolloJsonValue == null) {
      return;
    }
    // 获得 Placeholder 表达式
    String placeholder = apolloJsonValue.value();
    
    // 解析对应的值
    Object propertyValue = placeholderHelper
        .resolvePropertyValue(beanFactory, beanName, placeholder);

    // 忽略,非 String 值
    if (!(propertyValue instanceof String)) {
      return;
    }

    // 设置到 Field 中
    boolean accessible = field.isAccessible();
    field.setAccessible(true);
    ReflectionUtils
        .setField(field, bean, parseJsonValue((String)propertyValue, field.getGenericType()));
    field.setAccessible(accessible);

    // 是否开启自动更新机制
    if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
      
      // 提取keys属性
      Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
      
      // 循环 `keys` ,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
      for (String key : keys) {
        SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true);
        springValueRegistry.register(beanFactory, key, springValue);
        logger.debug("Monitoring {}", springValue);
      }
    }
  }
processMethod
    @Override
    protected void processMethod(Object bean, String beanName, Method method) {
        ApolloJsonValue apolloJsonValue = AnnotationUtils.getAnnotation(method, ApolloJsonValue.class);
        if (apolloJsonValue == null) {
            return;
        }

        // 获得 Placeholder 表达式
        String placeHolder = apolloJsonValue.value();

        // 解析对应的值
        Object propertyValue = placeholderHelper
                .resolvePropertyValue(beanFactory, beanName, placeHolder);

        // 忽略,非 String 值
        // propertyValue will never be null, as @ApolloJsonValue will not allow that
        if (!(propertyValue instanceof String)) {
            return;
        }

        Type[] types = method.getGenericParameterTypes();
        Preconditions.checkArgument(types.length == 1,
                "Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",
                bean.getClass().getName(), method.getName(), method.getParameterTypes().length);

        // 调用 Method ,设置值
        boolean accessible = method.isAccessible();
        method.setAccessible(true);
        ReflectionUtils.invokeMethod(method, bean, parseJsonValue((String) propertyValue, types[0]));
        method.setAccessible(accessible);

        // 是否开启自动更新机制
        if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) {
            // 提取 `keys` 属性们。
            Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeHolder);
            // 循环 `keys` ,创建对应的 SpringValue 对象,并添加到 `springValueRegistry` 中。
            for (String key : keys) {
                SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName,
                        method, true);
                springValueRegistry.register(beanFactory, key, springValue);
                logger.debug("Monitoring {}", springValue);
            }
        }
    }

ApolloAnnotationProcessor

处理 @ApolloConfig@ApolloConfigChangeListener 注解处理器的初始化

processField
    @Override
    protected void processField(Object bean, String beanName, Field field) {
        ApolloConfig annotation = AnnotationUtils.getAnnotation(field, ApolloConfig.class);
        if (annotation == null) {
            return;
        }

        Preconditions.checkArgument(Config.class.isAssignableFrom(field.getType()),
                "Invalid type: %s for field: %s, should be Config", field.getType(), field);

        // 创建 Config 对象
        String namespace = annotation.value();
        Config config = ConfigService.getConfig(namespace);

        // 设置 Config 对象,到对应的 Field
        ReflectionUtils.makeAccessible(field);
        ReflectionUtils.setField(field, bean, config);
    }
processMethod
    @Override
    protected void processMethod(final Object bean, String beanName, final Method method) {
        ApolloConfigChangeListener annotation = AnnotationUtils
                .findAnnotation(method, ApolloConfigChangeListener.class);
        if (annotation == null) {
            return;
        }
        Class<?>[] parameterTypes = method.getParameterTypes();
        Preconditions.checkArgument(parameterTypes.length == 1,
                "Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length,
                method);
        Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]),
                "Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0],
                method);

        // 创建 ConfigChangeListener 监听器。该监听器会调用被注解的方法。
        ReflectionUtils.makeAccessible(method);
        String[] namespaces = annotation.value();
        String[] annotatedInterestedKeys = annotation.interestedKeys();
        String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes();
        ConfigChangeListener configChangeListener = new ConfigChangeListener() {
            @Override
            public void onChange(ConfigChangeEvent changeEvent) {
                ReflectionUtils.invokeMethod(method, bean, changeEvent);
            }
        };

        Set<String> interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null;
        Set<String> interestedKeyPrefixes = annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null;

        // 向指定 Namespace 的 Config 对象们,注册该监听器
        for (String namespace : namespaces) {
            Config config = ConfigService.getConfig(namespace);

            if (interestedKeys == null && interestedKeyPrefixes == null) {
                config.addChangeListener(configChangeListener);
            } else {
                config.addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes);
            }
        }
    }
发布了37 篇原创文章 · 获赞 1 · 访问量 1068

猜你喜欢

转载自blog.csdn.net/zhuchencn/article/details/102533830