skywalking agent 启动类源码分析,ByteBuddy的应用例子
本文主要介绍了skywalking agent启动类源码及Byte Buddy 简单应用
Byte Buddy 应用demo
skywalking agent 主要是在类加载之前通过Byte Buddy api 对类字节码文件进行修改(增强),从而完成对各种组件的链路跟踪。
文章目录
前言
Byte Buddy 官方地址 [https://bytebuddy.net/#/tutorial]
(https://bytebuddy.net/#/tutorial)
中文翻译地址https://notes.diguage.com/byte-buddy-tutorial/
一、Byte Buddy在skywalking中的应用
1.agent(本文基于skywalking 8.7)
启动类:SkyWalkingAgent#premain
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
final PluginFinder pluginFinder;
try {
SnifferConfigInitializer.initializeCoreConfig(agentArgs);
} catch (Exception e) {
// try to resolve a new logger, and use the new logger to write the error log here
LogManager.getLogger(SkyWalkingAgent.class)
.error(e, "SkyWalking agent initialized failure. Shutting down.");
return;
} finally {
// refresh logger again after initialization finishes
LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
}
try {
pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
} catch (AgentPackageNotFoundException ape) {
LOGGER.error(ape, "Locate agent.jar failure. Shutting down.");
return;
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent initialized failure. Shutting down.");
return;
}
//实例化ByteBuddy
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
//创建agentBulid
AgentBuilder agentBuilder = new AgentBuilder.Default(byteBuddy).ignore(
nameStartsWith("net.bytebuddy.")
.or(nameStartsWith("org.slf4j."))
.or(nameStartsWith("org.groovy."))
.or(nameContains("javassist"))
.or(nameContains(".asm."))
.or(nameContains(".reflectasm."))
.or(nameStartsWith("sun.reflect"))
.or(allSkyWalkingAgentExcludeToolkit())
.or(ElementMatchers.isSynthetic()));
JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
try {
agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
return;
}
try {
agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down.");
return;
}
if (Config.Agent.IS_CACHE_ENHANCED_CLASS) {
try {
agentBuilder = agentBuilder.with(new CacheableTransformerDecorator(Config.Agent.CLASS_CACHE_MODE));
LOGGER.info("SkyWalking agent class cache [{}] activated.", Config.Agent.CLASS_CACHE_MODE);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent can't active class cache.");
}
}
agentBuilder.type(pluginFinder.buildMatch())//指定需要拦截的类
//分析(1)
.transform(new Transformer(pluginFinder))//各种插桩实现、字节码增强流程、改字节码
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)//是否保留修改前内容
.with(new RedefinitionListener())
.with(new Listener())
.installOn(instrumentation);
try {
ServiceManager.INSTANCE.boot();
} catch (Exception e) {
LOGGER.error(e, "Skywalking agent boot failure.");
}
Runtime.getRuntime()
.addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
}
分析(1)
transform 主要讲述字节码插桩的流程,点击transform可以看到增强的具体实现
如下:
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder, //当前拦截到类的字节码
final TypeDescription typeDescription, //类的描述信息
final ClassLoader classLoader, 加载当前拦截到类的类加载器
final JavaModule module) {
LoadedLibraryCollector.registerURLClassLoader(classLoader);
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
if (pluginDefines.size() > 0) {
DynamicType.Builder<?> newBuilder = builder;
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
//分析(1)define为字节码插桩的核心实现
DynamicType.Builder<?> possibleNewBuilder = define.define(
typeDescription, newBuilder, classLoader, context);
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
if (context.isEnhanced()) {
LOGGER.debug("Finish the prepare stage for {}.", typeDescription.getName());
}
return newBuilder;
}
LOGGER.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());
return builder;
}
分析(1)
#define 方法具体的插桩实现,进入define类中,我们只看他的enhance方法
/**
* find origin class source code for interceptor
*/
DynamicType.Builder<?> newClassBuilder = this.enhance(typeDescription, builder, classLoader, context);
context.initializationStageCompleted();
LOGGER.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder;
protected DynamicType.Builder<?> enhance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,
ClassLoader classLoader, EnhanceContext context) throws PluginException {
newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader);
newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context);
return newClassBuilder;
}
enhance 方法里面包含了两种增强类型,一种是增强,另一种是增强实例方法,我们只看增强类enhanceClass。点击enhanceClass
/**
* Enhance a class to intercept class static methods.
*
* @param typeDescription target class description
* @param newClassBuilder byte-buddy's builder to manipulate class bytecode.
* @return new byte-buddy's builder for further manipulation.
*/
protected DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,
ClassLoader classLoader) throws PluginException {
//(1)获取所有插件的静态方法拦截点
StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
String enhanceOriginClassName = typeDescription.getTypeName();
if (staticMethodsInterceptPoints == null || staticMethodsInterceptPoints.length == 0) {
return newClassBuilder;
}
//循环所有拦截点选择不同环绕增强方式。
for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) {
String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor();
if (StringUtil.isEmpty(interceptor)) {
throw new EnhanceException("no StaticMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName);
}
//带参数的增强方式
if (staticMethodsInterceptPoint.isOverrideArgs()) {
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(new StaticMethodsInterWithOverrideArgs(interceptor)));
}
} else {
//不带参数的增强方式数据JDK类库的
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
//不属于JDK类库的类增强方式
} else {
//(2)静态方法插桩
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(new StaticMethodsInter(interceptor)));
}
}
}
return newClassBuilder;
}
分析
(1)点击#getStaticMethodsInterceptPoints可以看到具体的插件拦截定义类
任意点击进去都可以看到具体的拦截类和需要拦截方法。
(2)点击#StaticMethodsInter可以看到具体的拦截实现方法,这里也是环绕增强的步骤所在。可以看出对类的方法前和方法后的操作。
@RuntimeType
public Object intercept(@Origin Class<?> clazz, @AllArguments Object[] allArguments, @Origin Method method,
@SuperCall Callable<?> zuper) throws Throwable {
StaticMethodsAroundInterceptor interceptor = InterceptorInstanceLoader.load(staticMethodsAroundInterceptorClassName, clazz
.getClassLoader());
MethodInterceptResult result = new MethodInterceptResult();
try {
interceptor.beforeMethod(clazz, method, allArguments, method.getParameterTypes(), result);
} catch (Throwable t) {
LOGGER.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName());
}
Object ret = null;
try {
if (!result.isContinue()) {
ret = result._ret();
} else {
ret = zuper.call();
}
} catch (Throwable t) {
try {
interceptor.handleMethodException(clazz, method, allArguments, method.getParameterTypes(), t);
} catch (Throwable t2) {
LOGGER.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage());
}
throw t;
} finally {
try {
ret = interceptor.afterMethod(clazz, method, allArguments, method.getParameterTypes(), ret);
} catch (Throwable t) {
LOGGER.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage());
}
}
return ret;
}
以上就是Byte Buddy在skywalking agent中的部分应用,另外还有其他几种增强方式这里就不做具体介绍。
二、Byte Buddy例子
1.agent端
首先新建任意maven 工程
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.9.2</version>
</dependency>
代码如下
新建代理接口:
public interface InstMethodAroundInterceptor {
/**
* 拦截点前
* @param inst: 被增强类实例
* @param interceptPoint:被增强方法
* @param allArguments:被增强方法入参
* @param argumentsTypes:被增强方法入参类型
* @param result:result 包装类
*/
void beforeMethod(Object inst, Method interceptPoint,
Object[] allArguments, Class<?>[] argumentsTypes,
EnhanceTemplate.ResultWrapper result);
Object afterMethod(Object inst, Method interceptPoint,
Object[] allArguments, Class<?>[] argumentsTypes,
Object ret);
void handleMethodException(Object inst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t);
}
然后建立具体实现类
public class ServiceInterceptor implements InstMethodAroundInterceptor {
@Override
public void beforeMethod(Object inst, Method interceptPoint, Object[] allArguments,
Class<?>[] argumentsTypes, EnhanceTemplate.ResultWrapper result) {
System.out.println("Service Interceptor before ..." + System.currentTimeMillis());
}
@Override
public Object afterMethod(Object inst, Method interceptPoint, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) {
System.out.println("Service Interceptor after ..." + System.currentTimeMillis());
return ret;
}
@Override
public void handleMethodException(Object inst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
System.out.println("Service Interceptor error handle ...");
}
}
之后建立环绕增强类
public class EnhanceTemplate {
private InstMethodAroundInterceptor interceptor;
public EnhanceTemplate(InstMethodAroundInterceptor interceptor) {
this.interceptor = interceptor;
}
/**
* 拦截增强主方法
*
* @param inst: 被拦截对象本身
* @param allArguments:被代理方法原参数
* @param zuper:被代理方法的包装对象,zuper.call()调用原方法
* @param method:原方法对象
* @return
*/
@RuntimeType
public Object interceptor(@This Object inst, @AllArguments Object[] allArguments,
@SuperCall Callable<?> zuper, @Origin Method method) {
ResultWrapper rw = new ResultWrapper();
if (this.interceptor != null) {
try {
// 调用前拦截处理
this.interceptor.beforeMethod(inst, method,
allArguments, method.getParameterTypes(), rw);
rw.setContinue(true);
} catch (Throwable t) {
t.printStackTrace();
}
}
if (!rw.isContinue()) {
return rw.getResult();
}
Object result = null;
try {
// 被代理方法调用
result = zuper.call();
} catch (Exception e) {
if (this.interceptor != null) {
try {
// 调用异常拦截处理
this.interceptor.handleMethodException(inst, method,
allArguments, method.getParameterTypes(), e);
} catch (Throwable t) {
t.printStackTrace();
}
}
}finally {
if (this.interceptor != null) {
try {
// 调用后拦截处理
result = this.interceptor.afterMethod(inst, method,
allArguments, method.getParameterTypes(), result);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
return result;
}
@Data
public class ResultWrapper {
private boolean isContinue;
private Object result;
}
}
最后建立主方法:
public static void premain(String agentArgs, Instrumentation inst) {
//创建一个转换器,转换器可以修改类的实现
//ByteBuddy对java agent提供了转换器的实现,直接使用即可
AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
return builder
.method(ElementMatchers.named("demo"))
// 拦截任意方法
// .method(ElementMatchers.<MethodDescription>any())
// 拦截到的方法委托给TimeInterceptor
.intercept(MethodDelegation.withDefaultConfiguration().to(new EnhanceTemplate(new ServiceInterceptor())));
// .intercept(MethodDelegation.to(MyInterceptor.class));
}
};
new AgentBuilder // Byte Buddy专门有个AgentBuilder来处理Java Agent的场景
.Default()
// 根据包名前缀拦截类
.type(ElementMatchers.nameStartsWith("com.agent.TestService"))
// 拦截到的类由transformer处理
.transform(transformer)
.installOn(inst);
}
1.服务端

建立需要拦截的类这里对应agent 程序中premain里的拦截点。
public class TestService {
public String demo(String name, int value) throws InterruptedException {
return "demo service";
}
public static void main(String[] args) throws InterruptedException {
TestService service =new TestService();
while (true){
System.out.println(service.demo("1231",222));
Thread.sleep(10000);
}
}
}
将程序进行agent 打包编译后放到linux服务器中
nohup java -javaagent:/home/app/agentdemo/java-agent-demo-1.0-SNAPSHOT.jar -jar java_agent_user-1.0-SNAPSHOT.jar &
以java agent方式进行启动可以看到增强结果
总结
skywalking agent字节码增强的技术主要就是通过Byte Buddy进行插桩,修改拦截代码实现自身增强逻辑。后续将分享TraceSegment发送流程
更多推荐

所有评论(0)