启动过程
Ark 1.0 非内嵌模式
打包方式
在 SOFAArk 1.0 中使用 sofa-ark-maven-plugin 打包
<build>
<plugins>
<plugin>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-ark-maven-plugin</artifactId>
<version>${sofa.ark.version}</version>
<executions>
<execution>
<id>default-cli</id>
<!--goal executed to generate executable-ark-jar -->
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<outputDirectory>./target</outputDirectory>
<!--default none-->
<arkClassifier>executable-ark</arkClassifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
启动流程图
Ark 1.0 应用的整体启动流程如下图所述:
启动方式
方式一、IDEA 启动
使用 idea 启动 SpringBoot Application 即可
方式二、命令行启动
Ark 包是可执行 Jar,可直接使用 java -jar 的方式启动,先使用 mvn clean package 进行打包,打包得到 ${bizName}-${bizVersion}-executable-ark.jar,命令行启动
java -jar ${bizName}-${bizVersion}-executable-ark.jar
启动原理分析
Springboot 应用,ArkApplicationStartListener 实现了 ApplicationListener 接口,监听 Spring 的启动事件,调用SofaArkBootstrap.launch(args)
启动 Ark。
public class ArkApplicationStartListener implements ApplicationListener<SpringApplicationEvent> {
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
try {
if (isSpringBoot2()
&& APPLICATION_STARTING_EVENT.equals(event.getClass().getCanonicalName())) {
startUpArk(event);
}
if (isSpringBoot1()
&& APPLICATION_STARTED_EVENT.equals(event.getClass().getCanonicalName())) {
startUpArk(event);
}
} catch (Throwable e) {
throw new RuntimeException("Meet exception when determine whether to start SOFAArk!", e);
}
}
public void startUpArk(SpringApplicationEvent event) {
if (LAUNCH_CLASSLOADER_NAME.equals(this.getClass().getClassLoader().getClass().getName())) {
// Ark 启动入口,非 Springboot 应用需要手动调用该方法
SofaArkBootstrap.launch(event.getArgs());
}
}
public boolean isSpringBoot1() {
return SpringBootVersion.getVersion().startsWith("1");
}
public boolean isSpringBoot2() {
return SpringBootVersion.getVersion().startsWith("2");
}
}
SofaArkBootstrap launch 方法里面启了一个线程执行SofaArkBootstrap.remain
方法,remain 里面调ClasspathLauncher.launch
方法。
public class SofaArkBootstrap {
private static final String BIZ_CLASSLOADER = "com.alipay.sofa.ark.container.service.classloader.BizClassLoader";
private static final String MAIN_ENTRY_NAME = "remain";
private static EntryMethod entryMethod;
public static void launch(String[] args) {
try {
if (!isSofaArkStarted()) {
entryMethod = new EntryMethod(Thread.currentThread());
IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(
entryMethod.getDeclaringClassName());
// 参数中指定当前类的remain方法,LaunchRunner.run 里面会用反射调用remain方法
LaunchRunner launchRunner = new LaunchRunner(SofaArkBootstrap.class.getName(),
MAIN_ENTRY_NAME, args);
Thread launchThread = new Thread(threadGroup, launchRunner,
entryMethod.getMethodName());
launchThread.start();
// 等待前面的线程执行完成
LaunchRunner.join(threadGroup);
threadGroup.rethrowUncaughtException();
System.exit(0);
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private static void remain(String[] args) throws Exception {// NOPMD
// 在一个新的线程里面执行该方法
AssertUtils.assertNotNull(entryMethod, "No Entry Method Found.");
URL[] urls = getURLClassPath();
new ClasspathLauncher(new ClassPathArchive(entryMethod.getDeclaringClassName(),
entryMethod.getMethodName(), urls)).launch(args, getClasspath(urls),
entryMethod.getMethod());
}
}
ClasspathLauncher launch 方法在基类 AbstractLauncher 里面,会先创建 ContainerClassLoader,然后修改当前线程的 classLoader,通过 ContainerClassLoader 加载 com.alipay.sofa.ark.container.ArkContainer,然后使用反射执行 com.alipay.sofa.ark.container.ArkContainer.main 方法。
public abstract class AbstractLauncher {
/**
* Launch the ark container. This method is the initial entry point when execute an fat jar.
* @throws Exception if the ark container fails to launch.
*/
public Object launch(String[] args) throws Exception {
JarFile.registerUrlProtocolHandler();
// 创建 ContainerClassLoader
ClassLoader classLoader = createContainerClassLoader(getContainerArchive());
List<String> attachArgs = new ArrayList<>();
attachArgs
.add(String.format("%s%s=%s", CommandArgument.ARK_CONTAINER_ARGUMENTS_MARK,
CommandArgument.FAT_JAR_ARGUMENT_KEY, getExecutableArchive().getUrl()
.toExternalForm()));
attachArgs.addAll(Arrays.asList(args));
return launch(attachArgs.toArray(new String[attachArgs.size()]), getMainClass(),
classLoader);
}
protected Object launch(String[] args, String mainClass, ClassLoader classLoader)
throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
// 修改线程的classLoader
Thread.currentThread().setContextClassLoader(classLoader);
// 通过反射执行 com.alipay.sofa.ark.container.ArkContainer.main
return createMainMethodRunner(mainClass, args).run();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
// ......
}
ArkContainer main 方法里面,会创建一个 ArkContainer 实例,然后执行 start 方法,start 方法中会获取 Pipeline,然后执行 StandardPipeline。
public class ArkContainer {
// ......
public Object start() throws ArkRuntimeException {
AssertUtils.assertNotNull(arkServiceContainer, "arkServiceContainer is null !");
if (started.compareAndSet(false, true)) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
stop();
}
}));
prepareArkConfig();
reInitializeArkLogger();
arkServiceContainer.start();
// 获取 Pipeline
Pipeline pipeline = arkServiceContainer.getService(Pipeline.class);
// 执行 Pipeline
pipeline.process(pipelineContext);
// Pipeline 执行完成之后 Ark 启动成功
System.out.println("Ark container started in " + (System.currentTimeMillis() - start) //NOPMD
+ " ms.");
}
return this;
}
// ......
}
StandardPipeline 里面内置了 6 个 Stage,会按顺序执行。
public class StandardPipeline implements Pipeline {
private static final ArkLogger LOGGER = ArkLoggerFactory.getDefaultLogger();
private List<PipelineStage> stages = new ArrayList<>();
public StandardPipeline() {
initializePipeline();
}
private void initializePipeline() {
// 初始化 Stage
addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(HandleArchiveStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(RegisterServiceStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(ExtensionLoaderStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(DeployPluginStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(DeployBizStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(FinishStartupStage.class));
}
@Override
public Pipeline addPipelineStage(PipelineStage pipelineStage) {
stages.add(pipelineStage);
return this;
}
@Override
public void process(PipelineContext pipelineContext) throws ArkRuntimeException {
for (PipelineStage pipelineStage : stages) {
try {
LOGGER.info(String.format("Start to process pipeline stage: %s", pipelineStage
.getClass().getName()));
// 按顺序执行 Stage,有一个 Stage 执行报错都会终止 ark 启动
pipelineStage.process(pipelineContext);
LOGGER.info(String.format("Finish to process pipeline stage: %s", pipelineStage
.getClass().getName()));
} catch (Throwable e) {
LOGGER.error(String.format("Process pipeline stage fail: %s", pipelineStage
.getClass().getName()), e);
throw new ArkRuntimeException(e);
}
}
}
}
Ark 2.0 内嵌模式
打包方式
在 SOFAArk 2.0 中基座是采用 spring-boot 原生打包插件 spring-boot-maven-plugin 打包
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.6</version>
<configuration>
<outputDirectory>target</outputDirectory>
<classifier>ark-biz</classifier>
</configuration>
<executions>
<execution>
<id>package</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
启动流程图
启动方式
方式一、IDEA 启动
本地启动需要加上启动参数
-Dsofa.ark.embed.enable=true -Dcom.alipay.sofa.ark.master.biz=${bizName}
方式二、命令行启动
Ark包是可执行Jar,可直接使用Java -jar的方式启动,先使用 mvn clean package 进行打包,打包得到 ${bizName}-${bizVersion}-ark-biz.jar,命令行启动
java -jar -Dsofa.ark.embed.enable=true -Dcom.alipay.sofa.ark.master.biz=${bizName} ${bizName}-${bizVersion}-ark-biz.jar
启动原理分析
启动入口
入口和 1.0 一样,使用 ArkApplicationStartListener 监听 Spring 的启动事件,调用EmbedSofaArkBootstrap.launch
启动 Ark。
public class ArkApplicationStartListener implements ApplicationListener<SpringApplicationEvent> {
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
try {
if (ArkConfigs.isEmbedEnable()
|| LaunchedURLClassLoader.class.isAssignableFrom(this.getClass().getClassLoader()
.getClass())) {
ArkConfigs.setEmbedEnable(true);
// Ark 2.0 内嵌模式
startUpArkEmbed(event);
return;
}
if (isSpringBoot2()
&& APPLICATION_STARTING_EVENT.equals(event.getClass().getCanonicalName())) {
startUpArk(event);
}
if (isSpringBoot1()
&& APPLICATION_STARTED_EVENT.equals(event.getClass().getCanonicalName())) {
startUpArk(event);
}
} catch (Throwable e) {
throw new RuntimeException("Meet exception when determine whether to start SOFAArk!", e);
}
}
// ......
protected void startUpArkEmbed(SpringApplicationEvent event) {
if (this.getClass().getClassLoader() != Thread.currentThread().getContextClassLoader()) {
return;
}
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent preparedEvent = (ApplicationEnvironmentPreparedEvent) event;
// Ark 启动入口
EmbedSofaArkBootstrap.launch(preparedEvent.getEnvironment());
}
if (event instanceof ApplicationReadyEvent) {
if (ArkClient.getEventAdminService() != null && ArkClient.getMasterBiz() != null) {
ArkClient.getEventAdminService().sendEvent(
new AfterBizStartupEvent(ArkClient.getMasterBiz()));
ArkClient.getEventAdminService().sendEvent(new AfterFinishDeployEvent());
ArkClient.getEventAdminService().sendEvent(new AfterFinishStartupEvent());
}
}
}
}
EmbedSofaArkBootstrap launch 方法里面直接调ClasspathLauncher.launch
,此处和 1.0 的处理有些差异。
public class EmbedSofaArkBootstrap {
private static AtomicBoolean started = new AtomicBoolean(false);
public static void launch(Environment environment) {
if (started.compareAndSet(false, true)) {
EntryMethod entryMethod = new EntryMethod(Thread.currentThread());
getOrSetDefault(
Constants.MASTER_BIZ,
environment.getProperty(Constants.MASTER_BIZ,
environment.getProperty("spring.application.name")));
getOrSetDefault(Constants.BIZ_CLASS_LOADER_HOOK_DIR,
environment.getProperty(Constants.BIZ_CLASS_LOADER_HOOK_DIR));
getOrSetDefault(Constants.PLUGIN_EXPORT_CLASS_ENABLE,
environment.getProperty(Constants.PLUGIN_EXPORT_CLASS_ENABLE, "false"));
getOrSetDefault(Constants.BIZ_CLASS_LOADER_HOOK_DIR,
DelegateToMasterBizClassLoaderHook.class.getName());
try {
URL[] urls = getURLClassPath();
ClasspathLauncher launcher = new ClasspathLauncher(new EmbedClassPathArchive(
entryMethod.getDeclaringClassName(), entryMethod.getMethod().getName(), urls));
// 调 ClasspathLauncher.launch
launcher.launch(new String[] {}, getClasspath(urls), entryMethod.getMethod());
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
// ......
}
ClasspathLauncher launch 方法内容和 Ark 1.0 类似,会先创建 ContainerClassLoader,然后修改当前线程的 classLoader,通过 ContainerClassLoader 加载 com.alipay.sofa.ark.container.ArkContainer,然后使用反射执行 com.alipay.sofa.ark.container.ArkContainer.main 方法。
ArkContainer main 方法里面,会创建一个 ArkContainer 实例,然后执行 start 方法,开始启动容器服务。
public class ArkContainer {
// .....
public static Object main(String[] args) throws ArkRuntimeException {
if (args.length < MINIMUM_ARGS_SIZE) {
throw new ArkRuntimeException("Please provide suitable arguments to continue !");
}
try {
LaunchCommand launchCommand = LaunchCommand.parse(args);
if (launchCommand.isExecutedByCommandLine()) {
ExecutableArkBizJar executableArchive;
File rootFile = new File(URLDecoder.decode(launchCommand.getExecutableArkBizJar()
.getFile()));
if (rootFile.isDirectory()) {
executableArchive = new ExecutableArkBizJar(new ExplodedArchive(rootFile));
} else {
executableArchive = new ExecutableArkBizJar(new JarFileArchive(rootFile,
launchCommand.getExecutableArkBizJar()));
}
return new ArkContainer(executableArchive, launchCommand).start();
} else {
ClassPathArchive classPathArchive;
if (ArkConfigs.isEmbedEnable()) {
// Ark 2.0 内嵌模式
classPathArchive = new EmbedClassPathArchive(launchCommand.getEntryClassName(),
launchCommand.getEntryMethodName(), launchCommand.getClasspath());
} else {
classPathArchive = new ClassPathArchive(launchCommand.getEntryClassName(),
launchCommand.getEntryMethodName(), launchCommand.getClasspath());
}
return new ArkContainer(classPathArchive, launchCommand).start();
}
} catch (IOException e) {
throw new ArkRuntimeException(String.format("SOFAArk startup failed, commandline=%s",
LaunchCommand.toString(args)), e);
}
}
// ......
public Object start() throws ArkRuntimeException {
AssertUtils.assertNotNull(arkServiceContainer, "arkServiceContainer is null !");
if (started.compareAndSet(false, true)) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
stop();
}
}));
prepareArkConfig();
reInitializeArkLogger();
// 启动容器服务
arkServiceContainer.start();
// 从容器服务中获取 Pipeline 实例,底层是从 Guice 中获取实例
Pipeline pipeline = arkServiceContainer.getService(Pipeline.class);
// 执行流水线
pipeline.process(pipelineContext);
// Ark 启动完成
System.out.println("Ark container started in " + (System.currentTimeMillis() - start) //NOPMD
+ " ms.");
}
return this;
}
}
启动容器服务
ArkServiceContainer 是基于 Guice 实现的容器服务,Guice 是 Google开发的, 一个轻量级的依赖注入框架。类似Spring 的依赖注入。通过 Guice 管理 Ark 容器服务相关的 bean。
public class ArkServiceContainer {
private Injector injector;
private List<ArkService> arkServiceList = new ArrayList<>();
private AtomicBoolean started = new AtomicBoolean(false);
private AtomicBoolean stopped = new AtomicBoolean(false);
private final String[] arguments;
private static final ArkLogger LOGGER = ArkLoggerFactory.getDefaultLogger();
public ArkServiceContainer(String[] arguments) {
this.arguments = arguments;
}
/**
* Start Ark Service Container
* @throws ArkRuntimeException
* @since 0.1.0
*/
public void start() throws ArkRuntimeException {
if (started.compareAndSet(false, true)) {
ClassLoader oldClassLoader = ClassLoaderUtils.pushContextClassLoader(getClass()
.getClassLoader());
try {
LOGGER.info("Begin to start ArkServiceContainer");
// Guice 是 Google开发的, 一个轻量级的依赖注入框架
injector = Guice.createInjector(findServiceModules());
// 从 guice 中查询所有 ArkService 实例
for (Binding<ArkService> binding : injector
.findBindingsByType(new TypeLiteral<ArkService>() {
})) {
arkServiceList.add(binding.getProvider().get());
}
Collections.sort(arkServiceList, new OrderComparator());
for (ArkService arkService : arkServiceList) {
LOGGER.info(String.format("Init Service: %s", arkService.getClass().getName()));
// 初始化 arkService,一共有 4 个 ArkService,分别是:
// PluginDeployService:部署 plugin 的服务
// BizDeployService: 部署 biz 包的服务
// ClassLoaderService: ClassLoader 服务
// StandardTelnetServer: Telnet 工具服务
arkService.init();
}
ArkServiceContainerHolder.setContainer(this);
ArkClient.setBizFactoryService(getService(BizFactoryService.class));
ArkClient.setBizManagerService(getService(BizManagerService.class));
ArkClient.setInjectionService(getService(InjectionService.class));
ArkClient.setEventAdminService(getService(EventAdminService.class));
ArkClient.setArguments(arguments);
LOGGER.info("Finish to start ArkServiceContainer");
} finally {
ClassLoaderUtils.popContextClassLoader(oldClassLoader);
}
}
}
private List<AbstractArkGuiceModule> findServiceModules() throws ArkRuntimeException {
try {
List<AbstractArkGuiceModule> modules = new ArrayList<>();
// 通过 java spi 加载 Module
for (AbstractArkGuiceModule module : ServiceLoader.load(AbstractArkGuiceModule.class)) {
modules.add(module);
}
return modules;
} catch (Throwable e) {
throw new ArkRuntimeException(e);
}
}
// ......
}
````
com.alipay.sofa.ark.common.guice.AbstractArkGuiceModule 文件中配置了 spi 实现 com.alipay.sofa.ark.container.guice.ContainerModule, ContainerModule 里配置了所有 ark 用到的实例,这些实例通过 @Inject 即可自动注入:
```java
public class ContainerModule extends AbstractArkGuiceModule {
@Override
protected void configure() {
// 当需要 Pipeline 的实例时,我们注入 StandardPipeline 的实例作为依赖
binder().bind(Pipeline.class).to(StandardPipeline.class);
Multibinder<ArkService> arkServiceMultibinder = Multibinder.newSetBinder(binder(),
ArkService.class);
// ArkService 有4个类型的实例
arkServiceMultibinder.addBinding().to(PluginDeployServiceImpl.class);
arkServiceMultibinder.addBinding().to(BizDeployServiceImpl.class);
arkServiceMultibinder.addBinding().to(ClassLoaderServiceImpl.class);
arkServiceMultibinder.addBinding().to(StandardTelnetServerImpl.class);
// 当需要 PluginManagerService 的实例时,我们注入 PluginManagerServiceImpl 的实例作为依赖
binder().bind(PluginManagerService.class).to(PluginManagerServiceImpl.class);
// 下面是一样的道理
binder().bind(BizManagerService.class).to(BizManagerServiceImpl.class);
binder().bind(ClassLoaderService.class).to(ClassLoaderServiceImpl.class);
binder().bind(PluginDeployService.class).to(PluginDeployServiceImpl.class);
binder().bind(BizDeployService.class).to(BizDeployServiceImpl.class);
binder().bind(RegistryService.class).to(RegistryServiceImpl.class);
binder().bind(InjectionService.class).to(InjectionServiceImpl.class);
binder().bind(TelnetServerService.class).to(StandardTelnetServerImpl.class);
binder().bind(BizFactoryService.class).to(BizFactoryServiceImpl.class);
binder().bind(PluginFactoryService.class).to(PluginFactoryServiceImpl.class);
binder().bind(ExtensionLoaderService.class).to(ExtensionLoaderServiceImpl.class);
binder().bind(EventAdminService.class).to(EventAdminServiceImpl.class);
}
}
执行流水线
容器服务 arkServiceContainer 启动完成之后,就容器服务中获取 Pipeline 实例,执行流水线,下面看一下 StandardPipeline 的源码:
// 在容器中是单例对象
@Singleton
public class StandardPipeline implements Pipeline {
private static final ArkLogger LOGGER = ArkLoggerFactory.getDefaultLogger();
private List<PipelineStage> stages = new ArrayList<>();
public StandardPipeline() {
initializePipeline();
}
private void initializePipeline() {
// 一共有 6 个步骤
addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(HandleArchiveStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(RegisterServiceStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(ExtensionLoaderStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(DeployPluginStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(DeployBizStage.class))
.addPipelineStage(
ArkServiceContainerHolder.getContainer().getService(FinishStartupStage.class));
}
@Override
public Pipeline addPipelineStage(PipelineStage pipelineStage) {
stages.add(pipelineStage);
return this;
}
@Override
public void process(PipelineContext pipelineContext) throws ArkRuntimeException {
for (PipelineStage pipelineStage : stages) {
try {
LOGGER.info(String.format("Start to process pipeline stage: %s", pipelineStage
.getClass().getName()));
// 执行每个步骤
pipelineStage.process(pipelineContext);
LOGGER.info(String.format("Finish to process pipeline stage: %s", pipelineStage
.getClass().getName()));
} catch (Throwable e) {
LOGGER.error(String.format("Process pipeline stage fail: %s", pipelineStage
.getClass().getName()), e);
throw new ArkRuntimeException(e);
}
}
}
}
Archive 解析
Ark 2.0 模式下,在这个步骤里会创建 master biz,创建 master biz 的过程见 processEmbed 方法和 BizFactoryServiceImpl 里面的 createEmbedMasterBiz,并且 master biz 是使用 LaunchedURLClassLoader 加载的(本地启动是用 AppClassLoader) 。创建完 master biz 之后进行安装 plugin。
// HandleArchiveStage 类
protected void processEmbed(PipelineContext pipelineContext) throws Exception {
// 获取到 Launcher$AppClassLoader
ClassLoader masterBizClassLoader = pipelineContext.getClass().getClassLoader();
// 创建 master biz
Biz masterBiz = bizFactoryService.createEmbedMasterBiz(masterBizClassLoader);
bizManagerService.registerBiz(masterBiz);
ArkClient.setMasterBiz(masterBiz);
ArkConfigs.putStringValue(Constants.MASTER_BIZ, masterBiz.getBizName());
ExecutableArchive executableArchive = pipelineContext.getExecutableArchive();
// 获取 plugin 包
List<PluginArchive> pluginArchives = executableArchive.getPluginArchives();
for (PluginArchive pluginArchive : pluginArchives) {
// jar 包里面带有 com/alipay/sofa/ark/plugin/mark 文件的都是 plugin
Plugin plugin = pluginFactoryService.createEmbedPlugin(pluginArchive,
masterBizClassLoader);
if (!isPluginExcluded(plugin)) {
pluginManagerService.registerPlugin(plugin);
} else {
LOGGER.warn(String.format("The plugin of %s is excluded.", plugin.getPluginName()));
}
}
return;
}
// BizFactoryServiceImpl 类
public Biz createEmbedMasterBiz(ClassLoader masterClassLoader) {
BizModel bizModel = new BizModel();
bizModel.setBizState(BizState.RESOLVED).setBizName(ArkConfigs.getStringValue(MASTER_BIZ))
.setBizVersion("1.0.0").setMainClass("embed main").setPriority("100")
.setWebContextPath("/").setDenyImportPackages(null).setDenyImportClasses(null)
.setDenyImportResources(null).setInjectPluginDependencies(new HashSet<>())
.setInjectExportPackages(null)
.setClassPath(((URLClassLoader) masterClassLoader).getURLs())
.setClassLoader(masterClassLoader);
return bizModel;
}
// EmbedClassPathArchive 类
@Override
public List<PluginArchive> getPluginArchives() throws Exception {
// 扫描 plugin 包,ARK_PLUGIN_MARK_ENTRY="com/alipay/sofa/ark/container/mark"
List<URL> urlList = filterUrls(Constants.ARK_PLUGIN_MARK_ENTRY);
List<PluginArchive> pluginArchives = new ArrayList<>();
for (URL url : urlList) {
pluginArchives.add(new JarPluginArchive(getUrlJarFileArchive(url)));
}
return pluginArchives;
}
注册容器服务
RegisterServiceStage
这一步是将所有 Ark 相关的服务注册到 com.alipay.sofa.ark.container.service.registry.RegistryServiceImpl#services 里去,并扫描服务中的 @ArkInject 注解,进行自动注入 Ark 服务。为什么要引入 @ArkInject?主要是为了方便开发高级特性,使用注解 @ArkInject 引用服务。SOFAArk 容器默认将内部功能组件发布成了服务,包括 Biz 管理,Plugin 管理,事件管理,服务注册管理。
// RegisterServiceStage 类
private void registryDefaultService() {
/**
* some basic container service is not allowed to be override, they are only published
* to be referenced by plugin and biz, even depended by other container service.
*/
registryService.publishService(BizManagerService.class, ArkServiceContainerHolder
.getContainer().getService(BizManagerService.class), new ContainerServiceProvider(
PriorityOrdered.HIGHEST_PRECEDENCE));
registryService.publishService(BizFactoryService.class, ArkServiceContainerHolder
.getContainer().getService(BizFactoryService.class), new ContainerServiceProvider(
PriorityOrdered.HIGHEST_PRECEDENCE));
registryService.publishService(PluginManagerService.class, ArkServiceContainerHolder
.getContainer().getService(PluginManagerService.class), new ContainerServiceProvider(
PriorityOrdered.HIGHEST_PRECEDENCE));
registryService.publishService(PluginFactoryService.class, ArkServiceContainerHolder
.getContainer().getService(PluginFactoryService.class), new ContainerServiceProvider(
PriorityOrdered.HIGHEST_PRECEDENCE));
registryService.publishService(EventAdminService.class, ArkServiceContainerHolder
.getContainer().getService(EventAdminService.class), new ContainerServiceProvider(
PriorityOrdered.HIGHEST_PRECEDENCE));
registryService.publishService(RegistryService.class, ArkServiceContainerHolder
.getContainer().getService(RegistryService.class), new ContainerServiceProvider(
PriorityOrdered.HIGHEST_PRECEDENCE));
/**
* some container service which may depends on other basic container service.
*/
registryService.publishService(BizDeployer.class, new DefaultBizDeployer(),
new ContainerServiceProvider());
registryService.publishService(CommandProvider.class, new PluginCommandProvider(),
PLUGIN_COMMAND_UNIQUE_ID, new ContainerServiceProvider());
registryService.publishService(CommandProvider.class, new BizCommandProvider(),
BIZ_COMMAND_UNIQUE_ID, new ContainerServiceProvider());
}
// RegistryServiceImpl 类
public <T> ServiceReference<T> publishService(Class<T> ifClass, T implObject, String uniqueId,
ServiceProvider serviceProvider) {
AssertUtils.assertNotNull(ifClass, "Service interface should not be null.");
AssertUtils.assertNotNull(implObject, "Service implementation should not be null.");
AssertUtils.assertNotNull(uniqueId, "Service uniqueId should not be null.");
AssertUtils.assertNotNull(serviceProvider, "ServiceProvider should not be null.");
ServiceMetadata serviceMetadata = new ServiceMetadataImpl(ifClass, uniqueId,
serviceProvider);
for (ServiceReference<?> serviceReference : services) {
// services 中已经存在这个服务,不重复注册
if (serviceMetadata.equals(serviceReference.getServiceMetadata())) {
LOGGER.warn(String.format("Service: %s publish by: %s already exist",
serviceMetadata.getServiceName(), serviceProvider));
return (ServiceReference<T>) serviceReference;
}
}
ServiceReference<T> serviceReference = new ServiceReferenceImpl<>(serviceMetadata,
implObject);
// 处理服务中的 @ArkInject ,自动注入依赖
injectionService.inject(serviceReference);
LOGGER.info(String.format("Service: %s publish by: %s succeed",
serviceMetadata.getServiceName(), serviceProvider));
services.add(serviceReference);
return serviceReference;
}
// InjectionServiceImpl 类
private void inject(final Object instance, final String type) {
ReflectionUtils.doWithFields(instance.getClass(), new FieldCallback() {
@Override
public void doWith(Field field) throws ArkRuntimeException {
// 查找 @ArkInject 注解
ArkInject arkInject = field.getAnnotation(ArkInject.class);
if (arkInject == null) {
return;
}
Class<?> serviceType = arkInject.interfaceType() == void.class ? field.getType()
: arkInject.interfaceType();
Object value = getService(serviceType, arkInject.uniqueId());
if (value == null) {
LOGGER.warn(String.format("Inject {field= %s} of {service= %s} fail!",
field.getName(), type));
return;
}
ReflectionUtils.makeAccessible(field);
try {
// 自动注入
field.set(instance, value);
LOGGER.info(String.format("Inject {field= %s} of {service= %s} success!",
field.getName(), type));
} catch (Throwable throwable) {
throw new ArkRuntimeException(throwable);
}
}
});
}
private Object getService(Class serviceType, String uniqueId) {
ServiceReference serviceReference = registryService.referenceService(serviceType, uniqueId);
return serviceReference == null ? null : serviceReference.getService();
}
初始化环境
ExtensionLoaderStage
这一步做的事情比较简单,将 ExtensionLoaderService 实例设置到 ArkServiceLoader 的静态属性上,方便使用静态方法就能获取到 ExtensionLoaderService 实例。
// ExtensionLoaderStage 类
public void process(PipelineContext pipelineContext) throws ArkRuntimeException {
ArkServiceLoader.setExtensionLoaderService(extensionLoaderService);
}
部署 Ark 插件
DeployPluginStage
这一步主要是部署 plugin。从 PluginManagerService 中获取到所有的 Ark 插件,并按照插件优先级顺序:
* ClassloaderService 准备插件 export 类的 map 映射
* PluginDeployService 启动插件的 com.alipay.sofa.ark.spi.service.PluginActivator。
// PluginDeployServiceImpl 类
public void deploy() throws ArkRuntimeException {
for (Plugin plugin : pluginManagerService.getPluginsInOrder()) {
try {
deployPlugin(plugin);
} catch (ArkRuntimeException e) {
LOGGER.error(String.format("Deploy plugin: %s meet error", plugin.getPluginName()),
e);
throw e;
}
}
}
// PluginModel 类
public void start() throws ArkRuntimeException {
if (activator == null || activator.isEmpty()) {
return;
}
EventAdminService eventAdminService = ArkServiceContainerHolder.getContainer().getService(
EventAdminService.class);
ClassLoader oldClassLoader = ClassLoaderUtils
.pushContextClassLoader(this.pluginClassLoader);
try {
eventAdminService.sendEvent(new BeforePluginStartupEvent(this));
pluginActivator = (PluginActivator) pluginClassLoader.loadClass(activator)
.newInstance();
pluginActivator.start(pluginContext);
} catch (Throwable ex) {
throw new ArkRuntimeException(ex.getMessage(), ex);
} finally {
eventAdminService.sendEvent(new AfterPluginStartupEvent(this));
ClassLoaderUtils.popContextClassLoader(oldClassLoader);
}
}
启动 Ark 业务
DeployBizStage
这一步主要是部署 biz。从 BizManagerService 中获取到所有的 Ark 业务,并执行业务配置在 MANIFEST.MF 属性 Main-Class 中提供的入口 main 函数
// BizDeployServiceImpl 类
public void deploy(String[] args) throws ArkRuntimeException {
ServiceReference<BizDeployer> serviceReference = registryService
.referenceService(BizDeployer.class);
bizDeployer = serviceReference.getService();
LOGGER.info(String.format("BizDeployer=\'%s\' is starting.", bizDeployer.getDesc()));
bizDeployer.init(args);
bizDeployer.deploy();
}
// DefaultBizDeployer 类
public void deploy() {
for (Biz biz : bizManagerService.getBizInOrder()) {
try {
LOGGER.info(String.format("Begin to start biz: %s", biz.getBizName()));
biz.start(arguments);
LOGGER.info(String.format("Finish to start biz: %s", biz.getBizName()));
} catch (Throwable e) {
LOGGER.error(String.format("Start biz: %s meet error", biz.getBizName()), e);
throw new ArkRuntimeException(e);
}
}
}
完成启动
FinishStartupStage
Ark 2.0 这一步什么事情都不会做,1.0 会发送一个 AfterFinishStartupEvent 事件。
@Singleton
public class FinishStartupStage implements PipelineStage {
@Inject
private EventAdminService eventAdminService;
@Override
public void process(PipelineContext pipelineContext) throws ArkRuntimeException {
if (ArkConfigs.isEmbedEnable()) {
// 2.0 直接返回
return;
}
eventAdminService.sendEvent(new AfterFinishStartupEvent());
}
}