Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dubbo-2.7.10] Fix setSkyWalkingDynamicField(java.lang.Object) not found #7517

Merged
merged 4 commits into from
Apr 27, 2021
Merged

[Dubbo-2.7.10] Fix setSkyWalkingDynamicField(java.lang.Object) not found #7517

merged 4 commits into from
Apr 27, 2021

Conversation

zifeihan
Copy link
Member

@zifeihan zifeihan commented Apr 7, 2021

What is the purpose of the change

Brief changelog

Verifying this change

  • Make sure there is a GitHub_issue field for the change (usually before you start working on it). Trivial changes like typos do not require a GitHub issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
  • Format the pull request title like [Dubbo-XXX] Fix UnknownException when host config not exist #XXX. Each commit in the pull request should have a meaningful subject line and body.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add sample in dubbo samples project.
  • Run mvn clean install -DskipTests=false & mvn clean test-compile failsafe:integration-test to make sure unit-test and integration-test pass.
  • If this contribution is large, please follow the Software Donation Guide.

Fix setSkyWalkingDynamicField(java.lang.Object) not found,the comment is a detailed description, in order to avoid misunderstanding, sorry to use Chinese ,link issue, #2830

@zifeihan zifeihan changed the title [Dubbo-2.7.10-SNAPSHOT] Fix setSkyWalkingDynamicField(java.lang.Object) not found [Dubbo-2.7.10] Fix setSkyWalkingDynamicField(java.lang.Object) not found Apr 7, 2021
@zifeihan
Copy link
Member Author

zifeihan commented Apr 7, 2021

Dubbo+SkyWalking使用导致应用启动失败

1.现象:在10357启动启动失败,并包含部分和SkyWalking相关的日志,使用了SkyWalking可选插件包spring-annotation-plugin

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'financeLessonServiceImpl': Unsatisfied dependency expressed through field 'lessonSynInfoService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'lessonSynInfoServiceImpl' defined in URL [jar:file:/opt/10357/target.jar!/BOOT-INF/classes!/com/zhangmen/lesson/service/LessonSynInfoServiceImpl.class]: Initialization of bean failed; nested exception is java.lang.RuntimeException: [source error] setSkyWalkingDynamicField(java.lang.Object) not found in com.zhangmen.lesson.service.LessonSynInfoServiceImpl
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:364)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1268)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:211)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1131)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583)
	... 27 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'lessonSynInfoServiceImpl' defined in URL [jar:file:/opt/10357/target.jar!/BOOT-INF/classes!/com/zhangmen/lesson/service/LessonSynInfoServiceImpl.class]: Initialization of bean failed; nested exception is java.lang.RuntimeException: [source error] setSkyWalkingDynamicField(java.lang.Object) not found in com.zhangmen.lesson.service.LessonSynInfoServiceImpl
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:481)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:312)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:308)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:211)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1131)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1059)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:583)
	... 40 common frames omitted
Caused by: java.lang.RuntimeException: [source error] setSkyWalkingDynamicField(java.lang.Object) not found in com.zhangmen.lesson.service.LessonSynInfoServiceImpl
	at com.alibaba.dubbo.common.bytecode.ClassGenerator.toClass(ClassGenerator.java:354)
	at com.alibaba.dubbo.common.bytecode.ClassGenerator.toClass(ClassGenerator.java:293)
	at com.alibaba.dubbo.common.bytecode.Wrapper.makeWrapper(Wrapper.java:346)
	at com.alibaba.dubbo.common.bytecode.Wrapper.getWrapper(Wrapper.java:89)
	at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory.getInvoker(JavassistProxyFactory.java:40)
	at com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper.getInvoker(StubProxyFactoryWrapper.java:104)
	at com.alibaba.dubbo.rpc.ProxyFactory$Adpative.getInvoker(ProxyFactory$Adpative.java)
	at com.alibaba.dubbo.config.ServiceConfig.exportLocal(ServiceConfig.java:515)
	at com.alibaba.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:469)
	at com.alibaba.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:285)
	at com.alibaba.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:246)
	at com.alibaba.dubbo.config.ServiceConfig.export(ServiceConfig.java:145)
	at com.alibaba.dubbo.config.spring.AnnotationBean.postProcessAfterInitialization(AnnotationBean.java:202)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1634)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
	... 49 common frames omitted
Caused by: javassist.CannotCompileException: [source error] setSkyWalkingDynamicField(java.lang.Object) not found in com.zhangmen.lesson.service.LessonSynInfoServiceImpl
	at javassist.CtNewMethod.make(CtNewMethod.java:79)
	at javassist.CtNewMethod.make(CtNewMethod.java:45)
	at com.alibaba.dubbo.common.bytecode.ClassGenerator.toClass(ClassGenerator.java:322)
	... 64 common frames omitted
Caused by: javassist.compiler.CompileError: setSkyWalkingDynamicField(java.lang.Object) not found in com.zhangmen.lesson.service.LessonSynInfoServiceImpl
	at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:749)
	at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:695)
	at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:157)
	at javassist.compiler.ast.CallExpr.accept(CallExpr.java:46)
	at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:242)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:330)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:351)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
	at javassist.compiler.CodeGen.atIfStmnt(CodeGen.java:398)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:355)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
	at javassist.compiler.CodeGen.atStmnt(CodeGen.java:351)
	at javassist.compiler.ast.Stmnt.accept(Stmnt.java:50)
	at javassist.compiler.CodeGen.atMethodBody(CodeGen.java:292)
	at javassist.compiler.CodeGen.atMethodDecl(CodeGen.java:274)
	at javassist.compiler.ast.MethodDecl.accept(MethodDecl.java:44)
	at javassist.compiler.Javac.compileMethod(Javac.java:169)
	at javassist.compiler.Javac.compile(Javac.java:95)
	at javassist.CtNewMethod.make(CtNewMethod.java:74)
	... 66 common frames omitted
609902 [DubboShutdownHook] INFO  c.a.dubbo.config.AbstractConfig -  [DUBBO] Run shutdown hook now., dubbo version: 2.8.4-SNAPSHOT, current host: 127.0.0.1
609910 [DubboShutdownHook] INFO  c.a.d.r.s.AbstractRegistryFactory -  [DUBBO] Close all registries [zookeeper://vpc-fat-2.zmaxis.com:2181/com.alibaba.dubbo.registry.RegistryService?application=lesson-service&client=curator&dubbo=2.8.4-SNAPSHOT&interface=com.alibaba.dubbo.registry.RegistryService&organization=zhangmen.com&owner=platform&pid=31067&timestamp=1617781930060], dubbo version: 2.8.4-SNAPSHOT, current host: 127.0.0.1

2.原因排查

排查该问题我们需要先明确几点:

2.1 SkyWalking在增强某个类的成员方法时(非静态方法),会为修改该类字节码,会为其增加_$EnhancedClassField_ws字段,见代码1,并使其实现org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance接口,该接口中存在两个方法,见代码2。

代码1: 
 				/**
         * Manipulate class source code.<br/>
         *
         * new class need:<br/>
         * 1.Add field, name {@link #CONTEXT_ATTR_NAME}.
         * 2.Add a field accessor for this field.
         *
         * And make sure the source codes manipulation only occurs once.
         *
         */
        if (!typeDescription.isAssignableTo(EnhancedInstance.class)) {
            if (!context.isObjectExtended()) {
                newClassBuilder = newClassBuilder.defineField(
                    CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE)
                                                 .implement(EnhancedInstance.class)
                                                 .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
                context.extendObjectCompleted();
            }
        }
代码2:
package org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance;

public interface EnhancedInstance {
    Object getSkyWalkingDynamicField();

    void setSkyWalkingDynamicField(Object value);
}

2.2 当某个类被SkyWalking增强后,可以通过反射机制查看到SkyWalking为其增加的getSkyWalkingDynamicField(),setSkyWalkingDynamicField这两个方法。还有就有就是如果没有使用javaagent相关机制,没有办法获取到jvm中被其他agent增强后的字节码,简单来说没有特殊机制没有办法获取到被增强后的字节码(或许有,我还不知道相关的办法)。

有了上述两点支撑,对于接下来排查问题就比较方便了。

2.3 问题发生的原因,我们可以看到在异常中存在setSkyWalkingDynamicField(java.lang.Object) not found in com.zhangmen.lesson.service.LessonSynInfoServiceImpl这个信息,当我看到这个信息的时候,我有两个怀疑点,1. 为什么dubbo的代码代理了setSkyWalkingDynamicField(java.lang.Object) 这个方法,2. com.zhangmen.lesson.service.LessonSynInfoServiceImpl这个类在加载完成后,里面肯定是存在setSkyWalkingDynamicField(java.lang.Object) 这个方法,为什么dubbo字节码代理的时候却说没有找到该方法。接下来我看了一下dubbo(2.8.4-SNAPSHOT)生成代理的代码如下,为了方便分析问题,添加了部分注释。

com.alibaba.dubbo.common.bytecode.Wrapper#makeWrapper:    
    private static Wrapper makeWrapper(Class<?> c) {
        if (c.isPrimitive()) {
            throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
        } else {
            String name = c.getName();
            ClassLoader cl = ClassHelper.getClassLoader(c);
            StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
            StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
            StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
            c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            Map<String, Class<?>> pts = new HashMap();
            Map<String, Method> ms = new LinkedHashMap();
            List<String> mns = new ArrayList();
            List<String> dmns = new ArrayList();
            Field[] arr$ = c.getFields();
            int len$ = arr$.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Field f = arr$[i$];
                String fn = f.getName();
                Class<?> ft = f.getType();
                if (!Modifier.isStatic(f.getModifiers()) && !Modifier.isTransient(f.getModifiers())) {
                    c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
                    c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
                    pts.put(fn, ft);
                }
            }

						// 在这里使用了反射获取当前类的方法,这里返回的方法中肯定包含SkyWalking字节码增强添加的两个方法
            Method[] methods = c.getMethods();
            boolean hasMethod = hasMethods(methods);
            if (hasMethod) {
                c3.append(" try{");
            }

            Method[] arr$ = methods;
            int len$ = methods.length;

            int ix;
            for(int i$ = 0; i$ < len$; ++i$) {
                Method m = arr$[i$];
                if (m.getDeclaringClass() != Object.class) {
                    String mn = m.getName();
                    c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
                    ix = m.getParameterTypes().length;
                    c3.append(" && ").append(" $3.length == ").append(ix);
                    boolean override = false;
                    Method[] arr$ = methods;
                    int len$ = methods.length;

                    for(int i$ = 0; i$ < len$; ++i$) {
                        Method m2 = arr$[i$];
                        if (m != m2 && m.getName().equals(m2.getName())) {
                            override = true;
                            break;
                        }
                    }

                    if (override && ix > 0) {
                        for(int l = 0; l < ix; ++l) {
                            c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"").append(m.getParameterTypes()[l].getName()).append("\")");
                        }
                    }

                    c3.append(" ) { ");
                    if (m.getReturnType() == Void.TYPE) {
                        c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
                    } else {
                        c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
                    }

                    c3.append(" }");
                    mns.add(mn);
                    if (m.getDeclaringClass() == c) {
                        dmns.add(mn);
                    }

                    ms.put(ReflectUtils.getDesc(m), m);
                }
            }

            if (hasMethod) {
                c3.append(" } catch(Throwable e) { ");
                c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
                c3.append(" }");
            }

            c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
            Iterator i$ = ms.entrySet().iterator();

            while(i$.hasNext()) {
                Entry<String, Method> entry = (Entry)i$.next();
                String md = (String)entry.getKey();
                Method method = (Method)entry.getValue();
                Matcher matcher;
                String pn;
                if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                    pn = propertyName(matcher.group(1));
                    c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
                    pts.put(pn, method.getReturnType());
                } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                    pn = propertyName(matcher.group(1));
                    c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
                    pts.put(pn, method.getReturnType());
                } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
                    Class<?> pt = method.getParameterTypes()[0];
                    String pn = propertyName(matcher.group(1));
                    c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
                    pts.put(pn, pt);
                }
            }

            c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
            c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
            long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
            ClassGenerator cc = ClassGenerator.newInstance(cl);
            cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
            cc.setSuperClass(Wrapper.class);
            cc.addDefaultConstructor();
            cc.addField("public static String[] pns;");
            cc.addField("public static " + Map.class.getName() + " pts;");
            cc.addField("public static String[] mns;");
            cc.addField("public static String[] dmns;");
            int i = 0;

            for(ix = ms.size(); i < ix; ++i) {
                cc.addField("public static Class[] mts" + i + ";");
            }

            cc.addMethod("public String[] getPropertyNames(){ return pns; }");
            cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
            cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
            cc.addMethod("public String[] getMethodNames(){ return mns; }");
            cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
            cc.addMethod(c1.toString());
            cc.addMethod(c2.toString());
            cc.addMethod(c3.toString());

            try {
            		// 代理生成类,dubbo自身的动态代理,在此步骤将会发生异常
                Class<?> wc = cc.toClass();
                wc.getField("pts").set((Object)null, pts);
                wc.getField("pns").set((Object)null, pts.keySet().toArray(new String[0]));
                wc.getField("mns").set((Object)null, mns.toArray(new String[0]));
                wc.getField("dmns").set((Object)null, dmns.toArray(new String[0]));
                ix = 0;
                Iterator i$ = ms.values().iterator();

                while(i$.hasNext()) {
                    Method m = (Method)i$.next();
                    wc.getField("mts" + ix++).set((Object)null, m.getParameterTypes());
                }

                Wrapper var50 = (Wrapper)wc.newInstance();
                return var50;
            } catch (RuntimeException var27) {
                throw var27;
            } catch (Throwable var28) {
                throw new RuntimeException(var28.getMessage(), var28);
            } finally {
                cc.release();
                ms.clear();
                mns.clear();
                dmns.clear();
            }
        }
    }

2.4 dubbo自身使用javassist来生成相关的动态类,用来代理真实的方法,我们定位到异常栈发生异常的方法,接下来我们主要关注targetClass从那里获取的,并且为什么没有setSkyWalkingDynamicField(java.lang.Object) 这个方法。

javassist.compiler.TypeChecker#atMethodCallCore:
	public Method atMethodCallCore(CtClass targetClass, String mname, ASTList args) throws CompileError {
        int nargs = this.getMethodArgsLength(args);
        int[] types = new int[nargs];
        int[] dims = new int[nargs];
        String[] cnames = new String[nargs];
        this.atMethodArgs(args, types, dims, cnames);
        Method found = this.resolver.lookupMethod(targetClass, this.thisClass, this.thisMethod, mname, types, dims, cnames);
        String clazz;
        if (found == null) {
            clazz = targetClass.getName();
            String signature = argTypesToString(types, dims, cnames);
            String msg;
            if (mname.equals("<init>")) {
                msg = "cannot find constructor " + clazz + signature;
            } else {
                msg = mname + signature + " not found in " + clazz;
            }

            throw new CompileError(msg);
        } else {
            clazz = found.info.getDescriptor();
            this.setReturnType(clazz);
            return found;
        }
    }

lookupMethod相关逻辑如下,可以看到是通过解析classFile来实现的:

private MemberResolver.Method lookupMethod(CtClass clazz, String methodName, int[] argTypes, int[] argDims, String[] argClassNames, boolean onlyExact) throws CompileError {
        MemberResolver.Method maybe = null;
        ClassFile cf = clazz.getClassFile2();
        int i;
        MemberResolver.Method r;
        if (cf != null) {
            List list = cf.getMethods();
            int n = list.size();

            for(int i = 0; i < n; ++i) {
                MethodInfo minfo = (MethodInfo)list.get(i);
                if (minfo.getName().equals(methodName) && (minfo.getAccessFlags() & 64) == 0) {
                    i = this.compareSignature(minfo.getDescriptor(), argTypes, argDims, argClassNames);
                    if (i != -1) {
                        r = new MemberResolver.Method(clazz, minfo, i);
                        if (i == 0) {
                            return r;
                        }

                        if (maybe == null || maybe.notmatch > i) {
                            maybe = r;
                        }
                    }
                }
            }
        }

        if (onlyExact) {
            maybe = null;
        } else if (maybe != null) {
            return maybe;
        }

        int mod = clazz.getModifiers();
        boolean isIntf = Modifier.isInterface(mod);

        try {
            if (!isIntf) {
                CtClass pclazz = clazz.getSuperclass();
                if (pclazz != null) {
                    MemberResolver.Method r = this.lookupMethod(pclazz, methodName, argTypes, argDims, argClassNames, onlyExact);
                    if (r != null) {
                        return r;
                    }
                }
            }
        } catch (NotFoundException var15) {
        }

        try {
            CtClass[] ifs = clazz.getInterfaces();
            int size = ifs.length;

            for(i = 0; i < size; ++i) {
                r = this.lookupMethod(ifs[i], methodName, argTypes, argDims, argClassNames, onlyExact);
                if (r != null) {
                    return r;
                }
            }

            if (isIntf) {
                CtClass pclazz = clazz.getSuperclass();
                if (pclazz != null) {
                    r = this.lookupMethod(pclazz, methodName, argTypes, argDims, argClassNames, onlyExact);
                    if (r != null) {
                        return r;
                    }
                }
            }
        } catch (NotFoundException var16) {
        }

        return maybe;
    }

于是我们把定位targetClass,转换为了classfile从何而来,最终定位到targetClass来源于javassist.ClassPool#createCtClass,,在创建CtClass时调用了如下构造函数,但是这里面的classfile并没有被赋值,但是在该类的父类中存在getClassFile方法,并在该方法中返回this.getClassFile2(),通过getClassFile2()相关的逻辑我们知道了classfile最终来源于读取了classpath下的类源码文件,而在该源码中肯定是不存在和SkyWalking相关的代码。

javassist.CtClassType:
	CtClassType(String name, ClassPool cp) {
        super(name);
        this.doPruning = ClassPool.doPruning;
        this.classPool = cp;
        this.wasChanged = this.wasFrozen = this.wasPruned = this.gcConstPool = false;
        this.classfile = null;
        this.rawClassfile = null;
        this.memberCache = null;
        this.accessors = null;
        this.fieldInitializers = null;
        this.hiddenMethods = null;
        this.uniqueNumberSeed = 0;
        this.getCount = 0;
    }
    
    public ClassFile getClassFile2() {
        return this.getClassFile3(true);
    }

    public ClassFile getClassFile3(boolean doCompress) {
        ClassFile cfile = this.classfile;
        if (cfile != null) {
            return cfile;
        } else {
            if (doCompress) {
                this.classPool.compress();
            }

            if (this.rawClassfile != null) {
                try {
                    ClassFile cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(this.rawClassfile)));
                    this.rawClassfile = null;
                    this.getCount = 2;
                    return this.setClassFile(cf);
                } catch (IOException var16) {
                    throw new RuntimeException(var16.toString(), var16);
                }
            } else {
                Object fin = null;

                ClassFile var5;
                try {
                    fin = this.classPool.openClassfile(this.getName());
                    if (fin == null) {
                        throw new NotFoundException(this.getName());
                    }

                    fin = new BufferedInputStream((InputStream)fin);
                    ClassFile cf = new ClassFile(new DataInputStream((InputStream)fin));
                    if (!cf.getName().equals(this.qualifiedName)) {
                        throw new RuntimeException("cannot find " + this.qualifiedName + ": " + cf.getName() + " found in " + this.qualifiedName.replace('.', '/') + ".class");
                    }

                    var5 = this.setClassFile(cf);
                } catch (NotFoundException var17) {
                    throw new RuntimeException(var17.toString(), var17);
                } catch (IOException var18) {
                    throw new RuntimeException(var18.toString(), var18);
                } finally {
                    if (fin != null) {
                        try {
                            ((InputStream)fin).close();
                        } catch (IOException var15) {
                        }
                    }

                }

                return var5;
            }
        }
    }

问题解决:

Dubbo这种在代理时通过反射获取方法然后在生成类时的逻辑有些问题,在反射时获取的方法有可能是增强后的,有可能多添加方法,但是在生成类时却获取了原字节码文件中的方法,导致javassist生成类时字节码校验失败。

修复办法:

1.修改dubbo源码com.alibaba.dubbo.common.bytecode.Wrapper#makeWrapper逻辑,在通过javassist获取源文件中的方法,和最终的生成、校验逻辑一致。

2.其他办法暂时还没有...

@codecov-io
Copy link

codecov-io commented Apr 8, 2021

Codecov Report

Merging #7517 (322d072) into master (6055932) will decrease coverage by 0.38%.
The diff coverage is 84.61%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #7517      +/-   ##
============================================
- Coverage     59.24%   58.86%   -0.39%     
+ Complexity      503      500       -3     
============================================
  Files          1079     1079              
  Lines         43385    43350      -35     
  Branches       6329     6297      -32     
============================================
- Hits          25704    25516     -188     
- Misses        14842    14989     +147     
- Partials       2839     2845       +6     
Impacted Files Coverage Δ Complexity Δ
...java/org/apache/dubbo/common/bytecode/Wrapper.java 82.58% <84.61%> (+0.04%) 0.00 <0.00> (ø)
...a/org/apache/dubbo/rpc/filter/AccessLogFilter.java 26.86% <0.00%> (-52.24%) 0.00% <0.00%> (ø%)
...va/org/apache/dubbo/rpc/support/AccessLogData.java 53.16% <0.00%> (-37.98%) 0.00% <0.00%> (ø%)
...ng/transport/dispatcher/all/AllChannelHandler.java 62.06% <0.00%> (-34.49%) 0.00% <0.00%> (ø%)
...bbo/common/bytecode/CustomizedLoaderClassPath.java 28.00% <0.00%> (-16.00%) 0.00% <0.00%> (ø%)
...rg/apache/dubbo/remoting/utils/PayloadDropper.java 76.92% <0.00%> (-15.39%) 0.00% <0.00%> (ø%)
...ng/transport/dispatcher/WrappedChannelHandler.java 47.82% <0.00%> (-15.22%) 0.00% <0.00%> (ø%)
...bo/rpc/cluster/support/FailbackClusterInvoker.java 52.45% <0.00%> (-14.76%) 0.00% <0.00%> (ø%)
.../remoting/transport/netty4/NettyClientHandler.java 72.88% <0.00%> (-13.56%) 0.00% <0.00%> (ø%)
...dubbo/common/status/support/LoadStatusChecker.java 50.00% <0.00%> (-11.54%) 0.00% <0.00%> (ø%)
... and 48 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6055932...322d072. Read the comment docs.

@kimmking kimmking merged commit 68062c1 into apache:master Apr 27, 2021
goodjava pushed a commit to WZD-MI/incubator-dubbo that referenced this pull request May 6, 2021
…ound` (apache#7517)

* Fix `setSkyWalkingDynamicField(java.lang.Object) not found`

* Polishing.

* Polishing.

* Polishing.
AlbumenJ added a commit to AlbumenJ/dubbo that referenced this pull request May 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants