Skip to content

Spy class是如何在各个业务classloader 中加载的? #292

@shidongwa

Description

@shidongwa

请教各位大神:

看greys-anatomy/core/src/main/java/com/github/ompc/greys/core/advisor/Enhancer.java 中的代码,是把spyClassFromGreysClassLoader中的Spy.class 拷一份到 spyClassFromTargetClassLoader中去加载,前提是spyClassFromTargetClassLoader中找不到Spy.class的话。问题是Spy.class是打包在greys-agent.jar 而不是 grey-core.jar 中。spyClassFromGreysClassLoader实际从grey-core.jar是找不到这个Spy.class的,最终还是通过父classloader加载。这里是bootstrap classloader。既然Spy.class 是通过bootstrap加载了,那么spyClassFromTargetClassLoader走的是父委托方式,都会找到bootstrap中的Spy.class, 也就不需要在spyClassFromTargetClassLoader中分别加载了。这不是没有达到“派遣间谍混入对方的classLoader中”的目的么?

`
/*
* 派遣间谍混入对方的classLoader中
*/
private void spy(final ClassLoader targetClassLoader)
throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {

    // 如果对方是bootstrap就算了
    if (null == targetClassLoader) {
        return;
    }


    // Enhancer类只可能从greysClassLoader中加载
    // 所以找他要ClassLoader是靠谱的
    final ClassLoader greysClassLoader = Enhancer.class.getClassLoader();

    final String spyClassName = GaStringUtils.SPY_CLASSNAME;

    // 从GreysClassLoader中加载Spy
    final Class<?> spyClassFromGreysClassLoader = loadSpyClassFromGreysClassLoader(greysClassLoader, spyClassName);
    if (null == spyClassFromGreysClassLoader) {
        return;
    }

    // 从目标ClassLoader中尝试加载或定义ClassLoader
    Class<?> spyClassFromTargetClassLoader = null;
    try {

        // 去目标类加载器中找下是否已经存在间谍
        // 如果间谍已经存在就算了
        spyClassFromTargetClassLoader = targetClassLoader.loadClass(spyClassName);
        logger.info("Spy already in targetClassLoader : " + targetClassLoader);

    }

    // 看来间谍不存在啊
    catch (ClassNotFoundException cnfe) {

        try {// 在目标类加载器中混入间谍
            spyClassFromTargetClassLoader = defineClass(
                    targetClassLoader,
                    spyClassName,
                    toByteArray(Enhancer.class.getResourceAsStream("/" + spyClassName.replace('.', '/') + ".class"))
            );
        } catch (InvocationTargetException ite) {
            if (ite.getCause() instanceof java.lang.LinkageError) {
                // CloudEngine 由于 loadClass 不到,会导致 java.lang.LinkageError: loader (instance of  com/alipay/cloudengine/extensions/equinox/KernelAceClassLoader): attempted  duplicate class definition for name: "com/taobao/arthas/core/advisor/Spy"
                // 这里尝试忽略
                logger.debug("resolve #112 issues", ite);
            } else {
                throw ite;
            }
        }

    }


    // 无论从哪里取到spyClass,都需要重新初始化一次
    // 用以兼容重新加载的场景
    // 当然,这样做会给渲染的过程带来一定的性能开销,不过能简化编码复杂度
    finally {

        if (null != spyClassFromTargetClassLoader) {
            // 初始化间谍
            invokeStaticMethod(
                    spyClassFromTargetClassLoader,
                    "init",
                    greysClassLoader,
                    getField(spyClassFromGreysClassLoader, "ON_BEFORE_METHOD").get(null),
                    getField(spyClassFromGreysClassLoader, "ON_RETURN_METHOD").get(null),
                    getField(spyClassFromGreysClassLoader, "ON_THROWS_METHOD").get(null),
                    getField(spyClassFromGreysClassLoader, "BEFORE_INVOKING_METHOD").get(null),
                    getField(spyClassFromGreysClassLoader, "AFTER_INVOKING_METHOD").get(null),
                    getField(spyClassFromGreysClassLoader, "THROW_INVOKING_METHOD").get(null)
            );
        }

    }

}

`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions