今天我们要分析的是 SkyWalking Java Agent 配置相关内容,我们接触到的框架大都需要一些配置文件,比如 SpringBoot 中的 application.yml。 SkyWalking Java Agent 在 premain 方法中首先做的就是通过 SnifferConfigInitializer.initializeCoreConfig(agentArgs);
初始化核心配置。
/**
- 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.
*/
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);
}
// 省略部分代码…
}
// 省略部分代码…
}
复制代码
今天我们要重点分析的就是这行代码的内部实现
SnifferConfigInitializer.initializeCoreConfig(agentArgs);
复制代码
初始化核心配置
SnifferConfigInitializer 类使用多种方式初始化配置,内部实现有以下几个重要步骤:
1.loadConfig() 加载配置文件
-
从指定的配置文件路径读取配置文件内容,通过 -Dskywalking_config=/xxx/yyy 可以指定配置文件位置;
-
如果没有指定配置文件路径,则从默认配置文件 config/agent.config 读取;
-
将配置文件内容加载到 Properties;
/**
-
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 {
// System.getProperty() 读取 Java 虚拟机中的系统属性, Java 虚拟机中的系统属性在运行Java程序的时候通过 java -Dk1=v1 配置.
String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH);
// 使用指定的配置文件或默认的配置文件, AgentPackagePath.getPath() 获取 skywalking-agent.jar 所在目录
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.”);
}
复制代码
2.replacePlaceholders() 解析占位符 placeholder
- 从配置文件中读取到的配置值都是以 placeholder 形式(比如 agent.service_name=${SW_AGENT_NAME:Your_ApplicationName})存在的,这里需要将占位符解析为实际值。
/**
-
Replaces all placeholders of format {@code ${name}} with the corresponding property from the supplied {@link
-
Properties}.
-
@param value the value containing the placeholders to be replaced
-
@param properties the {@code Properties} to use for replacement
-
@return the supplied value with placeholders replaced inline
*/
public String replacePlaceholders(String value, final Properties properties) {
return replacePlaceholders(value, new PlaceholderResolver() {
@Override
public String resolvePlaceholder(String placeholderName) {
return getConfigValue(placeholderName, properties);
}
});
}
// 优先级 System.Properties(-D) > System environment variables > Config file
private String getConfigValue(String key, final Properties properties) {
// 从Java虚拟机系统属性中获取(-D)
String value = System.getProperty(key);
if (value == null) {
// 从操作系统环境变量获取, 比如 JAVA_HOME、Path 等环境变量
value = System.getenv(key);
}
if (value == null) {
// 从配置文件中获取
value = properties.getProperty(key);
}
return value;
}
复制代码
3.overrideConfigBySystemProp() 读取 System.getProperties() 中以 skywalking. 开头的系统属性覆盖配置;
/**
-
Override the config by system properties. The property key must start with
skywalking
, the result should be as -
same as in
agent.config
-
-
such as: Property key of
agent.service_name
should beskywalking.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();
// 必须是以 skywalking. 开头的属性
if (key.startsWith(ENV_KEY_PREFIX)) {
String realKey = key.substring(ENV_KEY_PREFIX.length());
AGENT_SETTINGS.put(realKey, prop.getValue());
}
}
}
复制代码
4.overrideConfigByAgentOptions() 解析 agentArgs 参数配置覆盖配置;
- agentArgs 就是 premain 方法的第一个参数,以
-javaagent:/path/to/skywalking-agent.jar=k1=v1,k2=v2
的形式传值。
5.initializeConfig() 将以上读取到的配置信息映射到 Config 类的静态属性,后面会重点分析;
6.configureLogger() 根据配置的 Config.Logging.RESOLVER 重配置 Log,更多关于日志参见文章 SkyWalking Java Agent 日志组件分析;
static void configureLogger() {
switch (Config.Logging.RESOLVER) {
case JSON:
LogManager.setLogResolver(new JsonLogResolver());
break;
case PATTERN:
default:
LogManager.setLogResolver(new PatternLogResolver());
}
}
复制代码
7.必填参数验证,验证非空参数 agent.service_name 和 collector.servers。
定位 skywalking-agent.jar 所在目录
skywalking-agent 目录结构如下:
config 目录存放的是默认配置文件 agent.config,读取默认配置文件,以及后面加载插件都需要用到 skywalking-agent.jar 所在目录。
/**
-
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 {
// System.getProperty() 读取 Java 虚拟机中的系统属性, Java 虚拟机中的系统属性在运行Java程序的时候通过 java -Dk1=v1 配置.
String specifiedConfigPath = System.getProperty(SPECIFIED_CONFIG_PATH);
// 使用指定的配置文件或默认的配置文件, AgentPackagePath.getPath() 获取 skywalking-agent.jar 所在目录
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.”);
}
复制代码
new File(AgentPackagePath.getPath(), DEFAULT_CONFIG_FILE_NAME) 定位默认配置文件的位置, AgentPackagePath.getPath() 方法用来获取 skywalking-agent.jar 所在目录
/**
-
AgentPackagePath is a flag and finder to locate the SkyWalking agent.jar. It gets the absolute path of the agent jar.
-
The path is the required metadata for agent core looking up the plugins and toolkit activations. If the lookup
-
mechanism fails, the agent will exit directly.
*/
public class AgentPackagePath {
private static final ILog LOGGER = LogManager.getLogger(AgentPackagePath.class);
private static File AGENT_PACKAGE_PATH;
public static File getPath() throws AgentPackageNotFoundException {
if (AGENT_PACKAGE_PATH == null) {
// 返回 skywalking-agent.jar 文件所在的目录 E:\develop\source\sample\source\skywalking-java\skywalking-agent
AGENT_PACKAGE_PATH = findPath();
}
return AGENT_PACKAGE_PATH;
}
public static boolean isPathFound() {
return AGENT_PACKAGE_PATH != null;
}
private static File findPath() throws AgentPackageNotFoundException {
// 将 AgentPackagePath 全类名中的.替换成 /
// org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class
String classResourcePath = AgentPackagePath.class.getName().replaceAll(“.”, “/”) + “.class”;
// 使用 AppClassLoader 加载资源,通常情况下 AgentPackagePath 类是被 AppClassLoader 加载的。
URL resource = ClassLoader.getSystemClassLoader().getResource(classResourcePath);
if (resource != null) {
String urlString = resource.toString();
//jar:file:/E:/source/skywalking-java/skywalking-agent/skywalking-agent.jar!/org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class
LOGGER.debug(“The beacon class location is {}.”, urlString);
// 判断 url 中是否包含!,如果包含则说明 AgentPackagePath.class 是包含在jar中。
int insidePathIndex = urlString.indexOf(‘!’);
boolean isInJar = insidePathIndex > -1;
if (isInJar) {
// file:/E:/source/skywalking-java/skywalking-agent/skywalking-agent.jar
urlString = urlString.substring(urlString.indexOf(“file:”), insidePathIndex);
File agentJarFile = null;
try {
// E:\source\skywalking-java\skywalking-agent\skywalking-agent.jar
agentJarFile = new File(new URL(urlString).toURI());
} catch (MalformedURLException | URISyntaxException e) {
LOGGER.error(e, “Can not locate agent jar file by url:” + urlString);
}
if (agentJarFile.exists()) {
// 返回 skywalking-agent.jar 文件所在的目录
return agentJarFile.getParentFile();
}
} else {
int prefixLength = “file:”.length();
String classLocation = urlString.substring(
prefixLength, urlString.length() - classResourcePath.length());
return new File(classLocation);
}
}
LOGGER.error(“Can not locate agent jar file.”);
throw new AgentPackageNotFoundException(“Can not locate agent jar file.”);
}
}
复制代码
最后
既已说到spring cloud alibaba,那对于整个微服务架构,如果想要进一步地向上提升自己,到底应该掌握哪些核心技能呢?
就个人而言,对于整个微服务架构,像RPC、Dubbo、Spring Boot、Spring Cloud Alibaba、Docker、kubernetes、Spring Cloud Netflix、Service Mesh等这些都是最最核心的知识,架构师必经之路!下图,是自绘的微服务架构路线体系大纲,如果有还不知道自己该掌握些啥技术的朋友,可根据小编手绘的大纲进行一个参考。
如果觉得图片不够清晰,也可来找小编分享原件的xmind文档!
且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:
-
出神入化——SpringCloudAlibaba.pdf
-
SpringCloud微服务架构笔记(一).pdf
-
SpringCloud微服务架构笔记(二).pdf
-
SpringCloud微服务架构笔记(三).pdf
-
SpringCloud微服务架构笔记(四).pdf
-
Dubbo框架RPC实现原理.pdf
-
Dubbo最新全面深度解读.pdf
-
Spring Boot学习教程.pdf
-
SpringBoo核心宝典.pdf
-
第一本Docker书-完整版.pdf
-
使用SpringCloud和Docker实战微服务.pdf
-
K8S(kubernetes)学习指南.pdf
另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!
档!
且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:
-
出神入化——SpringCloudAlibaba.pdf
-
SpringCloud微服务架构笔记(一).pdf
-
SpringCloud微服务架构笔记(二).pdf
-
SpringCloud微服务架构笔记(三).pdf
-
SpringCloud微服务架构笔记(四).pdf
-
Dubbo框架RPC实现原理.pdf
-
Dubbo最新全面深度解读.pdf
-
Spring Boot学习教程.pdf
-
SpringBoo核心宝典.pdf
-
第一本Docker书-完整版.pdf
-
使用SpringCloud和Docker实战微服务.pdf
-
K8S(kubernetes)学习指南.pdf
[外链图片转存中…(img-krW3MDEB-1714446738681)]
另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!
[外链图片转存中…(img-pdcLIW3B-1714446738681)]