原理概述
在目标类中插入它自己的监控代码(插桩)
启动方式
SkyWalking 只支持静态启动方式。 入口SkyWalkingAgent.premain()
这个模块下只有这一个类。
启动流程
1、初始化配置
涉及到类
-
SkyWalkingAgent -
SnifferConfigInitializer
/**
* The main entrance of sky-walking agent, based on javaagent mechanism.
*/
public class SkyWalkingAgent {
private static ILog LOGGER = LogManager.getLogger(SkyWalkingAgent.class);
/**
* Main entrance. Use byte-buddy transform to enhance all classes, which define in plugins.
* //传参方式。等号后面
* -javaagent:/path/to/agent.jar=xxxxxx
* // 机构话传参
* -javaagent:/path/to/agent.jar=aaa=xx,bbb=xxx
* -
* 我常用的skyWalking的启动配置
* -
* java -javaagent:skywalking-agent/skywalking-agent.jar \
* -Dskywalking.agent.service_name=${SKYWALKING_AGENT_SERVICE_NAME} \
* -Dskywalking.collector.backend_service=${SKYWALKING_COLLECTOR_BACKEND_SERVICE} \
* -jar ${JAR_NAME}
*/
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
final PluginFinder pluginFinder;
// 初始化配置
try {
SnifferConfigInitializer.initializeCoreConfig(agentArgs);
} catch (Exception e) {
// 初始化配置时,重定义了一个logger,所以这里要重新获取一下
// 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);
}
// ----
}
}
/**
* The <code>SnifferConfigInitializer</code> initializes all configs in several way.
*/
public class SnifferConfigInitializer {
private static ILog LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
private static final String SPECIFIED_CONFIG_PATH = "skywalking_config";
private static final String DEFAULT_CONFIG_FILE_NAME = "/config/agent.config";
private static final String ENV_KEY_PREFIX = "skywalking.";
private static Properties AGENT_SETTINGS;
private static boolean IS_INIT_COMPLETED = false;
/**
* If the specified agent config path is set, the agent will try to locate the specified agent config. If the
* specified agent config path is not set , the agent will try to locate `agent.config`, which should be in the
* /config directory of agent package.
* <p>
* Also try to override the config by system.properties. All the keys in this place should start with {@link
* #ENV_KEY_PREFIX}. e.g. in env `skywalking.agent.service_name=yourAppName` to override `agent.service_name` in
* config file.
* <p>
* At the end, `agent.service_name` and `collector.servers` must not be blank.
*/
public static void initializeCoreConfig(String agentOptions) {
AGENT_SETTINGS = new Properties();
try (final InputStreamReader configFileStream = loadConfig()) {
// 将流 load 到 Properties 中
AGENT_SETTINGS.load(configFileStream);
// 替换占位符
// aaa = xxx
// bbb = ${aaa}-yyy ==替换==> xxx-yyy
for (String key : AGENT_SETTINGS.stringPropertyNames()) {
String value = (String) AGENT_SETTINGS.get(key);
AGENT_SETTINGS.put(key, PropertyPlaceholderHelper.INSTANCE.replacePlaceholders(value, AGENT_SETTINGS));
}
} catch (Exception e) {
LOGGER.error(e, "Failed to read the config file, skywalking is going to run in default config.");
}
// 如果在环境变量里配置了一些变量,要覆盖 Properties中的变量
// 环境变量优先级更高
try {
overrideConfigBySystemProp();
} catch (Exception e) {
LOGGER.error(e, "Failed to read the system properties.");
}
// agent 参数替换
// agent参数 优先级更高
agentOptions = StringUtil.trim(agentOptions, ',');
if (!StringUtil.isEmpty(agentOptions)) {
try {
agentOptions = agentOptions.trim();
LOGGER.info("Agent options is {}.", agentOptions);
overrideConfigByAgentOptions(agentOptions);
} catch (Exception e) {
LOGGER.error(e, "Failed to parse the agent options, val is {}.", agentOptions);
}
}
// AGENT_SETTINGS 中的配置数据。映射到 Config类中
initializeConfig(Config.class);
// 重新配置logger
// 根据配置的日志解析模式,重新生成一个logger。 模式 JSON PATTERN
// reconfigure logger after config initialization
configureLogger();
LOGGER = LogManager.getLogger(SnifferConfigInitializer.class);
// 使用agent,要传入server_name .这里做效验
if (StringUtil.isEmpty(Config.Agent.SERVICE_NAME)) {
throw new ExceptionInInitializerError("`agent.service_name` is missing.");
}
if (StringUtil.isEmpty(Config.Collector.BACKEND_SERVICE)) {
throw new ExceptionInInitializerError("`collector.backend_service` is missing.");
}
// PEER 可以理解为链接
// APPLICATION -> Redis
// PEER 就是 redis 地址
if (Config.Plugin.PEER_MAX_LENGTH <= 3) {
LOGGER.warn(
"PEER_MAX_LENGTH configuration:{} error, the default value of 200 will be used.",
Config.Plugin.PEER_MAX_LENGTH
);
Config.Plugin.PEER_MAX_LENGTH = 200;
}
// 配置加载完成
IS_INIT_COMPLETED = true;
}
/**
* Initialize field values of any given config class.
*
* @param configClass to host the settings for code access.
*/
public static void initializeConfig(Class configClass) {
if (AGENT_SETTINGS == null) {
LOGGER.error("Plugin configs have to be initialized after core config initialization.");
return;
}
try {
ConfigInitializer.initialize(AGENT_SETTINGS, configClass);
} catch (IllegalAccessException e) {
LOGGER.error(e,
"Failed to set the agent settings {}"
+ " to Config={} ",
AGENT_SETTINGS, configClass
);
}
}
private static void overrideConfigByAgentOptions(String agentOptions) throws IllegalArgumentException {
for (List<String> terms : parseAgentOptions(agentOptions)) {
if (terms.size() != 2) {
throw new IllegalArgumentException("[" + terms + "] is not a key-value pair.");
}
AGENT_SETTINGS.put(terms.get(0), terms.get(1));
}
}
private static List<List<String>> parseAgentOptions(String agentOptions) {
List<List<String>> options = new ArrayList<>();
List<String> terms = new ArrayList<>();
boolean isInQuotes = false;
StringBuilder currentTerm = new StringBuilder();
for (char c : agentOptions.toCharArray()) {
if (c == '\'' || c == '"') {
isInQuotes = !isInQuotes;
} else if (c == '=' && !isInQuotes) { // key-value pair uses '=' as separator
terms.add(currentTerm.toString());
currentTerm = new StringBuilder();
} else if (c == ',' && !isInQuotes) { // multiple options use ',' as separator
terms.add(currentTerm.toString());
currentTerm = new StringBuilder();
options.add(terms);
terms = new ArrayList<>();
} else {
currentTerm.append(c);
}
}
// add the last term and option without separator
terms.add(currentTerm.toString());
options.add(terms);
return options;
}
public static boolean isInitCompleted() {
return IS_INIT_COMPLETED;
}
/**
* Override the config by system properties. The property key must start with `skywalking`, the result should be as
* same as in `agent.config`
* <p>
* such as: Property key of `agent.service_name` should be `skywalking.agent.service_name`
*/
private static void overrideConfigBySystemProp() throws IllegalAccessException {
Properties systemProperties = System.getProperties();
for (final Map.Entry<Object, Object> prop : systemProperties.entrySet()) {
String key = prop.getKey().toString();
if (key.startsWith(ENV_KEY_PREFIX)) {
String realKey = key.substring(ENV_KEY_PREFIX.length());
AGENT_SETTINGS.put(realKey, prop.getValue());
}
}
}
/**
* Load the specified config file or default config file
*
* @return the config file {@link InputStream}, or null if not needEnhance.
*/
private static InputStreamReader loadConfig() throws AgentPackageNotFoundException, ConfigNotFoundException {
// 配置文件地址
String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH);
// 如果为空,就加载 默认配置文件 /config/agent.config
// AgentPackagePath.getPath() 用来查找agent的绝对目录
File configFile = StringUtil.isEmpty(specifiedConfigPath) ? new File(
AgentPackagePath.getPath(), DEFAULT_CONFIG_FILE_NAME) : new File(specifiedConfigPath);
if (configFile.exists() && configFile.isFile()) {
try {
LOGGER.info("Config file found in {}.", configFile);
return new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8);
} catch (FileNotFoundException e) {
throw new ConfigNotFoundException("Failed to load agent.config", e);
}
}
throw new ConfigNotFoundException("Failed to load agent.config.");
}
static void configureLogger() {
switch (Config.Logging.RESOLVER) {
case JSON:
LogManager.setLogResolver(new JsonLogResolver());
break;
case PATTERN:
default:
LogManager.setLogResolver(new PatternLogResolver());
}
}
}
2、加载插件
SkyWalking 通过自定义类加载器的方式,去加载指定目录下的jar包(插件)。
自定义类加载器
AgentClassLoader
开启类加载器的并行加载模式
/**
* The <code>AgentClassLoader</code> represents a classloader, which is in charge of finding plugins and interceptors.
*
* 自定义类加载器
*
*/
public class AgentClassLoader extends ClassLoader {
static {
/*
* Try to solve the classloader dead lock. See https://github.com/apache/skywalking/pull/2016
* 开启类加载器的并行加载模式。
* jdk1.7 之前 类加载是串行的。1.7后,改为并行,
* 原理: super.loadClass() 中锁,从锁当前类加载器,改为锁正在加载的类。
*
*
*/
registerAsParallelCapable();
}
}
// ClassLoader 类的构造器
private ClassLoader(Void unused, String name, ClassLoader parent) {
this.name = name;
this.parent = parent;
this.unnamedModule = new Module(this);
// 上面静态代码块中的方法,就是将clss注册为并行加载类
// 为parallelLockMap赋值
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
assertionLock = this;
}
this.package2certs = new ConcurrentHashMap<>();
this.nameAndId = nameAndId(this);
}
// ClassLoader类的 loadClass方法
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// getClassLoadingLock() 获取锁
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
// 重点。获取锁的方法
//
protected Object getClassLoadingLock(String className) {
Object lock = this;
// 并行加载map 不为空
if (parallelLockMap != null) {
// 创建一个新的锁
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(className, newLock);
if (lock == null) {
lock = newLock;
}
}
// 这里就是 以类加载器 为锁。线性加载
return lock;
}
从指定目录加载插件
简述:
AgentClassLoader初始化后,将agent插件根目录 的 "plugins", "activations"加入到classPath,后面就是从这两个目录下加载插件(jar包)。
findClass()方法就是加载类的方法,加载完成后,会检查一下类上有没有@PluginConfig注解。有的话,就将相关配置信息,拷给这个类。
// 构造函数
public AgentClassLoader(ClassLoader parent) throws AgentPackageNotFoundException {
super(parent);
File agentDictionary = AgentPackagePath.getPath();
classpath = new LinkedList<>();
// Config.Plugin.MOUNT 用来指定被加载类的目录
// 默认值 "plugins", "activations"
Config.Plugin.MOUNT.forEach(mountFolder -> classpath.add(new File(agentDictionary, mountFolder)));
}
// findClass方法
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 拿到所有的jar
List<Jar> allJars = getAllJars();
String path = name.replace('.', '/').concat(".class");
for (Jar jar : allJars) {
JarEntry entry = jar.jarFile.getJarEntry(path);
if (entry == null) {
continue;
}
try {
URL classFileUrl = new URL("jar:file:" + jar.sourceFile.getAbsolutePath() + "!/" + path);
byte[] data;
try (final BufferedInputStream is = new BufferedInputStream(
classFileUrl.openStream()); final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int ch;
while ((ch = is.read()) != -1) {
baos.write(ch);
}
data = baos.toByteArray();
}
// 包装一下。进行配置信息加载。将配置文件传给插件
return processLoadedClass(defineClass(name, data, 0, data.length));
} catch (IOException e) {
LOGGER.error(e, "find class fail.");
}
}
throw new ClassNotFoundException("Can't find " + name);
}
// processLoadedClass
private Class<?> processLoadedClass(Class<?> loadedClass) {
final PluginConfig pluginConfig = loadedClass.getAnnotation(PluginConfig.class);
if (pluginConfig != null) {
// Set up the plugin config when loaded by class loader at the first time.
// Agent class loader just loaded limited classes in the plugin jar(s), so the cost of this
// isAssignableFrom would be also very limited.
SnifferConfigInitializer.initializeConfig(pluginConfig.root());
}
return loadedClass;
}
3、插件定义体系
首先自己看SkyWalking官网的插件开发指南
从doubbe插件看开发流程
具体注释,看代码
4、 插件加载流程
涉及到类
PluginBootstrapPluginFinder
简述:
new PluginBootstrap().loadPlugins() 加载所有插件,通过读取skywalking-plugin.def文件,将定义的class 实例化。
PluginFinder 将这些类分类存放到nameMatchDefine,signatureMatchDefine,bootstrapClassMatchDefine。并且提供find方法,可以通过类查找到可以对这个类生效的插件
// SkyWalkingAgent
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
final PluginFinder pluginFinder;
// -----
// 加载插件
try {
// 插件查找器
// new PluginBootstrap().loadPlugins() 插件加载器
// 构造函数。对插件进行分类。
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;
}
}
public class PluginBootstrap {
private static final ILog LOGGER = LogManager.getLogger(PluginBootstrap.class);
/**
* load all plugins.
* 加载所有的插件
*
* @return plugin definition list.
*/
public List<AbstractClassEnhancePluginDefine> loadPlugins() throws AgentPackageNotFoundException {
// 初始化自定义类加载器实例
AgentClassLoader.initDefaultLoader();
// 插件资源转换器
PluginResourcesResolver resolver = new PluginResourcesResolver();
//拿到所有 skywalking-plugin.def 的资源
List<URL> resources = resolver.getResources();
if (resources == null || resources.size() == 0) {
LOGGER.info("no plugin files (skywalking-plugin.def) found, continue to start application.");
return new ArrayList<AbstractClassEnhancePluginDefine>();
}
for (URL pluginUrl : resources) {
try {
// url转换成流,然后load(解析.def文件)
PluginCfg.INSTANCE.load(pluginUrl.openStream());
} catch (Throwable t) {
LOGGER.error(t, "plugin file [{}] init failure.", pluginUrl);
}
}
// load后的数据
List<PluginDefine> pluginClassList = PluginCfg.INSTANCE.getPluginClassList();
List<AbstractClassEnhancePluginDefine> plugins = new ArrayList<AbstractClassEnhancePluginDefine>();
// 实例化
for (PluginDefine pluginDefine : pluginClassList) {
try {
LOGGER.debug("loading plugin class {}.", pluginDefine.getDefineClass());
// 创建实例
AbstractClassEnhancePluginDefine plugin = (AbstractClassEnhancePluginDefine) Class.forName(pluginDefine.getDefineClass(), true, AgentClassLoader
.getDefault()).newInstance();
plugins.add(plugin);
} catch (Throwable t) {
LOGGER.error(t, "load plugin [{}] failure.", pluginDefine.getDefineClass());
}
}
// DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()) 加载一些通过xml定义的插件
plugins.addAll(DynamicPluginLoader.INSTANCE.load(AgentClassLoader.getDefault()));
return plugins;
}
}
public class PluginFinder {
/**
* 为什么这里map 泛型是<String,List>
* 因为对于一个类,可能有多个插件都要对他进行字节码增强
* KEY => 目标类
* VAL => 所有可以对这个类生效的插件
*/
private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
// 这里是因为 间接匹配的,无法确定到具体的类
private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
private final List<AbstractClassEnhancePluginDefine> bootstrapClassMatchDefine = new ArrayList<AbstractClassEnhancePluginDefine>();
/**
* @param plugins 所有的插件
*/
public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
// 分类。放到不同的map中
for (AbstractClassEnhancePluginDefine plugin : plugins) {
// 拿到匹配器
ClassMatch match = plugin.enhanceClass();
if (match == null) {
continue;
}
// nameMatch
if (match instanceof NameMatch) {
NameMatch nameMatch = (NameMatch) match;
LinkedList<AbstractClassEnhancePluginDefine> pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
if (pluginDefines == null) {
pluginDefines = new LinkedList<AbstractClassEnhancePluginDefine>();
nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
}
pluginDefines.add(plugin);
} else {
// 间接匹配
signatureMatchDefine.add(plugin);
}
// 对jdk类库进行增强的插件
if (plugin.isBootstrapInstrumentation()) {
bootstrapClassMatchDefine.add(plugin);
}
}
}
/**
* 根据类查找 插件
* 查找要对这个类生效的插件
* 1.从命名插件中找
* 2. 从间接匹配插件中找
* @param typeDescription 类的描述信息
* @return
*/
public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription) {
List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<AbstractClassEnhancePluginDefine>();
String typeName = typeDescription.getTypeName();
if (nameMatchDefine.containsKey(typeName)) {
matchedPlugins.addAll(nameMatchDefine.get(typeName));
}
// 间接匹配。使用匹配器进行验证
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
IndirectMatch match = (IndirectMatch) pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) {
matchedPlugins.add(pluginDefine);
}
}
return matchedPlugins;
}
/***
* 用来告诉byteBuddy要拦截的类
* @return
*/
public ElementMatcher<? super TypeDescription> buildMatch() {
ElementMatcher.Junction judge = new AbstractJunction<NamedElement>() {
@Override
public boolean matches(NamedElement target) {
return nameMatchDefine.containsKey(target.getActualName());
}
};
// 不能是接口
judge = judge.and(not(isInterface()));
for (AbstractClassEnhancePluginDefine define : signatureMatchDefine) {
ClassMatch match = define.enhanceClass();
if (match instanceof IndirectMatch) {
judge = judge.or(((IndirectMatch) match).buildJunction());
}
}
// 封装一下,避免和其他字节码增强工具的兼容性问题。
return new ProtectiveShieldMatcher(judge);
}
public List<AbstractClassEnhancePluginDefine> getBootstrapClassMatchDefine() {
return bootstrapClassMatchDefine;
}
}
5、 定制agent
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
// ----
// 定制化agent
// Config.Agent.IS_OPEN_DEBUGGING_CLASS 是否打开调试类
final ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS));
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())
// Synthetic 关键字, 用来标识,生成的字节码类
.or(ElementMatchers.isSynthetic())
);
JDK9ModuleExporter.EdgeClasses edgeClasses = new JDK9ModuleExporter.EdgeClasses();
try {
// 将 edgeClasses 注入到 Bootstrap ClassLoader
agentBuilder = BootstrapInstrumentBoost.inject(pluginFinder, instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent inject bootstrap instrumentation failure. Shutting down.");
return;
}
try {
// 打开读边界
// jdK9之后,出现模块化加载新技术,这里是绕过 模块化加载
agentBuilder = JDK9ModuleExporter.openReadEdge(instrumentation, agentBuilder, edgeClasses);
} catch (Exception e) {
LOGGER.error(e, "SkyWalking agent open read edge in JDK 9+ failure. Shutting down.");
return;
}
// 为true 的话, 将修改后的字节码,保存到磁盘或者内存上
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.");
}
}
// pluginFinder.buildMatch() 构造出一个巨大的条件,用来匹配插件类
// type 指定byteBuddy要拦截的类
agentBuilder.type(pluginFinder.buildMatch())
.transform(new Transformer(pluginFinder))
// 增强的模式: redefine 和 retransform 的区别就在于 是否保留修改前的内容
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
// 注册监听器
.with(new RedefinitionListener())
.with(new Listener())
// 安装到 instrumentation
.installOn(instrumentation);
// ----
}
}
synthetic
略
NBAC
略
6、加载服务
简述:
通过 服务管理器ServiceManager 基于 ServiceLoader(SPI) 加载所有 BootService 的实现类。
根据@DefaultImplementor,@OverrideImplementor注解,来决定 服务最终选择的实现类。规则如上思维导图。
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
// ----
// 启动服务
try {
ServiceManager.INSTANCE.boot();
} catch (Exception e) {
LOGGER.error(e, "Skywalking agent boot failure.");
}
// ---
}
/**
* The <code>ServiceManager</code> bases on {@link ServiceLoader}, load all {@link BootService} implementations.
* 服务管理器。 基于 ServiceLoader(SPI) 加载所有 BootService 的实现类
*/
public enum ServiceManager {
INSTANCE;
private static final ILog LOGGER = LogManager.getLogger(ServiceManager.class);
private Map<Class, BootService> bootedServices = Collections.emptyMap();
public void boot() {
// 加载服务
bootedServices = loadAllServices();
prepare();
startup();
onComplete();
}
public void shutdown() {
// 倒序。 根据依赖关系。优雅关闭
bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority).reversed()).forEach(service -> {
try {
service.shutdown();
} catch (Throwable e) {
LOGGER.error(e, "ServiceManager try to shutdown [{}] fail.", service.getClass().getName());
}
});
}
private Map<Class, BootService> loadAllServices() {
Map<Class, BootService> bootedServices = new LinkedHashMap<>();
List<BootService> allServices = new LinkedList<>();
// spi 去加载服务类
load(allServices);
// 根据 默认实现、覆盖实现。为服务分类
// 一个服务class, 有 默认实现、覆盖实现。 覆盖实现的优先级高。
// 如果一个服务class,只有一个实现,可以不用加注解
for (final BootService bootService : allServices) {
Class<? extends BootService> bootServiceClass = bootService.getClass();
boolean isDefaultImplementor = bootServiceClass.isAnnotationPresent(DefaultImplementor.class);
if (isDefaultImplementor) {
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
//ignore the default service
}
} else {
OverrideImplementor overrideImplementor = bootServiceClass.getAnnotation(OverrideImplementor.class);
if (overrideImplementor == null) {
if (!bootedServices.containsKey(bootServiceClass)) {
bootedServices.put(bootServiceClass, bootService);
} else {
// 服务不能重复定义,抛异常
throw new ServiceConflictException("Duplicate service define for :" + bootServiceClass);
}
} else {
Class<? extends BootService> targetService = overrideImplementor.value();
if (bootedServices.containsKey(targetService)) {
boolean presentDefault = bootedServices.get(targetService)
.getClass()
.isAnnotationPresent(DefaultImplementor.class);
if (presentDefault) {
bootedServices.put(targetService, bootService);
} else {
throw new ServiceConflictException(
"Service " + bootServiceClass + " overrides conflict, " + "exist more than one service want to override :" + targetService);
}
} else {
// 当前 覆盖实现 要覆盖的 默认实现 还没有被加载出来。这时候,就把这个 覆盖实现 当做是其服务的 默认实现。
// @OverrideImplementor 有个value字段,value就是 要覆盖的服务。 这里 把这个 要覆盖的服务,当成了key.
bootedServices.put(targetService, bootService);
}
}
}
}
return bootedServices;
}
private void prepare() {
bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> {
try {
service.prepare();
} catch (Throwable e) {
LOGGER.error(e, "ServiceManager try to pre-start [{}] fail.", service.getClass().getName());
}
});
}
private void startup() {
bootedServices.values().stream().sorted(Comparator.comparingInt(BootService::priority)).forEach(service -> {
try {
service.boot();
} catch (Throwable e) {
LOGGER.error(e, "ServiceManager try to start [{}] fail.", service.getClass().getName());
}
});
}
private void onComplete() {
for (BootService service : bootedServices.values()) {
try {
service.onComplete();
} catch (Throwable e) {
LOGGER.error(e, "Service [{}] AfterBoot process fails.", service.getClass().getName());
}
}
}
/**
* Find a {@link BootService} implementation, which is already started.
*
* @param serviceClass class name.
* @param <T> {@link BootService} implementation class.
* @return {@link BootService} instance
*/
public <T extends BootService> T findService(Class<T> serviceClass) {
return (T) bootedServices.get(serviceClass);
}
/**
* spi 去加载 服务
*
* @param allServices
*/
void load(List<BootService> allServices) {
for (final BootService bootService : ServiceLoader.load(BootService.class, AgentClassLoader.getDefault())) {
allServices.add(bootService);
}
}
}
7 注册关闭钩子
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
// ----
// 注册关闭钩子,优雅关机
Runtime.getRuntime()
.addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
}
插件工作原理
witness机制
插件工作流程
这块理解的不好。可以看这个博客,很清晰。就不复制人家的笔记了,等后面把这块重新看看,再自己总计。 blog.csdn.net/qq_40378034…
入口
org/apache/skywalking/apm/agent/SkyWalkingAgent.java:156
SkyWalkingAgent.Transformer:agent自定义的增强逻辑。重点看 transform方法
/**
* 自己定义的插桩逻辑
*/
private static class Transformer implements AgentBuilder.Transformer {
private PluginFinder pluginFinder;
/**
*
* @param pluginFinder 插件查找器
*/
Transformer(PluginFinder pluginFinder) {
this.pluginFinder = pluginFinder;
}
/**
* @param builder 当前拦截到的类的字节码
* @param typeDescription 简单当成 Class ,它包含了类的描述信息
* @param classLoader 加载 【当前拦截到的类】的类加载器
* @param module The class's module or {@code null} if the current VM does not support modules.
* @return
*/
@Override
public DynamicType.Builder<?> transform(final DynamicType.Builder<?> builder,
final TypeDescription typeDescription,
final ClassLoader classLoader,
final JavaModule module) {
// 加载UrlClassLoader 类。 用于构造JVM信息
LoadedLibraryCollector.registerURLClassLoader(classLoader);
// 找到所有 对这个类生效的插件
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription);
if (pluginDefines.size() > 0) {
// 遍历这些差价,构造 newBuilder
DynamicType.Builder<?> newBuilder = builder;
// context 记录一些标记
EnhanceContext context = new EnhanceContext();
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
// 去做增强 【核心步骤】 define.define()
DynamicType.Builder<?> possibleNewBuilder = define.define(
typeDescription, newBuilder, classLoader, context);
// 如果增强了,就不会为null
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;
}
}
重点看这串代码:
for (AbstractClassEnhancePluginDefine define : pluginDefines) {
// 去做增强 【核心步骤】 define.define()
DynamicType.Builder<?> possibleNewBuilder = define.define(
typeDescription, newBuilder, classLoader, context);
// 如果增强了,就不会为null
if (possibleNewBuilder != null) {
newBuilder = possibleNewBuilder;
}
}
``AbstractClassEnhancePluginDefine
是所有插件的父类。define方法先进行witness版本识别,然后调用enhance方法,根据静态方法、实例方法/构造器、JDK类库中类分类进行不同的增强。然后具体的增强实现要看ClassEnhancePluginDefine[子类] 的 enhanceInstance() 和enhanceClass()这两个方法
/**
* 所有插件的父类
* <p>
* Basic abstract class of all sky-walking auto-instrumentation plugins.
* <p>
* It provides the outline of enhancing the target class. If you want to know more about enhancing, you should go to see
* {@link ClassEnhancePluginDefine}
*/
public abstract class AbstractClassEnhancePluginDefine {
private static final ILog LOGGER = LogManager.getLogger(AbstractClassEnhancePluginDefine.class);
/**
* New field name.
*/
public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws";
/**
* Main entrance of enhancing the class.
*
* @param builder 当前拦截到的类的字节码
* @param typeDescription 简单当成 Class ,它包含了类的描述信息
* @param classLoader 加载 【当前拦截到的类】的类加载器
* @param typeDescription target class description.
* @param builder byte-buddy's builder to manipulate target class's bytecode.
* @param classLoader load the given transformClass
* @return the new builder, or <code>null</code> if not be enhanced.
* @throws PluginException when set builder failure.
*/
public DynamicType.Builder<?> define(TypeDescription typeDescription, DynamicType.Builder<?> builder,
ClassLoader classLoader, EnhanceContext context) throws PluginException {
// 当前插件的名字
String interceptorDefineClassName = this.getClass().getName();
// 被拦截的类的 className
String transformClassName = typeDescription.getTypeName();
if (StringUtil.isEmpty(transformClassName)) {
LOGGER.warn("classname of being intercepted is not defined by {}.", interceptorDefineClassName);
return null;
}
LOGGER.debug("prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);
// witness 版本识别 [细节可以不去了解]
// 来确认这个插件是不是可以用
WitnessFinder finder = WitnessFinder.INSTANCE;
/**
* find witness classes for enhance class
*/
// 根据类来识别
String[] witnessClasses = witnessClasses();
if (witnessClasses != null) {
for (String witnessClass : witnessClasses) {
if (!finder.exist(witnessClass, classLoader)) {
LOGGER.warn("enhance class {} by plugin {} is not working. Because witness class {} is not existed.", transformClassName, interceptorDefineClassName, witnessClass);
return null;
}
}
}
// 根据方法来识别
List<WitnessMethod> witnessMethods = witnessMethods();
if (!CollectionUtil.isEmpty(witnessMethods)) {
for (WitnessMethod witnessMethod : witnessMethods) {
if (!finder.exist(witnessMethod, classLoader)) {
LOGGER.warn("enhance class {} by plugin {} is not working. Because witness method {} is not existed.", transformClassName, interceptorDefineClassName, witnessMethod);
return null;
}
}
}
/**
* 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;
}
/**
* 增强方法
*
* Begin to define how to enhance class. After invoke this method, only means definition is finished.
*
* @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<?> 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;
}
/**
* 增强类以拦截构造函数和类实例方法。
* 看实现类 {@link ClassEnhancePluginDefine#enhanceInstance(TypeDescription, DynamicType.Builder, ClassLoader, EnhanceContext)}
*
* Enhance a class to intercept constructors and class instance 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 abstract DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
EnhanceContext context) throws PluginException;
/**
*
* 增强类以拦截类静态方法。
* 看实现类 {@link ClassEnhancePluginDefine#enhanceClass(TypeDescription, DynamicType.Builder, ClassLoader)}
* 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 abstract DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder,
ClassLoader classLoader) throws PluginException;
}
ClassEnhancePluginDefine是AbstractClassEnhancePluginDefine子类。实现了具体的增强逻辑。
public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine {
private static final ILog LOGGER = LogManager.getLogger(ClassEnhancePluginDefine.class);
/**
* 增强类的静态方法
* Enhance a class to intercept constructors and class instance 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<?> enhanceInstance(TypeDescription typeDescription,
DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader,
EnhanceContext context) throws PluginException {
// 获取拦截点 (构造方法拦截点,实例方法拦截点)
ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
// 被拦截的类的类名
String enhanceOriginClassName = typeDescription.getTypeName();
boolean existedConstructorInterceptPoint = false;
if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) {
existedConstructorInterceptPoint = true;
}
boolean existedMethodsInterceptPoints = false;
if (instanceMethodsInterceptPoints != null && instanceMethodsInterceptPoints.length > 0) {
existedMethodsInterceptPoints = true;
}
/**
* nothing need to be enhanced in class instance, maybe need enhance static methods.
*/
if (!existedConstructorInterceptPoint && !existedMethodsInterceptPoints) {
return newClassBuilder;
}
/**
*
* 修改类的源码
* 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. enhance constructors
*/
if (existedConstructorInterceptPoint) {
for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) {
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher())
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost
.forInternalDelegateClass(constructorInterceptPoint
.getConstructorInterceptor()))));
} else {
newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher())
// 代理的逻辑
.intercept(SuperMethodCall.INSTANCE.andThen(MethodDelegation.withDefaultConfiguration()
.to(new ConstructorInter(constructorInterceptPoint
.getConstructorInterceptor(), classLoader))));
}
}
}
/**
* 存在实例方法 拦截前
*
* 3. enhance instance methods
*/
if (existedMethodsInterceptPoints) {
for (InstanceMethodsInterceptPoint instanceMethodsInterceptPoint : instanceMethodsInterceptPoints) {
String interceptor = instanceMethodsInterceptPoint.getMethodsInterceptor();
if (StringUtil.isEmpty(interceptor)) {
throw new EnhanceException("no InstanceMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName);
}
ElementMatcher.Junction<MethodDescription> junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
// DeclaredInstanceMethodsInterceptPoint 声明式拦截点。一般用于判断spring 的注解
if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) {
// 辅助判断。
junction = junction.and(ElementMatchers.<MethodDescription>isDeclaredBy(typeDescription));
}
if (instanceMethodsInterceptPoint.isOverrideArgs()) {
// 重写入参?
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(Morph.Binder.install(OverrideCallable.class))
.to(new InstMethodsInterWithOverrideArgs(interceptor, classLoader)));
}
} else {
// 没有重新入参
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(junction)
.intercept(MethodDelegation.withDefaultConfiguration()
.to(new InstMethodsInter(interceptor, classLoader)));
}
}
}
}
return newClassBuilder;
}
/**
* 静态方法增强逻辑
* 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 {
// 获取静态方法拦截点。 调用的 AbstractClassEnhancePluginDefine 的方法
// 其实就是插件定中,写的那个方法
StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints();
// 简单认为获取className
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()) {
// BootstrapClassLoader 加载器加载的插件吗?
// 换个说法就是 是JDK类库中的类吗
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
// intercept 拦截
.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 {
// BootstrapClassLoader 加载器加载的插件吗?
// 换个说法就是 是JDK类库中的类吗
if (isBootstrapInstrumentation()) {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
.intercept(MethodDelegation.withDefaultConfiguration()
.to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)));
} else {
newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher()))
// intercept 拦截
// StaticMethodsInter 包装的一个代理类
.intercept(MethodDelegation.withDefaultConfiguration().to(new StaticMethodsInter(interceptor)));
}
}
}
return newClassBuilder;
}
/**
* @return null, means enhance no v2 instance methods.
*/
@Override
public InstanceMethodsInterceptV2Point[] getInstanceMethodsInterceptV2Points() {
return null;
}
/**
* @return null, means enhance no v2 static methods.
*/
@Override
public StaticMethodsInterceptV2Point[] getStaticMethodsInterceptV2Points() {
return null;
}
}