Упаковка Springboot 2.0 и пользовательский файл launch.script

Spring Boot Java

Оригинал: Miss Sister Taste (идентификатор публичной учетной записи WeChat: xjjdog), добро пожаловать, пожалуйста, сохраните источник для перепечатки.

Сегодня я разговаривал с первым о параметрах конфигурации springboot. Он сказал, что эти параметры конфигурации копируются и копируются разработчиками, а ошибиться легко, поэтому давайте их заблокируем.

Действительно, инженерctrl+cа такжеctrl+v, большинство важных параметров изменились до неузнаваемости и совсем не те, что были. Я видел слишком много подобных случаев, так что я согласен.

Почему у копипаста тоже проблемы? Есть две причины: потому что провайдер непостоянен, потому что пользователь горд.

Я коснулся руки первого кадра и сказал:готов к работе.

потребности и мышление

С нашимspringboot 2.0Разбираясь шаг за шагом, а также развертывая среду для упаковки, мы постепенно надеемсяspringbootПриложение упаковано висполняемый jarДа и системные параметры удобнее указывать при запуске.

Например, в среде Linux или в контейнере.

Возможный способ — упаковать springboot в исполняемый jar-файл, а затем запустить или закрыть программу аналогичным образом следующим образом:

$> ./application.jar start  
$> ./application.jar stop  
  
$> JAVA_OPTS=-Xmx2g ./application.jar start  

Вы можете видеть, что этот метод очень лаконичен, но SpringBoot не поддерживает его по умолчанию.

Кроме того, мы можем захотеть единообразно управлять методом упаковки springboot, например, ограничить каталог журнала, единообразно указать параметры JVM или дополнительно извлечь некоторые статические файлы из центра конфигурации при запуске.

Эти особые требования, родной launch.script не может быть выполнен, нам нужно расширить launch.scipt или настроить его.

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

проблема, с которой мы сталкиваемся:

  1. Даже если мы переделаем launch.script, с помощью<embeddedLaunchScript>, но этот скрипт можно разместить только в папке проекта本地目录. Если мы встроим этот скрипт во внешний jar (главным образом потому, что мы не хотим, чтобы все проекты повторяли этот скрипт), он может не загрузиться.
  2. даже если мы используем<inlinedConfScript>, но это内联脚本Не может поддерживать сложную логику сценария.

Способ решения проблемы:

  1. Чтобы сохранить большинство функций собственного сценария запуска Springboot, скопируйте копию из исходного кода Springboot.
  2. Разрабатываем maven-плагин, ставим наш кастомныйlaunch.scriptи обычайinlined-conf.scriptФайлы размещаются в этом модуле подключаемого модуля. Мы надеемся, что это начало сердца может быть универсальным видом многих проектов, скрипт унифицированного управления (модифицировать, обновление), только бизнес-проекты должны ссылаться на.
  3. Этот maven-плагин имеет очень простую функцию, то есть на этапе пакета скопируйте два скрипта в целевой каталог проекта.
  4. spring-boot-maven-pluginПосле небольшой настройки конфигурации вы можете обратиться к этим двум сценариям, потому что эти два сценария были скопированы в целевой каталог проекта с помощью нашего самостоятельно разработанного плагина.

1. разработка maven-плагина

Как видно из вышеизложенного, наша цель очень проста: сослаться на веб-проект этого плагина.При упаковке скопируйте два скрипта в целевой каталог веб-проекта для использования spring-boot-maven- плагин.

Этот плагин находится вpackageэтапы, в основном в том числе:

  1. LauncherWriterMojo: во время упаковки используется для копирования файлов скриптов в целевой каталог веб-проекта, в котором используется подключаемый модуль.
  2. inlined-conf.script: поддерживается плагином spring-boot-maven<inlinedConfScript>Конфигурация в основном указывает некоторые системные параметры, поддерживаемые некоторыми исполняемыми файлами jar Springboot.
  3. launch.script: Сценарий запуска, базовая плата исходит из исходного кода, поставляемого с springboot, мы добавили некоторые внутренние функции, такие как сборка параметров JVM, настройка системных параметров и т. д.

LauncherWriterMojo.java

 import org.apache.maven.plugin.AbstractMojo;  
import org.apache.maven.plugin.MojoExecutionException;  
import org.apache.maven.plugin.MojoFailureException;  
import org.apache.maven.plugins.annotations.LifecyclePhase;  
import org.apache.maven.plugins.annotations.Mojo;  
import org.apache.maven.plugins.annotations.Parameter;  
import org.apache.maven.plugins.annotations.ResolutionScope;  
  
import java.io.*;  
 
@Mojo(name = "package", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)  
public class LauncherWriterMojo extends AbstractMojo {  
  
    @Parameter(defaultValue = "${basedir}/target", required = true)  
    private File outputDirectory;  
  
    public void setOutputDirectory(File outputDirectory) {  
        this.outputDirectory = outputDirectory;  
    }  
  
    @Override  
    public void execute() throws MojoExecutionException, MojoFailureException {  
        try {  
            copy("launch.script");  
            getLog().info("launch.script has been created.");  
            copy("inlined-conf.script");  
            getLog().info("inlined-conf.script has been created.");  
        } catch (IOException ie) {  
            throw new MojoExecutionException("launch.script written error!",ie);  
        }  
    }  
  
    private void copy(String filename) throws IOException{  
        InputStream inputStream = getClass().getResourceAsStream("/" + filename);  
        BufferedWriter writer = null;  
        try {  
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));  
            File target = new File(outputDirectory + "/" + filename);  
            target.setExecutable(true,false);  
            target.setWritable(true,false);  
            target.setReadable(true,false);  
            writer = new BufferedWriter(new FileWriter(target));  
            while (true) {  
                String line = reader.readLine();  
                if (line == null) {  
                    break;  
                }  
                writer.write(line);  
                writer.newLine();  
            }  
            writer.flush();  
        }  finally {  
            if (inputStream != null) {  
                inputStream.close();  
            }  
            if (writer != null) {  
                writer.close();  
            }  
        }  
    }  
}  

inlined-conf.script

 MODE=service; identity=run; PID_FOLDER=./var; LOG_FOLDER=./; LOG_FILENAME=std.out; pidFilename=pid; JAVA_OPTS="$JAVA_OPTS -XX:NewRatio=2 -XX:G1HeapRegionSize=8m -XX:MaxMetaspaceSize=256m -XX:MaxTenuringThreshold=10 -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=45 -XX:MaxGCPauseMillis=200 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintReferenceGC -XX:+PrintAdaptiveSizePolicy -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=6 -XX:GCLogFileSize=32m -Xloggc:./var/run/gc.log.$(date +%Y%m%d%H%M) -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./var/run/java_pid<pid>.hprof -Dfile.encoding=UTF-8 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=${JMX_PORT:-0} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"; mkdir -p var/run  

Кратко опишите: этот встроенный скрипт в основном предназначен для уменьшения сложности пользовательской конфигурации плагина spring-boot-maven и для указания каталога журнала, файла PID, других общих параметров JVM, кроме размера кучи и т. д., чтобы этот плагин- в используется Пакетные проекты могут быть более стандартизированы.

launch.script: Код скопирован из spring-boot Можно подумать, что в этой статье разницы нет.

2. Как использовать

pom.xml вашего веб-проекта или модуля

 <plugin>  
    <groupId>com.??.commons</groupId>  
    <artifactId>meteor-spring-boot-maven-plugin</artifactId>  
    <version>${meteor-project.version}</version>  
    <executions>  
        <execution>  
            <goals>  
                <goal>package</goal>  
            </goals>  
        </execution>  
    </executions>  
</plugin>  
<plugin>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-maven-plugin</artifactId>  
    <version>${spring-boot.version}</version>  
    <configuration>  
        <executable>true</executable>  
        <embeddedLaunchScriptProperties>  
            <inlinedConfScript>${basedir}/target/inlined-conf.script</inlinedConfScript>  
        </embeddedLaunchScriptProperties>  
        <embeddedLaunchScript>${basedir}/target/launch.script</embeddedLaunchScript>  
    </configuration>  
    <executions>  
        <execution>  
            <goals>  
                <goal>repackage</goal>  
            </goals>  
        </execution>  
    </executions>  
</plugin>  

Конечно, чтобы унифицировать использование подключаемых модулей, вы можете поместить указанную выше конфигурацию в файл parent-pom.xml или родительский проект, а другие проекты, использующие эту структуру, напрямую ссылаются на указанные выше подключаемые модули, не указывая конфигурацию в подключаемый модуль. Например:

<build>  
   <finalName>application</finalName>  
   <plugins>  
       <plugin>  
           <groupId>com.??.commons</groupId>  
           <artifactId>meteor-spring-boot-maven-plugin</artifactId>  
       </plugin>  
       <plugin>  
           <groupId>org.springframework.boot</groupId>  
           <artifactId>spring-boot-maven-plugin</artifactId>  
       </plugin>  
   </plugins>  
</build>  

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

END

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

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

Об авторе:Мисс сестра вкус(xjjdog), публичная учетная запись, которая не позволяет программистам идти в обход. Сосредоточьтесь на инфраструктуре и Linux. Десять лет архитектуры, десятки миллиардов ежедневного трафика, обсуждение с вами мира высокой параллелизма, дающие вам другой вкус. Мой личный WeChat xjjdog0, добро пожаловать в друзья для дальнейшего общения.​