dubbo @Activate annotation usage and implementation parsing

The Activate annotation indicates whether an extension is activated (used). It can be placed on the class definition and method. dubbo uses it on the spi extension class definition to indicate the activation condition and time of the extension. First look at the definition:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
    /**
     * Group Filter conditions.
     * <br />
     * Contains the value given by the group parameter of {@ link extensionloader ා getactivateextension}, the extension is returned.
     * <br />
     * If there is no Group setting, it is not filtered.
     */
    String[] group() default {};

    /**
     * Key Filter conditions. If the parameter Key of the URL containing {@ link extensionloader ා getactivateextension}, the extension is returned.
     * <p/>
     * Example: < br / >
     * The value of annotation < code > @ activate ("cache, validatioin") < / code >,
     * If the URL parameter of {@ link extensionloader ා getactivateextension} has < code > cache < / code > key, or < code > validatioin < / code > returns the extension.
     * <br/>
     * If it is not set, it will not be filtered.
     */
    String[] value() default {};

    /**
     * Sorting information, can not be provided.
     */
    String[] before() default {};

    /**
     * Sorting information, can not be provided.
     */
    String[] after() default {};

    /**
     * Sorting information, can not be provided.
     */
    int order() default 0;
}

It has two fields to set filter conditions, group and value are character arrays. Used to specify the conditions under which this extension class is activated.

Here are a few extensions of the com.alibaba.dubbo.rpc.filter interface.

//Such as MonitorFilter
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER})
public class MonitorFilter implements Filter {

}

Indicates that the filter is activated if the filter user (specified by group) belongs to Constants.PROVIDER or Constants.CONSUMER.

//Look at this extension again
@Activate(group = Constants.PROVIDER, value = Constants.TOKEN_KEY)
public class TokenFilter implements Filter {
}

Indicates that the filter is activated if the user of the filter (specified by group) belongs to Constants.PROVIDER and the URL has the parameter Constants.TOKEN_KEY (token).

Let's look at the specific implementation:

When dubbo parses an interface extension implementation class in the ExtensionLoader class, it will put all implementation classes with Activate annotation into a global map first.

Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
    //If yes, add the cachedActivates map extension: implementation class, form
    cachedActivates.put(names[0], activate);
}

Then four methods are provided to specifically use cachedActivates to return the extension to be activated.

 /**
     * This is equivalent to <pre>
     *     getActivateExtension(url, key, null);
     * </pre>
     * In all activation, the extension specified by key is used
     * @param url url
     * @param key url parameter key which used to get extension point names
     * @return extension list which are activated.
     * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String, String)
     */
    public List<T> getActivateExtension(URL url, String key)

      /**
     * This is equivalent to <pre>
     *     getActivateExtension(url, url.getParameter(key).split(","), null);
     * </pre>
     * In all activation, the group to be specified plus the extension specified by key
     * @param url   url
     * @param key   url parameter key which used to get extension point names
     * @param group group
     * @return extension list which are activated.
     * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String)
     */
    public List<T> getActivateExtension(URL url, String key, String group)

      /**
     * This is equivalent to <pre>
     *     getActivateExtension(url, values, null);
     * </pre>
     * The extension specified by values in all activations
     * @param url    url
     * @param values extension point names
     * @return extension list which are activated
     * @see #getActivateExtension(com.alibaba.dubbo.common.URL, String[], String)
     */
    public List<T> getActivateExtension(URL url, String[] values)

    //Finally, there are the following methods to realize
       /**
     * Get activate extensions.
     * Load active extension
     * @param url    url
     * @param values extension point names
     * @param group  group
     * @return extension list which are activated
     * @see com.alibaba.dubbo.common.extension.Activate
     */
    public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            getExtensionClasses();
            //Implementation extension of map structure interface put in cachedActivates: Activate object on it
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {//Traverse all Activate annotation objects
                String name = entry.getKey();//spi extension
                Activate activate = entry.getValue();
                if (isMatchGroup(group, activate.group())) {//If there is a group match
                    T ext = getExtension(name);//Add to extension class
                    //Name is not specified in values, and name is not excluded. The value of activate has corresponding parameters in url, even if it is activated
                    if (!names.contains(name)
                            && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
                            && isActive(activate, url)) {
                        //
                        exts.add(ext);
                    }
                }
            }
            //Sort Activate is implemented in Activate Comparator, which implements Comparator interface compare method
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        List<T> usrs = new ArrayList<T>();
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                    && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                //Traverse all extensions not excluded
                if (Constants.DEFAULT_KEY.equals(name)) {
                    if (usrs.size() > 0) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    //By extension, load extension added to result set
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        if (usrs.size() > 0) {
            exts.addAll(usrs);
        }
	//Return eligible activation extensions
        return exts;
    }

Tags: Dubbo

Posted on Sun, 05 Apr 2020 23:28:48 -0700 by Drachlen