Skip to content

Commit

Permalink
合并为增强引导类加载器加载的类而定制的Template、Transform
Browse files Browse the repository at this point in the history
  • Loading branch information
luanwenfei-venus committed Jul 28, 2023
1 parent 5680849 commit ba541e4
Show file tree
Hide file tree
Showing 31 changed files with 1,132 additions and 1,767 deletions.
3 changes: 3 additions & 0 deletions sermant-agentcore/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>sermant-agentcore-god</module>
<module>sermant-agentcore-core</module>
<module>sermant-agentcore-premain</module>
<module>sermant-agentcore-config</module>
Expand All @@ -55,6 +56,7 @@
<profile>
<id>test</id>
<modules>
<module>sermant-agentcore-god</module>
<module>sermant-agentcore-core</module>
<module>sermant-agentcore-premain</module>
<module>sermant-agentcore-config</module>
Expand All @@ -64,6 +66,7 @@
<profile>
<id>release</id>
<modules>
<module>sermant-agentcore-god</module>
<module>sermant-agentcore-core</module>
<module>sermant-agentcore-premain</module>
<module>sermant-agentcore-implement</module>
Expand Down
5 changes: 5 additions & 0 deletions sermant-agentcore/sermant-agentcore-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@
</profiles>

<dependencies>
<dependency>
<groupId>com.huaweicloud.sermant</groupId>
<artifactId>sermant-agentcore-god</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import com.huaweicloud.sermant.core.event.collector.FrameworkEventCollector;
import com.huaweicloud.sermant.core.operation.OperationManager;
import com.huaweicloud.sermant.core.plugin.PluginSystemEntrance;
import com.huaweicloud.sermant.core.plugin.agent.adviser.AdviserScheduler;
import com.huaweicloud.sermant.core.plugin.agent.template.DefaultAdviser;
import com.huaweicloud.sermant.core.service.ServiceManager;

import java.lang.instrument.Instrumentation;
Expand Down Expand Up @@ -72,6 +74,10 @@ public static void run(Map<String, Object> argsMap, Instrumentation instrumentat
// 初始化插件
PluginSystemEntrance.initialize(instrumentation);

// 注册Adviser
DefaultAdviser defaultAdviser = new DefaultAdviser();
AdviserScheduler.registry(defaultAdviser);

// 上报Sermant启动事件
FrameworkEventCollector.getInstance().collectAgentStartEvent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import com.huaweicloud.sermant.core.plugin.classloader.PluginClassLoader;
import com.huaweicloud.sermant.core.utils.FileUtils;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.agent.builder.AgentBuilder.Default;
import net.bytebuddy.agent.builder.ResettableClassFileTransformer;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.description.type.TypeList.Generic;
Expand All @@ -49,6 +49,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand Down Expand Up @@ -209,12 +210,10 @@ private BufferedAgentBuilder setOutputListener() {
String currentTime = LocalDateTime.now().format(formatter);
if (outputPath == null || outputPath.isEmpty()) {
outputDirectory = Paths.get(FileUtils.getAgentPath())
.resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR)
.resolve(currentTime);
.resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR).resolve(currentTime);
} else {
outputDirectory = Paths.get(outputPath)
.resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR)
.resolve(currentTime);
outputDirectory =
Paths.get(outputPath).resolve(CommonConstant.ENHANCED_CLASS_OUTPUT_PARENT_DIR).resolve(currentTime);
}
final File file;
try {
Expand All @@ -225,13 +224,12 @@ private BufferedAgentBuilder setOutputListener() {
}
return addAction(builder -> builder.with(new AgentBuilder.Listener.Adapter() {
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader,
JavaModule module, boolean loaded, DynamicType dynamicType) {
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
boolean loaded, DynamicType dynamicType) {
try {
dynamicType.saveIn(file);
} catch (IOException e) {
LOGGER.warning(String.format(
"Save class [%s] byte code failed. ", typeDescription.getTypeName()));
LOGGER.log(Level.WARNING, "Save class {0} byte code failed.", typeDescription.getTypeName());
}
}
}));
Expand Down Expand Up @@ -274,11 +272,10 @@ public BufferedAgentBuilder addAction(BuilderAction action) {
* @return 安装结果,可重置的转换器,若无类元信息改动,调用其reset方法即可重置
*/
public ResettableClassFileTransformer install(Instrumentation instrumentation) {
AgentBuilder builder = new AgentBuilder.Default(new ByteBuddy());
AgentBuilder builder = new Default().disableClassFormatChanges();
for (BuilderAction action : actions) {
builder = action.process(builder);
}
builder.disableClassFormatChanges();
return builder.installOn(instrumentation);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,24 @@

package com.huaweicloud.sermant.core.plugin.agent.collector;

import com.huaweicloud.sermant.core.common.LoggerFactory;
import com.huaweicloud.sermant.core.config.ConfigManager;
import com.huaweicloud.sermant.core.plugin.agent.config.AgentConfig;
import com.huaweicloud.sermant.core.plugin.agent.declarer.AbstractPluginDescription;
import com.huaweicloud.sermant.core.plugin.agent.declarer.InterceptDeclarer;
import com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer;
import com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDescription;
import com.huaweicloud.sermant.core.plugin.agent.declarer.SuperTypeDeclarer;
import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassMatcher;
import com.huaweicloud.sermant.core.plugin.agent.matcher.ClassTypeMatcher;
import com.huaweicloud.sermant.core.plugin.agent.transformer.AdviceTransformer;
import com.huaweicloud.sermant.core.plugin.agent.transformer.BootstrapTransformer;
import com.huaweicloud.sermant.core.plugin.agent.transformer.DefaultTransformer;

import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.utility.JavaModule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* 插件收集器管理器,用于从所有插件收集器中获取插件描述器
Expand All @@ -48,6 +43,8 @@
* @since 2022-01-26
*/
public class PluginCollectorManager {
private static final Logger LOGGER = LoggerFactory.getLogger();

/**
* 通过spi检索所有配置的插件收集器
*/
Expand All @@ -73,7 +70,7 @@ public static List<PluginDescription> getPlugins() {
*/
public static List<PluginDescription> getPlugins(AgentConfig.CombineStrategy strategy) {
final List<PluginDescription> plugins = new ArrayList<>();
plugins.addAll(combinePlugins(getDeclarers(), strategy));
plugins.addAll(combinePlugins(getDeclarers()));
plugins.addAll(getDescriptions());
return plugins;
}
Expand Down Expand Up @@ -114,27 +111,12 @@ private static List<? extends PluginDescription> getDescriptions() {
* 合并所有的插件声明器
*
* @param declarers 插件声明器列表
* @param strategy 插件声明器合并策略
* @return 合并所得的插件描述器列表
*/
private static List<PluginDescription> combinePlugins(List<? extends PluginDeclarer> declarers,
AgentConfig.CombineStrategy strategy) {
private static List<PluginDescription> combinePlugins(List<? extends PluginDeclarer> declarers) {
final List<PluginDescription> plugins = new ArrayList<>();
if (!declarers.isEmpty()) {
switch (strategy) {
case NONE:
plugins.addAll(describeDeclarers(declarers));
break;
case BY_NAME:
plugins.addAll(combineDeclarersByName(declarers));
break;
case ALL:
plugins.add(combineAllDeclarers(declarers));
break;
default:
throw new IllegalArgumentException(String.format(Locale.ROOT,
"Unknown combine strategy %s. ", strategy));
}
plugins.addAll(describeDeclarers(declarers));
}
return plugins;
}
Expand Down Expand Up @@ -163,170 +145,25 @@ private static PluginDescription describeDeclarer(PluginDeclarer declarer) {
return new AbstractPluginDescription() {
@Override
public boolean matches(TypeDescription target) {
return declarer.getClassMatcher().matches(target);
}

@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
if (classLoader == null) {
return new BootstrapTransformer(
declarer.getInterceptDeclarers(ClassLoader.getSystemClassLoader())
).transform(builder, typeDescription, null, module);
} else {
return new AdviceTransformer(
declarer.getInterceptDeclarers(classLoader), declarer.getSuperTypeDeclarers()
).transform(builder, typeDescription, classLoader, module);
}
}
};
}

/**
* 仅通过名称合并插件声明器为一个插件描述器,其他的直接描述{@link #describeDeclarer}
*
* @param declarers 插件声明器集
* @return 插件描述器集
*/
private static List<PluginDescription> combineDeclarersByName(Iterable<? extends PluginDeclarer> declarers) {
final List<PluginDescription> plugins = new ArrayList<>();
final Map<String, List<PluginDeclarer>> nameCombinedMap = new HashMap<>();
for (PluginDeclarer pluginDeclarer : declarers) {
final ClassMatcher classMatcher = pluginDeclarer.getClassMatcher();
if (classMatcher instanceof ClassTypeMatcher) {
for (String typeName : ((ClassTypeMatcher) classMatcher).getTypeNames()) {
List<PluginDeclarer> nameCombinedList = nameCombinedMap.get(typeName);
if (nameCombinedList == null) {
nameCombinedList = new ArrayList<>();
nameCombinedMap.put(typeName, nameCombinedList);
}
nameCombinedList.add(pluginDeclarer);
}
} else {
plugins.add(describeDeclarer(pluginDeclarer));
}
}
if (!nameCombinedMap.isEmpty()) {
plugins.add(createNameCombinedDescription(nameCombinedMap));
}
return plugins;
}

/**
* 创建根据名称合并插件声明器的插件描述器
*
* @param nameCombinedMap 插件声明器及其声明的被增强类名集
* @return 插件描述器
*/
private static PluginDescription createNameCombinedDescription(Map<String, List<PluginDeclarer>> nameCombinedMap) {
return new AbstractPluginDescription() {
@Override
public boolean matches(TypeDescription target) {
return nameCombinedMap.containsKey(target.getActualName());
return matchTarget(declarer.getClassMatcher(), target);
}

@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
return nameCombinedTransform(builder, typeDescription, classLoader, module, nameCombinedMap);
ClassLoader classLoader, JavaModule module) {
return new DefaultTransformer(declarer.getInterceptDeclarers(ClassLoader.getSystemClassLoader()))
.transform(builder, typeDescription, classLoader, module);
}
};
}

/**
* 合并所有插件声明器为一个插件描述器
*
* @param declarers 插件声明器集
* @return 插件描述器
*/
private static PluginDescription combineAllDeclarers(Iterable<? extends PluginDeclarer> declarers) {
final Map<String, List<PluginDeclarer>> nameCombinedMap = new HashMap<>();
final List<PluginDeclarer> combinedList = new ArrayList<>();
for (PluginDeclarer pluginDeclarer : declarers) {
final ClassMatcher classMatcher = pluginDeclarer.getClassMatcher();
if (classMatcher instanceof ClassTypeMatcher) {
for (String typeName : ((ClassTypeMatcher) classMatcher).getTypeNames()) {
List<PluginDeclarer> nameCombinedList = nameCombinedMap.get(typeName);
if (nameCombinedList == null) {
nameCombinedList = new ArrayList<>();
nameCombinedMap.put(typeName, nameCombinedList);
}
nameCombinedList.add(pluginDeclarer);
}
} else {
combinedList.add(pluginDeclarer);
}
}
return createAllCombinedDescription(nameCombinedMap, combinedList);
}

/**
* 创建合并全部插件声明器的插件描述器
*
* @param nameCombinedMap 插件声明器及其声明的被增强类名集
* @param combinedList 其他模糊匹配的插件声明器列表
* @return 插件描述器
*/
private static PluginDescription createAllCombinedDescription(Map<String, List<PluginDeclarer>> nameCombinedMap,
List<PluginDeclarer> combinedList) {
return new AbstractPluginDescription() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
return nameCombinedTransform(builder, typeDescription, classLoader, module, nameCombinedMap);
}

@Override
public boolean matches(TypeDescription target) {
final String typeName = target.getActualName();
for (PluginDeclarer pluginDeclarer : combinedList) {
if (pluginDeclarer.getClassMatcher().matches(target)) {
List<PluginDeclarer> declarers = nameCombinedMap.get(typeName);
if (declarers == null) {
declarers = new ArrayList<>();
nameCombinedMap.put(typeName, declarers);
}
declarers.add(pluginDeclarer);
}
}
return nameCombinedMap.containsKey(typeName);
}
};
}

/**
* 处理按名称合并的插件声明器的{@link net.bytebuddy.agent.builder.AgentBuilder.Transformer#transform}方法
*
* @param builder byte-buddy的动态构建器
* @param typeDescription 被增强类的描述器
* @param classLoader 被增强类的类加载器
* @param module byte-buddy的java模块对象
* @param nameCombinedMap 插件声明器及其声明的被增强类名集
* @return 构建器
*/
private static DynamicType.Builder<?> nameCombinedTransform(DynamicType.Builder<?> builder,
TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
Map<String, List<PluginDeclarer>> nameCombinedMap) {
final List<PluginDeclarer> pluginDeclarers = nameCombinedMap.remove(typeDescription.getActualName());
final List<InterceptDeclarer> interceptDeclarers = new ArrayList<>();
if (classLoader == null) {
for (PluginDeclarer pluginDeclarer : pluginDeclarers) {
interceptDeclarers.addAll(
Arrays.asList(pluginDeclarer.getInterceptDeclarers(ClassLoader.getSystemClassLoader())));
}
return new BootstrapTransformer(
interceptDeclarers.toArray(new InterceptDeclarer[0])
).transform(builder, typeDescription, null, module);
} else {
final List<SuperTypeDeclarer> superTypeDeclarers = new ArrayList<>();
for (PluginDeclarer pluginDeclarer : pluginDeclarers) {
interceptDeclarers.addAll(Arrays.asList(pluginDeclarer.getInterceptDeclarers(classLoader)));
superTypeDeclarers.addAll(Arrays.asList(pluginDeclarer.getSuperTypeDeclarers()));
}
return new AdviceTransformer(
interceptDeclarers.toArray(new InterceptDeclarer[0]),
superTypeDeclarers.toArray(new SuperTypeDeclarer[0])
).transform(builder, typeDescription, classLoader, module);
private static boolean matchTarget(ElementMatcher<TypeDescription> matcher, TypeDescription target) {
try {
return matcher.matches(target);
} catch (Exception exception) {
LOGGER.log(Level.WARNING, "Exception occurs when math target: " + target.getActualName() + ",{0}",
exception.getMessage());
return false;
}
}
}
Loading

0 comments on commit ba541e4

Please sign in to comment.