AbstractClassEnhancePluginDefine.java 3.5 KB
Newer Older
1
package org.skywalking.apm.agent.core.plugin;
2

A
ascrutae 已提交
3
import net.bytebuddy.dynamic.DynamicType;
4 5
import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
import org.skywalking.apm.util.StringUtil;
P
pengys5 已提交
6 7
import org.skywalking.apm.logging.ILog;
import org.skywalking.apm.logging.LogManager;
8

9 10 11 12
/**
 * Basic abstract class of all sky-walking auto-instrumentation plugins.
 * <p>
 * It provides the outline of enhancing the target class.
13
 * If you want to know more about enhancing, you should go to see {@link ClassEnhancePluginDefine}
14 15
 */
public abstract class AbstractClassEnhancePluginDefine {
16
    private static final ILog logger = LogManager.getLogger(AbstractClassEnhancePluginDefine.class);
17

18 19 20 21
    /**
     * Main entrance of enhancing the class.
     *
     * @param transformClassName target class.
22
     * @param builder byte-buddy's builder to manipulate target class's bytecode.
wu-sheng's avatar
wu-sheng 已提交
23
     * @param classLoader load the given transformClass
24
     * @return the new builder, or <code>null</code> if not be enhanced.
25 26
     * @throws PluginException, when set builder failure.
     */
27
    public DynamicType.Builder<?> define(String transformClassName,
28
        DynamicType.Builder<?> builder, ClassLoader classLoader) throws PluginException {
29 30
        String interceptorDefineClassName = this.getClass().getName();

31
        if (StringUtil.isEmpty(transformClassName)) {
32
            logger.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName);
33
            return null;
34 35
        }

36
        logger.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);
37

38 39 40 41
        /**
         * find witness classes for enhance class
         */
        String[] witnessClasses = witnessClasses();
42
        if (witnessClasses != null) {
A
ascrutae 已提交
43
            for (String witnessClass : witnessClasses) {
44
                if (!WitnessClassFinder.INSTANCE.exist(witnessClass, classLoader)) {
45
                    logger.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName,
46
                        witnessClass);
47
                    return null;
48 49 50 51
                }
            }
        }

A
ascrutae 已提交
52 53 54
        /**
         * find origin class source code for interceptor
         */
55
        DynamicType.Builder<?> newClassBuilder = this.enhance(transformClassName, builder);
56

57
        logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
A
ascrutae 已提交
58

59
        return newClassBuilder;
60 61
    }

62
    protected abstract DynamicType.Builder<?> enhance(String enhanceOriginClassName,
63
        DynamicType.Builder<?> newClassBuilder) throws PluginException;
64 65

    /**
66
     * Define the classname of target class.
67
     *
68
     * @return class full name.
69 70
     */
    protected abstract String enhanceClassName();
71

72
    /**
73 74 75 76 77 78
     * Witness classname list. Why need witness classname? Let's see like this: A library existed two released versions
     * (like 1.0, 2.0), which include the same target classes, but because of version iterator, they may have the same
     * name, but different methods, or different method arguments list. So, if I want to target the particular version
     * (let's say 1.0 for example), version number is obvious not an option, this is the moment you need "Witness
     * classes". You can add any classes only in this particular release version ( something like class
     * com.company.1.x.A, only in 1.0 ), and you can achieve the goal.
79 80 81
     *
     * @return
     */
82 83
    protected String[] witnessClasses() {
        return new String[] {};
84
    }
85
}