惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
D
Docker
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
N
Netflix TechBlog - Medium
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
H
Help Net Security
B
Blog
宝玉的分享
宝玉的分享

Nicksxs's Blog

Pi Agent 源码解析(一):从调试环境到双层主循环 6GB显存能跑35B MoE吗:FreeToken极限配置、性能压榨与实操教程 聊聊 Java 的类加载机制一 从ASM到ByteKit再到Arthas:一条Java字节码增强链路 8GB显存如何跑35B:深入理解FreeToken的专家缓存与CPU-GPU协同 让chatgpt来给我讲解下deepseek harness的插件体系 来学习下pi agent的原理 如何在命令行中输出进度条 联想 G400 安装 Windows 7 折腾记录 记一个gitea推送失败的问题 学一下chrome的扩展开发 看下chrome的内置模型 从 app.test 到小锁:valet 本地 HTTPS 的完整链路 浅析一下jpeg图片格式及其来源 关于github拉取下载加速的另一个方式 关于适合什么模型,推荐下llmfit 看看目前本地能跑什么模型,使用llama.cpp 最近使用vibe coding的一些感悟 使用php的inotify扩展来监听文件变更 一些设计模式的记忆点 使用xiaomi mimo大模型api运行Hermes Agent 结合Obsidian的cli的一体化体验 开始尝试使用obsidian作为笔记软件 学习下大神的知识库 体验下微软开源的Markdown转换工具Markitdown 学习下git的worktree 一些架构师知识点的记录 解答一下关于traefik的一点疑惑 记录一下迁移服务器需要使用的一些命令 较早代iPhone更换新iPhone的一些小指南
学习体验下Koupleless框架-浅析代码
2026-01-25 · via Nicksxs's Blog

上次简单体验了下koupleless框架,可以发现ark模块的加载运行是非常有优势的,
这次就来看下这个模块式怎么加载的
我们可以通过启动基座使用调试模式,然后打下断点在ArkClient这个类的几个核心方法
比如com.alipay.sofa.ark.api.ArkClient#installBiz(java.io.File)
核心方法是在这

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private static ClientResponse doInstallBiz(File bizFile, String[] args, Map<String, String> envs) throws Throwable {
AssertUtils.assertNotNull(bizFactoryService, "bizFactoryService must not be null!");
AssertUtils.assertNotNull(bizManagerService, "bizManagerService must not be null!");
AssertUtils.assertNotNull(bizFile, "bizFile must not be null!");
long start = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss,SSS");
String startDate = sdf.format(new Date(start));
Biz biz = bizFactoryService.createBiz(bizFile);
ClientResponse response = new ClientResponse();
if (bizManagerService.getBizByIdentity(biz.getIdentity()) == null && bizManagerService.registerBiz(biz)) {
try {
biz.start(args, envs);
long end = System.currentTimeMillis();
response.setCode(ResponseCode.SUCCESS).setMessage(String.format("Install Biz: %s success, cost: %s ms, started at: %s", biz.getIdentity(), end - start, startDate)).setBizInfos(Collections.singleton(biz));
getLogger().info(response.getMessage());
return response;
} catch (Throwable var15) {
long end = System.currentTimeMillis();
response.setCode(ResponseCode.FAILED).setMessage(String.format("Install Biz: %s fail,cost: %s ms, started at: %s", biz.getIdentity(), end - start, startDate));
getLogger().error(response.getMessage(), var15);
boolean autoUninstall = Boolean.parseBoolean(ArkConfigs.getStringValue("sofa.ark.auto.uninstall.when.failed.enable", "true"));
if (autoUninstall) {
try {
getLogger().error(String.format("Start Biz: %s failed, try to unInstall this biz.", biz.getIdentity()));
biz.stop();
} catch (Throwable var14) {
getLogger().error(String.format("UnInstall Biz: %s fail.", biz.getIdentity()), var14);
}
}

throw var15;
}
} else {
return response.setCode(ResponseCode.REPEAT_BIZ).setMessage(String.format("Biz: %s has been installed or registered.", biz.getIdentity()));
}
}

具体的代码在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Biz createBiz(File file) throws IOException {
boolean unpackBizWhenInstall = Boolean.parseBoolean(ArkConfigs.getStringValue("sofa.ark.unpack.biz.when.install", "true"));
Object bizArchive;
if (ArkConfigs.isEmbedEnable() && unpackBizWhenInstall) {
File unpackFile = FileUtils.file(file.getAbsolutePath() + "-unpack");
if (!unpackFile.exists()) {
unpackFile = FileUtils.unzip(file, file.getAbsolutePath() + "-unpack");
}

if (file.exists()) {
file.delete();
}

file = unpackFile;
bizArchive = new ExplodedBizArchive(unpackFile);
} else {
JarFile bizFile = new JarFile(file);
JarFileArchive jarFileArchive = new JarFileArchive(bizFile);
bizArchive = new JarBizArchive(jarFileArchive);
}

BizModel biz = (BizModel)this.createBiz((BizArchive)bizArchive);
biz.setBizTempWorkDir(file);
return biz;
}

接下来是创建biz模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Biz createBiz(BizArchive bizArchive) throws IOException {
AssertUtils.isTrue(this.isArkBiz(bizArchive), "Archive must be a ark biz!", new Object[0]);
BizModel bizModel = new BizModel();
Attributes manifestMainAttributes = bizArchive.getManifest().getMainAttributes();
String mainClass = manifestMainAttributes.getValue("Main-Class");
String startClass = manifestMainAttributes.getValue("Start-Class");
bizModel.setBizState(BizState.RESOLVED, StateChangeReason.CREATED).setBizName(manifestMainAttributes.getValue("Ark-Biz-Name")).setBizVersion(manifestMainAttributes.getValue("Ark-Biz-Version")).setMainClass(!StringUtils.isEmpty(startClass) ? startClass : mainClass).setPriority(manifestMainAttributes.getValue("priority")).setWebContextPath(manifestMainAttributes.getValue("web-context-path")).setDenyImportPackages(manifestMainAttributes.getValue("deny-import-packages")).setDenyImportClasses(manifestMainAttributes.getValue("deny-import-classes")).setDenyImportResources(manifestMainAttributes.getValue("deny-import-resources")).setInjectPluginDependencies(this.getInjectDependencies(manifestMainAttributes.getValue("inject-plugin-dependencies"))).setInjectExportPackages(manifestMainAttributes.getValue("inject-export-packages")).setDeclaredLibraries(manifestMainAttributes.getValue("declared-libraries")).setClassPath(bizArchive.getUrls()).setPluginClassPath(this.getPluginURLs());
if (!(bizArchive instanceof DirectoryBizArchive)) {
bizModel.setBizUrl(bizArchive.getUrl());
}

BizClassLoader bizClassLoader = new BizClassLoader(bizModel.getIdentity(), this.getBizUcp(bizModel.getClassPath()), bizArchive instanceof ExplodedBizArchive || bizArchive instanceof DirectoryBizArchive);
bizClassLoader.setBizModel(bizModel);
bizModel.setClassLoader(bizClassLoader);
return bizModel;
}

这里就会读取对应biz包的启动类等,以及创建对应的biz模块的类加载器 BizClassLoader
接下去回到上一层

1
biz.start(args, envs);

接下来就是BizModel的start方法

1
2
3
public void start(String[] args, Map<String, String> envs) throws Throwable {
this.doStart(args, envs);
}

实际的就是doStart方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private void doStart(String[] args, Map<String, String> envs) throws Throwable {
AssertUtils.isTrue(this.bizState == BizState.RESOLVED, "BizState must be RESOLVED", new Object[0]);
if (envs != null) {
String mainClassFromEnv = (String)envs.get("sofa.ark.biz.main.class");
if (mainClassFromEnv != null) {
this.mainClass = mainClassFromEnv;
ArkLoggerFactory.getDefaultLogger().info("Ark biz {} will start with main class {} from envs", this.getIdentity(), mainClassFromEnv);
}
}

if (this.mainClass == null) {
throw new ArkRuntimeException(String.format("biz: %s has no main method", this.getBizName()));
} else {
ClassLoader oldClassLoader = ClassLoaderUtils.pushContextClassLoader(this.classLoader);
EventAdminService eventAdminService = (EventAdminService)ArkServiceContainerHolder.getContainer().getService(EventAdminService.class);

try {
eventAdminService.sendEvent(new BeforeBizStartupEvent(this));
this.resetProperties();
if (!this.isMasterBizAndEmbedEnable()) {
long start = System.currentTimeMillis();
ArkLoggerFactory.getDefaultLogger().info("Ark biz {} start.", this.getIdentity());
MainMethodRunner mainMethodRunner = new MainMethodRunner(this.mainClass, args, envs);
mainMethodRunner.run();
eventAdminService.sendEvent(new AfterBizStartupEvent(this));
ArkLoggerFactory.getDefaultLogger().info("Ark biz {} started in {} ms", this.getIdentity(), System.currentTimeMillis() - start);
}
} catch (Throwable var11) {
this.setBizState(BizState.BROKEN, StateChangeReason.INSTALL_FAILED, getStackTraceAsString(var11));
eventAdminService.sendEvent(new AfterBizStartupFailedEvent(this, var11));
throw var11;
} finally {
ClassLoaderUtils.popContextClassLoader(oldClassLoader);
}

BizManagerService bizManagerService = (BizManagerService)ArkServiceContainerHolder.getContainer().getService(BizManagerService.class);
if (bizManagerService.getActiveBiz(this.bizName) == null) {
this.setBizState(BizState.ACTIVATED, StateChangeReason.STARTED);
} else {
boolean activateMultiBizVersion = Boolean.parseBoolean(ArkConfigs.getStringValue("sofa.ark.activate.multi.biz.version.enable", "false"));
if (activateMultiBizVersion) {
this.setBizState(BizState.ACTIVATED, StateChangeReason.STARTED);
} else {
if (Boolean.getBoolean("activate.new.module")) {
Biz currentActiveBiz = bizManagerService.getActiveBiz(this.bizName);
((BizModel)currentActiveBiz).setBizState(BizState.DEACTIVATED, StateChangeReason.SWITCHED, String.format("switch to new biz %s", this.getIdentity()));
this.setBizState(BizState.ACTIVATED, StateChangeReason.STARTED, String.format("switch from old biz: %s", currentActiveBiz.getIdentity()));
} else {
this.setBizState(BizState.DEACTIVATED, StateChangeReason.STARTED, "start but is deactivated");
}

}
}
}
}

主要是看这个方法

1
2
3
ArkLoggerFactory.getDefaultLogger().info("Ark biz {} start.", this.getIdentity());
MainMethodRunner mainMethodRunner = new MainMethodRunner(this.mainClass, args, envs);
mainMethodRunner.run();

看到这个run方法

1
2
3
4
5
public Object run() throws Exception {
Class<?> mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
return mainMethod.invoke((Object)null, this.args);
}

最终就是到这个,它就用了这个上下文的类加载器,而这个类加载器就是用的前面设置的bizClassLoader

1
2
3
4
5
public static ClassLoader pushContextClassLoader(ClassLoader newClassLoader) {
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(newClassLoader);
return oldClassLoader;
}