前言
Active注解可以被框架中自动激活加载扩展,此Annotation用于配置扩展被自动激活加载条件,不过有时机上的选择。
理解:比如dubbo的Filter 拦截器,我们有很多的实现存在。但是有些是必须要立刻加载的,访问服务日志拦截器AccessLogFilter 如下:
@Activate(group = PROVIDER, value = ACCESS_LOG_KEY)public class AccessLogFilter implements Filter
当提供者的URL中含有accesslog才加载,这里的控制就是需要Active 注解。首先,Dubbo加载这些文件,其次,单需要这个Filter时,使用ExtensionLoader 的方法getActivateExtension(URL url, String key) 来加载对应的实现,就能按条件激活了。
Active源码
/*** 这个注解能够自动激活某些的类*/@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})public @interface Activate {//激活Group的过滤条件String[] group() default {};//Keys过滤条件String[] value() default {};//加载这些扩展的排序int order() default 0;}
getExtension
ExtensionLoader 中含有ClassCache,用于加载标注Actives的Class。
//cache actives类private final Map<String, Object> cachedActivates = new ConcurrentHashMap();//加载所有标注SPI的class,这个方法在加载所有的SPI实现时,里面有个chachedActivates的缓存代码。private Map<String, Class<?>> getExtensionClasses()//加载class时,拿到加载文件的nameprivate void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {...String[] names = NAME_SEPARATOR.split(name);if (ArrayUtils.isNotEmpty(names)) {cacheActivateClass(clazz, names[0]);for (String n : names) {cacheName(clazz, n);saveInExtensionClass(extensionClasses, clazz, n);}}}//找到name对应的class之后,看到是否含有类的Actives注解private void cacheActivateClass(Class<?> clazz, String name) {Activate activate = clazz.getAnnotation(Activate.class);if (activate != null) {cachedActivates.put(name, activate);} else {// support com.alibaba.dubbo.common.extension.Activatecom.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);if (oldActivate != null) {cachedActivates.put(name, oldActivate);}}}
getActiveExtension(…)
这里所有的方法最后调用一个调用加载
public List<T> getActivateExtension(URL url, String key) {return getActivateExtension(url, key, null);}public List<T> getActivateExtension(URL url, String[] values) {return getActivateExtension(url, values, null);}public List<T> getActivateExtension(URL url, String key, String group) {String value = url.getParameter(key);return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);}
getActivateExtension
真正的加载
public List<T> getActivateExtension(URL url, String[] values, String group) {List<T> activateExtensions = new ArrayList<>();List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {//加载SPI标记的所有的class,这时候含有Actives的类就会缓存下来getExtensionClasses();for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {//spi 扩展名String name = entry.getKey();//Actives注解对应的valuesObject activate = entry.getValue();String[] activateGroup, activateValue;if (activate instanceof Activate) {activateGroup = ((Activate) activate).group();activateValue = ((Activate) activate).value();} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();} else {continue;}//传入的参数group和标注的activeGroup是否一致if (isMatchGroup(group, activateGroup)&& !names.contains(name)&& !names.contains(REMOVE_VALUE_PREFIX + name)&& isActive(activateValue, url)) {activateExtensions.add(getExtension(name));}}//排序Activate 具体实现在ActivateComparator里,实现了Comparator 接口compare方法activateExtensions.sort(ActivateComparator.COMPARATOR);}List<T> loadedExtensions = new ArrayList<>();for (int i = 0; i < names.size(); i++) {String name = names.get(i);if (!name.startsWith(REMOVE_VALUE_PREFIX)&& !names.contains(REMOVE_VALUE_PREFIX + name)) {//遍历所有没有排除的扩展名if (DEFAULT_KEY.equals(name)) {if (!loadedExtensions.isEmpty()) {activateExtensions.addAll(0, loadedExtensions);loadedExtensions.clear();}} else {//通过扩展名,加载扩展添加到结果集loadedExtensions.add(getExtension(name));}}}if (!loadedExtensions.isEmpty()) {activateExtensions.addAll(loadedExtensions);}return activateExtensions;}
