Инструкции по использованию Sofa-ark и анализ исходного кода контейнера изоляции Java

Java

1. Как использовать и примеры

Введение. Когда вводится пакет зависимостей стороннего производителя или пакет зависимостей стороннего производителя, может возникнуть конфликт между внешним пакетом jar зависимостей и собственными потребностями проекта, или несколько сторонних и сторонних пакетов зависимостей конфликтуют друг с другом. разное. В настоящее время для их изоляции необходим изолирующий контейнер.Принцип зависимости заключается в том, что JVM считает, что классы, загруженные разными загрузчиками классов, различны, даже если имя пакета и имя класса совпадают. диван-арк упаковывает пакеты jar, которые необходимо изолировать, в плагины и использует независимый загрузчик классов для загрузки каждого плагина.

(Напоминание: если вы мало знаете о диван-ковчеге, вам лучше сначала пойти и посмотреть егоофициальная документация, Легко понять)

Основные шаги для использования:

  1. Добавьте плагин maven, предоставленный диваном-арком, в файл POM пакета jar, который будет конфликтовать, и отформатируйте его в пакет jar (плагин) в определенном формате.
  2. Пакет jar импортируется во внешний проект в соответствии с соглашением. Если внешний проект нужно упаковать в исполняемый файл jar (fat-jar), необходимо добавить специальный плагин maven.
  3. запустить напрямую.

Глоссарий:

  • Контейнер Ark: Контейнер Ark является ядром компонента SOFAArk.При запуске пакета Ark контейнер Ark запускается первым и отвечает за управление средой выполнения приложения.В основном это включает в себя создание таблицы отношений импорта и экспорта классов Ark Plugin и Ark Biz., запускать и инициализировать Ark Plugin и Ark Biz, управлять публикацией и ссылками на сервисы Ark Plugin и многое другое.
  • Biz: бизнес-проект, который ссылается на один или несколько внешних пакетов jar.
  • плагин: пакет fat-jar конфликтующего пакета jar внешней зависимости создается с помощью предоставленного плагина Maven. Во время выполнения он загружается независимым загрузчиком классов, поэтому пакеты Jar с требованиями к изоляции рекомендуется упаковывать как подключаемый модуль Ark для зависимостей приложений.

1.0 Принцип дивана-ковчега

В диване-арк контейнер-контейнер используется для запуска внешнего проекта (Biz) и конфликтующего пакета jar (плагина). может ссылаться только на классы, экспортируемые плагином, и этот класс сделан независимым отPluginClassLoaderзагружен, тем самым решив проблему конфликта пакетов jar.

image-20180724204016919

1.1 Пример конфликта

jar冲突

1.2 Устанавливаем мыльный ковчег

отофициальный сайт диван-ковчегаЗагрузите весь проект и выполните его по пути, где находится самый внешний файл pom.xml.mvn packageиmvn installУстановите пакет JAR зависимостей дивана-арка локально.

1.3 Создайте пакет Jar с базовой зависимостью (конфликтующий пакет)

Создайте проект myjar самостоятельно, упакуйте две версии в обычном режиме и установите их на локальном складе maven.

Например: версия v1

image-20180724185922039

версия v2

image-20180724190102751

1.4 Создать пакет услуг (плагин)

Создайте два проекта, как показано на рисунке:

существуетmyJarservice-v1иmyJarservice-v2Два базовых пакета зависимостей, написанные ранее, упоминаются в pom соответственно. затем вMyJarService1иMyJarService2См. методы в соответствующей версии пакета myjar соответственно.

Например, MyJarService1.java:

image-20180724190836319

MyJarService2.java

image-20180724191026890

Примечание. Две службы здесь относятся к разным версиям myjar.

Далее нужно запаковать два проекта.Чем отличается от обычной упаковки, так это плагином maven, который нужно добавить в диван-арк-плагин. Необходимо добавить pom.xml в оба проекта:

 <build>
        <plugins>
            <plugin>
                <groupId>com.alipay.sofa</groupId>
                <artifactId>sofa-ark-plugin-maven-plugin</artifactId>
                <version>0.4.0-SNAPSHOT</version>
                <executions>
                    <execution>
                        <id>default-cli</id>
                        <goals>
                            <goal>ark-plugin</goal>
                        </goals>

                        <configuration>
                            <!-- configure exported class -->
                            <exported>
                                <!-- configure class-level exported class -->
                                <classes>
                                 
           <class>com.netease.sofaservice.MyJar1Service</class>
                                </classes>
                            </exported>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

существуетexportedМетоды, которые должны быть предоставлены извне, написаны в метке, и все методы, на которые нужно ссылаться извне, должны быть записаны здесь, что может быть записано в классе (<classes>) для единиц и пакетов (packages) экспортируются в единицах.

Перейти к родительскому пути проектаmvn packageиmvn installВот и все.

1.5 Внешняя ссылка на проект (Biz)

Создайте новый проект и введите следующие зависимости в pom.xml:

<dependencies>
        <dependency>
            <groupId>com.alipay.sofa</groupId>
            <artifactId>sofa-ark-support-starter</artifactId>
            <version>0.4.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.netease</groupId>
            <artifactId>myjarservice-v1</artifactId>
            <classifier>ark-plugin</classifier>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>com.netease</groupId>
            <artifactId>myjarservice-v2</artifactId>
            <classifier>ark-plugin</classifier>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>com.netease</groupId>
            <artifactId>myjarservice-v1</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.netease</groupId>
            <artifactId>myjarservice-v2</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

Примечание для добавления<classifier>Этикетка, так как среда IDE не может распознать jar-пакет ark-plugin, ей необходимо ввести другую область видимости.providedбаночный пакет.

Затем pom.xml также добавляет плагин maven:

<build>
        <plugins>
            <plugin>
                <groupId>com.alipay.sofa</groupId>
                <artifactId>sofa-ark-maven-plugin</artifactId>
                <version>0.4.0-SNAPSHOT</version>
                <executions>
                    <execution>
                        <id>default-cli</id>

                        <!--goal executed to generate executable-ark-jar -->
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <!--specify destination where executable-ark-jar will be saved, default saved to ${project.build.directory}-->
                            <outputDirectory>./</outputDirectory>

                            <!--default none-->
                            <arkClassifier>executable-ark</arkClassifier>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

Затем просто напишите класс, чтобы представить классы двух версий пакета услуг для использования.Вам нужно добавить предложение при входе в основную функцию:

SofaArkBootstrap.launch(args);

image-20180724203423465

Вы можете увидеть результат печати:

image-20180724203546696

2. Принципиальный анализ плагина Sofa-ark-plugin-maven-plugin

2.1 Просмотр содержимого пакета jar плагина

использоватьsofa-ark-plugin-maven-pluginПодключаемый модуль Maven может упаковать пакет jar в пакет jar, который можно изолировать и загрузить в контейнер (например, myjarservice-v1-1.0-ark-plugin.jarr и myjarservice-v2-1.0-ark-plugin.jar). Введя расположение локального репозитория maven проекта myJarservice-v1, вы увидите, что у maven есть два пакета: один — это общий пакет, созданный подключаемым модулем, который поставляется с maven:myjarservice-v1-1.0.jar, другой — это пакет, созданный плагином maven, предоставленным диваном-арком.myjarservice-v1-1.0-ark-plugin.jar,Открытымmyjarservice-v1-1.0-ark-plugin.jarВы можете увидеть следующие каталоги:

Соответствующее описание каталога:

  • com/alipay/sofa/ark/plugin/mark: пометить файл, пометить пакет Jarsofa-ark-plugin-maven-pluginупакованный сгенерированныйArk Pluginдокумент.
  • META-INF/MANIFEST.MF: запись метаинформации плагина,который содержит классы для экспорта и импорта.
Manifest-Version: 1.0
groupId: com.netease
artifactId: myjarservice-v1
version: 1.0
priority: 100
pluginName: myjarservice-v1
activator: 
import-packages: 
import-classes: 
import-resources: 
export-packages: 
export-classes: com.netease.sofaservice.MyJar1Service
export-resources: 
  • conf/export.index: Плагин экспортирует файл индекса класса, чтобы избежать его вычисления во время выполнения.MANIFEST.MF серединаexport-packagesВ пакете создаются следующие специальные классы экспортаArk PluginПри , индексный файл всех экспортированных классов плагина будет сгенерирован, сокращаяArk ContainerВремя настройки разбора.
  • lib/: В каталоге lib хранятся общие пакеты Jar, от которых зависят проекты подключаемых модулей, обычно включая пакеты Jar, которые необходимо изолировать подключаемым модулям от других подключаемых модулей или предприятий; экспортированные классы, настроенные подключаемыми модулями, включаются в эти пакеты Jar.

2.2 Анализ исходного кода диван-арк-плагин-мавен-плагин

Введите загруженный исходный код дивана-аркаark-plugin-maven-pluginProject, вы можете видеть, что ArkPluginMojo унаследовал

@Mojo(name = "ark-plugin", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.RUNTIME)
public class ArkPluginMojo extends AbstractMojo {
@Parameter(defaultValue = "${project.artifactId}")
    public String                   pluginName;

    @Parameter(defaultValue = "100", property = "sofa.ark.plugin.priority")
    protected Integer               priority;

    @Parameter
    protected String                activator;

    @Parameter
    protected ExportConfig          exported;

    @Parameter
    protected ImportConfig          imported;
...

@Mojoцель, которая может быть привязана кphase(Вот пакет) выполнение, @Parameter — это параметр, переданный извне, вы можете напрямую получить параметры, настроенные в xml. Стандартные требования к плагину Maven должны быть переписаныexecute()метод, когда подключаемый модуль выполняется, он в основном выполняетсяexecute().

    @Override
    public void execute() throws MojoExecutionException 
    {
        Archiver archiver;//zip归档
        archiver = getArchiver();
        outputDirectory.mkdirs();
        String fileName = getFileName();
        File destination = new File(outputDirectory, fileName);
        archiver.setDestFile(destination);
        Set<Artifact> artifacts = project.getArtifacts();
        artifacts = filterExcludeArtifacts(artifacts);
        Set<Artifact> conflictArtifacts = filterConflictArtifacts(artifacts);
        addArkPluginArtifact(archiver, artifacts, conflictArtifacts);
        addArkPluginConfig(archiver);
      	archiver.createArchive();
        projectHelper.attachArtifact(project, destination, getClassifier());
    }

здесь будетexecute()Этот метод упрощен, он в основном делает следующее:

  1. Создайте архив в формате zip, чтобы сохранить импортированный пакет jar и другие файлы, и укажите выходной путь.
  2. Получите все введенные зависимости (артефакты) и исключите пакеты, которые необходимо исключить.
  3. Запишите все зависимости в каталог lib в zip-архиве.

image-20180725153520102

  1. Запишите информацию о конфигурации в zip-архив, включая ранее упомянутыеexport.index,MANIFEST.MF,mark
    image-20180725153659204

После вышеуказанных шагов зависимые зависимости и файлы конфигурации записываются в zip, а затем преобразуются в суффикс jar.

3. Анализ принципа дивана-ковчега

3.1 Инициализировать ArkContainer

В предыдущем разделе объяснялось, как работает подключаемый модуль, а в этом разделе описывается, как внешний проект обращается к пакету jar подключаемого модуля, упакованному с подключаемым модулем, для разрешения конфликта изоляции. можно добавить из основного методаSofaArkBootstrap.launch(args)Для пошагового отслеживания этот код в основномЗапустите контейнер, а затем дайте контейнеру загрузить Plugin и Biz. существуетlaunchМетод вызывается отражениемSofaArkBootstrapизremainметод, вremainМетод в основном делает две вещи:

 private static void remain(String[] args) throws Exception {// NOPMD
        URL[] urls = getURLClassPath();
        new ClasspathLauncher(new ClassPathArchive(urls)).launch(args, getClasspath(urls),
            entryMethod.getMethod());
    }
  1. Получите все пакеты jar в пути к классам, включая собственные пакеты jar JDK и пакеты jar, представленные maven.
  2. положить всеЗависит от пакета jar и класса запуска, а его основная функция написана сама по себеПередать как URLClasspathLauncher,ClasspathLauncherвызов отраженияArkContainerизmainметод и использованиеContainerClassLoaderнагрузкаArkContainer. В этот момент запустите ArkContainer.

3.2 Запустить АркКонтейнер

Затем он работаетArkContainerВ основном методе входящий параметр args является предыдущимClasspathLauncherвходящий URL

public static Object main(String[] args) throws ArkException
    {
            //使用LaunchCommand将传入的参数按类型分类
            LaunchCommand launchCommand = LaunchCommand.parse(args[ARK_COMMAND_ARG_INDEX], Arrays.copyOfRange(args, MINIMUM_ARGS_SIZE, args.length));
            //ClassPathArchive将传入依赖的Jar包分类,并提供获得plugin和biz的filter方法
            ClassPathArchive classPathArchive = new ClassPathArchive(launchCommand.getEntryClassName(), launchCommand.getEntryMethodName(), launchCommand.getEntryMethodDescriptor(), launchCommand.getClasspath());
            return new ArkContainer(classPathArchive, launchCommand).start();
            }
    }

Этот метод в основном выполняет следующие действия:

  1. использоватьLaunchCommandКлассифицируйте входящие параметры, извлеките URL пути к классам и основной метод класса запуска, написанный вами
    image-20180726151249913
  2. будетLaunchCommandвходящийArkContainerи начните:

существуетArkContainer.start()середина:

public Object start() throws ArkException
    {
        if (started.compareAndSet(false, true))
        {
            arkServiceContainer.start();
            Pipeline pipeline = arkServiceContainer.getService(Pipeline.class);
            pipeline.process(pipelineContext);
        }
        return this;
    }

arkServiceContainerОн содержит некоторые сервисы, которые необходимо запустить до запуска Контейнера, и эти сервисы инкапсулированы в один за другим.PipelineStageв этихPipelineStageОн снова инкапсулируется в список вpipelineсередина. В основном включают в себя этиPipelineStage, выполнить последовательно:

  1. HandleArchiveStageОтфильтруйте все сторонние пакеты jar, которые содержат отмеченные меткой jar-файлы плагинов, указав, что эти jar-файлы упакованы плагином дивана ark maven и должны быть изолированы. Извлеките классы, которые необходимо изолировать, из файла export.index в банке и добавьте их вPluginList, а каждому плагину назначить отдельныйPluginClassLoader. В то же время назначьте Biz с той же операцией.BizClassLoader
  2. DeployPluginStageСоздайте карту, ключ — это класс, который необходимо изолировать, а значение — это экземпляр PluginClassLoader, используемый для загрузки этого класса.
  3. DeployBizStageВызовите основной метод Biz, используя отражение BizClassLoader.

В этот момент Контейнер запускается. При вызове класса, который необходимо изолировать позже, поскольку поток, запустивший Biz, был заменен BizClassLoader, BizClassLoader сначала просматриваетDeployPluginStageЕсть ли в созданной карте PluginClassLoader, который может загрузить этот класс, и если да, делегируйте PluginClassLoader для загрузки. Достигается, что разные классы загружаются с помощью разных загрузчиков классов.