问题(十九)JavaAgent-ByteBuddy与CGLIB字节码增强冲突问题
一、引言
其他团队在使用作者的性能分析组件时发生了发布阻塞
二、排查
1、arthas
通过arthas thread -b分析阻塞问题
"localhost-startStop-1" Id=94 WAITING on qunar.tc.qconfig.client.impl.AbstractConfiguration$InitFuture@75152c62
at sun.misc.Unsafe.park(Native Method)
- waiting on qunar.tc.qconfig.client.impl.AbstractConfiguration$InitFuture@75152c62
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:557)
at qunar.tc.qconfig.client.impl.AbstractConfiguration.waitFistLoad(AbstractConfiguration.java:77)
at qunar.tc.qconfig.client.JsonConfig.current(JsonConfig.java:79)
at com.**.helper.ProfilerConfig.getAgentCo(ProfilerConfig.java:35)
at com.**.action.MethodProfilerActionImpl.onMethodEnter(MethodProfilerActionImpl.java:21)
at com.**.service.config.TransactionConfig$$EnhancerBySpringCGLIB$$11b95d25.CGLIB$STATICHOOK2(<generated>)
at com.**.service.config.TransactionConfig$$EnhancerBySpringCGLIB$$11b95d25.<clinit>(<generated>)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:415)
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336)
- locked org.apache.catalina.loader.WebappClassLoader@5e30c4e3 <---- but blocks 5 other threads!
at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:492)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:93)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:91)
at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:337)
at org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(ConfigurationClassEnhancer.java:135)
at org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(ConfigurationClassEnhancer.java:107)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:409)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:266)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:281)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:125)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:686)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:524)
- locked java.lang.Object@31c06725
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5157)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5680)
- locked org.apache.catalina.core.StandardContext@4ab60688
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
- locked org.apache.catalina.core.StandardContext@4ab60688
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1707)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1697)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@1a09ced8
看这个堆栈一开始的怀疑方向是qconfig问题,因为显示是阻塞在qconfig异步获取文件内容的地方
2、本地debug
但是在本地进行启动的时候可以看到这段加载配置的代码是跑过去的
这里有个误解:
@Service和@Autowired都会导致spring生成代理类
其实并不是的,通过本地生成的class也可以看到是没有生成代理类的,他们是用于自动装配 Spring 应用上下文中的 Bean
如果做了切面注解,而且不是使用jdk动态代理,cglib是才会生成子类增强,而TransactionConfig这个类就是会生成子类的,也就是说本地启动应该也是会切入这个cglib增强类
这就有点奇怪了,本地不影响但是测试环境就会阻塞
但是首先解决问题,再分析原理
三、解决
1、IgnoredTypesMatcher
通过extends ElementMatcher.Junction.AbstractBase<TypeDescription>
bytebuddy的忽略配置,识别哪些路径的类需要忽略
但是经过测试没有实现把EnhancerBySpringCGLIB忽略掉
@Override
public boolean matches(TypeDescription target) {
if (target.isSynthetic()) {
return true;
}
String name = target.getActualName();
for (String ignored : IGNORED_STARTS_WITH_NAME) {
if (name.startsWith(ignored)) {
return true;
}
}
for (String ignored : IGNORED_CONTAINS_NAME) {
if (name.contains(ignored)) {
return true;
}
}
return false;
}
2、InnerTransformer
这个过滤是针对方法的,一开始还以为会过滤掉包含的类
private static class InnerTransformer implements AgentBuilder.Transformer {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module, ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(MethodServiceAdvice.class)
.on(ElementMatchers.not(ElementMatchers.isConstructor())
.and(ElementMatchers
.noneOf(ElementMatchers.hasSuperType(ElementMatchers.named("StaticApplicationContext"))))
.and(ElementMatchers.not(ElementMatchers.isTypeInitializer()))
.and(ElementMatchers.not(ElementMatchers.isSetter()))
.and(ElementMatchers.not(ElementMatchers.isGetter()))
.and(ElementMatchers.not(ElementMatchers.nameStartsWith("net.bytebuddy.generated")))
.and(ElementMatchers.not(ElementMatchers.nameContains("EnhancerBySpringCGLIB")))
.and(ElementMatchers.not(ElementMatchers.nameContains("FastClassByCGLIB")))
.and(ElementMatchers.not(ElementMatchers.nameContains("MethodInterceptor")))));
}
}
3、ElementMatcher.Junction
直接在识别哪些类需要增强的地方忽略cglib生成的子类
这个方案是成功的,同时也说明了是因为我们的agent捕获了cglib增强过的子类,才导致代码问题
private static final String[] IGNORED_CONTAINS_NAME = new String[] {"EnhancerBySpringCGLIB", "EnhancerByCGLIB"};
for (String i : IGNORED_CONTAINS_NAME) {
namedElementJunction = namedElementJunction.and(ElementMatchers.not(ElementMatchers.nameContains(i)));
}
四、原理解析
这里面其实存在几个问题:
1、增强是进行代码环绕,为什么会触发agent的执行?
2、即使是切入了cglib生成的子类会有问题,但是为什么会是卡在AbstractFuture的异步get?
3、为什么本地没有问题,但是测试环境就会卡住?
先看第一个问题,按照道理来说这时候只是会在方法的前后增加一段代码,为什么会执行agent里面的代码
再看看堆栈
TransactionConfig$$EnhancerBySpringCGLIB$$11b95d25.CGLIB$STATICHOOK2(<generated>)
at com.ctrip.corp.fareresource.service.service.config.TransactionConfig$$EnhancerBySpringCGLIB$$11b95d25.<clinit>(<generated>
出现问题的源头代码是clinit方法,这是类初始化阶段会执行的代码
在clinit里面主要就是执行方法的static静态块,还有静态代码的赋值,那我们看看bytebuddy增强cglib的代码到底是什么样
可以看到静态块里面会执行这些方法
static { ClassLoader.getSystemClassLoader().loadClass("shaded.corpprofiler.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.forName("java.lang.Class"), Integer.TYPE).invoke((Object)null, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa"), -618929103); CGLIB$STATICHOOK2(); CGLIB$STATICHOOK1(); }
而这些方法已经被bytebuddy环绕了我们agent的逻辑
ProfilerAction var0 = LogActionHolder.getLogAction("com.**.action.MethodProfilerActionImpl"); if (Objects.nonNull(var0)) { var10000 = var0.onMethodEnter(new Object[0], Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$STATICHOOK1"), false); break label43; }
所以第一个问题就清晰了,虽然只是代码环绕,但是被编织进入了cglib增强类的静态块里面
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.ctrip.corp.intlflight.search.config;
import com.**.agent.bootstrap.LogActionHolder;
import com.**.agent.bootstrap.ProfilerAction;
import com.c**.agent.bootstrap.bo.MethodArg;
import java.lang.reflect.Method;
import java.util.Objects;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
public class StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa extends StaticApplicationContext implements EnhancedConfiguration {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private NoOp CGLIB$CALLBACK_2;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$setBeanFactory$5$Method;
private static final MethodProxy CGLIB$setBeanFactory$5$Proxy;
private static final Object[] CGLIB$emptyArgs;
public BeanFactory $$beanFactory;
static void CGLIB$STATICHOOK1() {
MethodArg var10000;
label43: {
try {
ProfilerAction var0 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var0)) {
var10000 = var0.onMethodEnter(new Object[0], Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$STATICHOOK1"), false);
break label43;
}
} catch (Throwable var7) {
System.out.println("MethodServiceAdvice error" + var7);
}
var10000 = null;
}
MethodArg var8 = var10000;
Throwable var1;
label37: {
try {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var9 = Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa");
Class var2;
CGLIB$setBeanFactory$5$Method = ReflectUtils.findMethods(new String[]{"setBeanFactory", "(Lorg/springframework/beans/factory/BeanFactory;)V"}, (var2 = Class.forName("org.springframework.beans.factory.BeanFactoryAware")).getDeclaredMethods())[0];
CGLIB$setBeanFactory$5$Proxy = MethodProxy.create(var2, var9, "(Lorg/springframework/beans/factory/BeanFactory;)V", "setBeanFactory", "CGLIB$setBeanFactory$5");
} catch (Throwable var6) {
var1 = var6;
break label37;
}
var1 = null;
}
try {
try {
ProfilerAction var10 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var10)) {
var10.onMethodExit(new Object[0], Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$STATICHOOK1"), var8, false);
}
} catch (Throwable var4) {
System.out.println("MethodServiceAdvice error" + var4);
}
} catch (Throwable var5) {
}
if (var1 != null) {
throw var1;
}
}
final void CGLIB$setBeanFactory$5(BeanFactory var1) throws BeansException {
MethodArg var10000;
label42: {
try {
ProfilerAction var2 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var2)) {
var10000 = var2.onMethodEnter(new Object[]{var1}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$setBeanFactory$5", Class.forName("org.springframework.beans.factory.BeanFactory")), false);
break label42;
}
} catch (Throwable var10) {
System.out.println("MethodServiceAdvice error" + var10);
}
var10000 = null;
}
MethodArg var11 = var10000;
StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa var3 = this;
BeanFactory var4 = var1;
Throwable var12;
label36: {
try {
var3.setBeanFactory(var4);
} catch (Throwable var9) {
var12 = var9;
break label36;
}
var12 = null;
}
try {
try {
ProfilerAction var13 = LogActionHolder.getLogAction("com.**.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var13)) {
var13.onMethodExit(new Object[]{var1}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$setBeanFactory$5", Class.forName("org.springframework.beans.factory.BeanFactory")), var11, false);
}
} catch (Throwable var7) {
System.out.println("MethodServiceAdvice error" + var7);
}
} catch (Throwable var8) {
}
if (var12 != null) {
throw var12;
}
}
public final void setBeanFactory(BeanFactory var1) throws BeansException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$setBeanFactory$5$Method, new Object[]{var1}, CGLIB$setBeanFactory$5$Proxy);
} else {
super.setBeanFactory(var1);
}
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
MethodArg var10000;
label50: {
try {
ProfilerAction var1 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var1)) {
var10000 = var1.onMethodEnter(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getMethod("CGLIB$findMethodProxy", Class.forName("org.springframework.cglib.core.Signature")), false);
break label50;
}
} catch (Throwable var9) {
System.out.println("MethodServiceAdvice error" + var9);
}
var10000 = null;
}
MethodArg var10 = var10000;
Signature var2 = var0;
Throwable var3;
MethodProxy var11;
label44: {
MethodProxy var13;
try {
label41: {
String var12 = var2.toString();
switch(var12.hashCode()) {
case 2095635076:
if (var12.equals("setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;)V")) {
var13 = CGLIB$setBeanFactory$5$Proxy;
break label41;
}
}
var13 = null;
}
} catch (Throwable var8) {
var3 = var8;
var11 = null;
break label44;
}
var11 = var13;
var3 = null;
}
try {
try {
ProfilerAction var4 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var4)) {
var4.onMethodExit(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getMethod("CGLIB$findMethodProxy", Class.forName("org.springframework.cglib.core.Signature")), var10, false);
}
} catch (Throwable var6) {
System.out.println("MethodServiceAdvice error" + var6);
}
} catch (Throwable var7) {
}
if (var3 != null) {
throw var3;
} else {
return var11;
}
}
public StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
MethodArg var10000;
label42: {
try {
ProfilerAction var1 = LogActionHolder.getLogAction("com.**.action.MethodProfilerActionImpl");
if (Objects.nonNull(var1)) {
var10000 = var1.onMethodEnter(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getMethod("CGLIB$SET_THREAD_CALLBACKS", Class.forName("[Lorg.springframework.cglib.proxy.Callback;")), false);
break label42;
}
} catch (Throwable var8) {
System.out.println("MethodServiceAdvice error" + var8);
}
var10000 = null;
}
MethodArg var9 = var10000;
Callback[] var2 = var0;
Throwable var10;
label36: {
try {
CGLIB$THREAD_CALLBACKS.set(var2);
} catch (Throwable var7) {
var10 = var7;
break label36;
}
var10 = null;
}
try {
try {
ProfilerAction var3 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var3)) {
var3.onMethodExit(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getMethod("CGLIB$SET_THREAD_CALLBACKS", Class.forName("[Lorg.springframework.cglib.proxy.Callback;")), var9, false);
}
} catch (Throwable var5) {
System.out.println("MethodServiceAdvice error" + var5);
}
} catch (Throwable var6) {
}
if (var10 != null) {
throw var10;
}
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
MethodArg var10000;
label42: {
try {
ProfilerAction var1 = LogActionHolder.getLogAction("com.**.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var1)) {
var10000 = var1.onMethodEnter(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getMethod("CGLIB$SET_STATIC_CALLBACKS", Class.forName("[Lorg.springframework.cglib.proxy.Callback;")), false);
break label42;
}
} catch (Throwable var8) {
System.out.println("MethodServiceAdvice error" + var8);
}
var10000 = null;
}
MethodArg var9 = var10000;
Callback[] var2 = var0;
Throwable var10;
label36: {
try {
CGLIB$STATIC_CALLBACKS = var2;
} catch (Throwable var7) {
var10 = var7;
break label36;
}
var10 = null;
}
try {
try {
ProfilerAction var3 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var3)) {
var3.onMethodExit(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getMethod("CGLIB$SET_STATIC_CALLBACKS", Class.forName("[Lorg.springframework.cglib.proxy.Callback;")), var9, false);
}
} catch (Throwable var5) {
System.out.println("MethodServiceAdvice error" + var5);
}
} catch (Throwable var6) {
}
if (var10 != null) {
throw var10;
}
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
MethodArg var10000;
label53: {
try {
ProfilerAction var1 = LogActionHolder.getLogAction("com.**.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var1)) {
var10000 = var1.onMethodEnter(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$BIND_CALLBACKS", Class.forName("java.lang.Object")), false);
break label53;
}
} catch (Throwable var8) {
System.out.println("MethodServiceAdvice error" + var8);
}
var10000 = null;
}
MethodArg var9 = var10000;
Object var2 = var0;
Throwable var10;
label47: {
try {
StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa var3 = (StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa)var2;
if (!var3.CGLIB$BOUND) {
label57: {
var3.CGLIB$BOUND = true;
Object var12 = CGLIB$THREAD_CALLBACKS.get();
if (var12 == null) {
var12 = CGLIB$STATIC_CALLBACKS;
if (var12 == null) {
break label57;
}
}
Callback[] var10001 = (Callback[])var12;
var3.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var12)[2];
var3.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
var3.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];
}
}
} catch (Throwable var7) {
var10 = var7;
break label47;
}
var10 = null;
}
try {
try {
ProfilerAction var11 = LogActionHolder.getLogAction("com.**.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var11)) {
var11.onMethodExit(new Object[]{var0}, Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$BIND_CALLBACKS", Class.forName("java.lang.Object")), var9, false);
}
} catch (Throwable var5) {
System.out.println("MethodServiceAdvice error" + var5);
}
} catch (Throwable var6) {
}
if (var10 != null) {
throw var10;
}
}
static {
ClassLoader.getSystemClassLoader().loadClass("shaded.corpprofiler.net.bytebuddy.dynamic.Nexus").getMethod("initialize", Class.forName("java.lang.Class"), Integer.TYPE).invoke((Object)null, Class.forName("com.**g.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa"), -618929103);
CGLIB$STATICHOOK2();
CGLIB$STATICHOOK1();
}
static void CGLIB$STATICHOOK2() {
MethodArg var10000;
label37: {
try {
ProfilerAction var0 = LogActionHolder.getLogAction("com.**.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var0)) {
var10000 = var0.onMethodEnter(new Object[0], Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$STATICHOOK2"), false);
break label37;
}
} catch (Throwable var5) {
System.out.println("MethodServiceAdvice error" + var5);
}
var10000 = null;
}
MethodArg var6 = var10000;
Object var1 = null;
try {
try {
ProfilerAction var2 = LogActionHolder.getLogAction("com.ctrip.corp.profiler.agent.instrumentation.action.MethodProfilerActionImpl");
if (Objects.nonNull(var2)) {
var2.onMethodExit(new Object[0], Class.forName("com.**.StaticApplicationContext$$EnhancerBySpringCGLIB$$2d3e27aa").getDeclaredMethod("CGLIB$STATICHOOK2"), var6, false);
}
} catch (Throwable var3) {
System.out.println("MethodServiceAdvice error" + var3);
}
} catch (Throwable var4) {
}
if (var1 != null) {
throw var1;
}
}
}
第二个问题,qconfig框架人员配合查了一下日志,但是这时候有一个有趣的现象,网络请求没有发出,但是获取结果的异步代码temp.current()已经执行
这是一个很奇怪的现象,就好像少执行了一段代码一样,但是代码是不会少执行的,只有可能是网络请求没有发出
作者又试了一下,然后把配置执行的所有等级文件都拿出来看,有一条显示远程文件已经拉取到本地了,这说明也不是网络请求没有发出,应该是qconfig的人看错了
这样看起来第二个问题也清晰了,他卡在AbstractFuture的异步get并不是因为配置中心的数据一致没有拉取到,而是因为卡在了LockSupport.park(this),锁住this的时候由于this已经被主线程锁住,但是主线程又在等待这个异步get,造成死锁
public V get() throws InterruptedException, ExecutionException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
Object localValue = value;
if (localValue != null & !(localValue instanceof SetFuture)) {
return getDoneValue(localValue);
}
Waiter oldHead = waiters;
if (oldHead != Waiter.TOMBSTONE) {
Waiter node = new Waiter();
do {
node.setNext(oldHead);
if (ATOMIC_HELPER.casWaiters(this, oldHead, node)) {
// we are on the stack, now wait for completion.
while (true) {
LockSupport.park(this);
// Check interruption first, if we woke up due to interruption we need to honor that.
if (Thread.interrupted()) {
removeWaiter(node);
throw new InterruptedException();
}
// Otherwise re-read and check doneness. If we loop then it must have been a spurious
// wakeup
localValue = value;
if (localValue != null & !(localValue instanceof SetFuture)) {
return getDoneValue(localValue);
}
}
}
oldHead = waiters; // re-read and loop.
} while (oldHead != Waiter.TOMBSTONE);
}
// re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a
// waiter.
// requireNonNull is safe because value is always set before TOMBSTONE.
return getDoneValue(requireNonNull(value));
}
String appId = Foundation.app().getAppId();
JsonConfig<AgentCo> temp = JsonConfig.get(ProfilerConstant.CORP_PROFILER_CONFIG,
appId + ProfilerConstant.UNDER_LINE + ProfilerConstant.AGENT_JSON, Feature.DEFAULT, AgentCo.class);
temp.addListener(agentCo1 -> agentCo = handleAgentCo(agentCo1));
agentCo = handleAgentCo(temp.current());
接下来唯一有疑问的是为什么本地环境不会卡在这个死锁层级上面?
作者的想法是测试环境其他组件也在增强cglib的子类,在锁住增强的过程中执行了static,触发了作者的性能分析agent执行,所以导致其他组件锁住子类,等待子类的static执行完成,static里面性能分析又在等待LockSupport.park(this),造成死锁,进程卡住
五、总结
javaagent这种方式就是会遇到各种包冲突、类冲突的问题,需要不断去适配,这个过程还是比较复杂的,没有实际开发经验很难理解
但是大家还是可以尝试去研究,不理解的可以和作者交流,因为这对于java的底层了解是很有帮助的,而且这是一种非常省人力的开发方式,无侵入的特性决定了其他人都不需要开发,可谓是悲催你一个、幸福其他人!