前言

Active注解可以被框架中自动激活加载扩展,此Annotation用于配置扩展被自动激活加载条件,不过有时机上的选择。
理解:比如dubbo的Filter 拦截器,我们有很多的实现存在。但是有些是必须要立刻加载的,访问服务日志拦截器AccessLogFilter 如下:

  1. @Activate(group = PROVIDER, value = ACCESS_LOG_KEY)
  2. public class AccessLogFilter implements Filter

当提供者的URL中含有accesslog才加载,这里的控制就是需要Active 注解。首先,Dubbo加载这些文件,其次,单需要这个Filter时,使用ExtensionLoader 的方法getActivateExtension(URL url, String key) 来加载对应的实现,就能按条件激活了。

Active源码

  1. /**
  2. * 这个注解能够自动激活某些的类
  3. */
  4. @Documented
  5. @Retention(RetentionPolicy.RUNTIME)
  6. @Target({ElementType.TYPE, ElementType.METHOD})
  7. public @interface Activate {
  8. //激活Group的过滤条件
  9. String[] group() default {};
  10. //Keys过滤条件
  11. String[] value() default {};
  12. //加载这些扩展的排序
  13. int order() default 0;
  14. }

getExtension

ExtensionLoader 中含有ClassCache,用于加载标注Actives的Class。

  1. //cache actives类
  2. private final Map<String, Object> cachedActivates = new ConcurrentHashMap();
  3. //加载所有标注SPI的class,这个方法在加载所有的SPI实现时,里面有个chachedActivates的缓存代码。
  4. private Map<String, Class<?>> getExtensionClasses()
  5. //加载class时,拿到加载文件的name
  6. private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
  7. ...
  8. String[] names = NAME_SEPARATOR.split(name);
  9. if (ArrayUtils.isNotEmpty(names)) {
  10. cacheActivateClass(clazz, names[0]);
  11. for (String n : names) {
  12. cacheName(clazz, n);
  13. saveInExtensionClass(extensionClasses, clazz, n);
  14. }
  15. }
  16. }
  17. //找到name对应的class之后,看到是否含有类的Actives注解
  18. private void cacheActivateClass(Class<?> clazz, String name) {
  19. Activate activate = clazz.getAnnotation(Activate.class);
  20. if (activate != null) {
  21. cachedActivates.put(name, activate);
  22. } else {
  23. // support com.alibaba.dubbo.common.extension.Activate
  24. com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
  25. if (oldActivate != null) {
  26. cachedActivates.put(name, oldActivate);
  27. }
  28. }
  29. }

getActiveExtension(…)

这里所有的方法最后调用一个调用加载

  1. public List<T> getActivateExtension(URL url, String key) {
  2. return getActivateExtension(url, key, null);
  3. }
  4. public List<T> getActivateExtension(URL url, String[] values) {
  5. return getActivateExtension(url, values, null);
  6. }
  7. public List<T> getActivateExtension(URL url, String key, String group) {
  8. String value = url.getParameter(key);
  9. return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
  10. }

getActivateExtension

真正的加载

  1. public List<T> getActivateExtension(URL url, String[] values, String group) {
  2. List<T> activateExtensions = new ArrayList<>();
  3. List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
  4. if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
  5. //加载SPI标记的所有的class,这时候含有Actives的类就会缓存下来
  6. getExtensionClasses();
  7. for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
  8. //spi 扩展名
  9. String name = entry.getKey();
  10. //Actives注解对应的values
  11. Object activate = entry.getValue();
  12. String[] activateGroup, activateValue;
  13. if (activate instanceof Activate) {
  14. activateGroup = ((Activate) activate).group();
  15. activateValue = ((Activate) activate).value();
  16. } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
  17. activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
  18. activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
  19. } else {
  20. continue;
  21. }
  22. //传入的参数group和标注的activeGroup是否一致
  23. if (isMatchGroup(group, activateGroup)
  24. && !names.contains(name)
  25. && !names.contains(REMOVE_VALUE_PREFIX + name)
  26. && isActive(activateValue, url)) {
  27. activateExtensions.add(getExtension(name));
  28. }
  29. }
  30. //排序Activate 具体实现在ActivateComparator里,实现了Comparator 接口compare方法
  31. activateExtensions.sort(ActivateComparator.COMPARATOR);
  32. }
  33. List<T> loadedExtensions = new ArrayList<>();
  34. for (int i = 0; i < names.size(); i++) {
  35. String name = names.get(i);
  36. if (!name.startsWith(REMOVE_VALUE_PREFIX)
  37. && !names.contains(REMOVE_VALUE_PREFIX + name)) {
  38. //遍历所有没有排除的扩展名
  39. if (DEFAULT_KEY.equals(name)) {
  40. if (!loadedExtensions.isEmpty()) {
  41. activateExtensions.addAll(0, loadedExtensions);
  42. loadedExtensions.clear();
  43. }
  44. } else {
  45. //通过扩展名,加载扩展添加到结果集
  46. loadedExtensions.add(getExtension(name));
  47. }
  48. }
  49. }
  50. if (!loadedExtensions.isEmpty()) {
  51. activateExtensions.addAll(loadedExtensions);
  52. }
  53. return activateExtensions;
  54. }

参考