Spring Boot: возможно ли использовать внешние файлы application.properties в произвольных каталогах с толстой флягой?
Можно ли иметь несколько файлов application.properties? (РЕДАКТИРОВАТЬ: обратите внимание, что этот вопрос превратился в вопрос в названии.)
Я пытался иметь 2 файла.
- Первый находится в корневой папке приложения Jar.
- Второй находится в каталоге, который указан в classpath.
2 файла называются application.properties.
Возможно ли объединить содержимое обоих файлов? (и значения свойств второго переопределяют свойства первого) Или, если у меня есть один файл, тогда другой файл игнорируется?
ОБНОВЛЕНИЕ 1: возможно "объединить" содержимое. Вчера казалось, что первый был проигнорирован, но кажется, что это что-то сломалось. Теперь это работает хорошо.
ОБНОВЛЕНИЕ 2: он вернулся снова! Опять же, только один из двух файлов применяется. Странно... Это началось после того, как я собрал файл jar приложения с помощью Spring Tool Suite. И кажется, что версия Jar всегда игнорирует вторую (в classpath), в то время как поведение расширенной версии, работающей на STS, варьируется. Откуда я могу начать расследование?
ОБНОВЛЕНИЕ 3:
Поведение версии Jar было на самом деле правильным. Это спецификация java.exe. Если указан параметр -jar, java.exe игнорирует параметр -classpath и переменную среды CLASSPATH, а путь к классам будет содержать только файл jar. Итак, второй файл application.properties на пути к классам игнорируется.
Теперь, как я могу позволить загружать второй application.properties в classpath?
ОБНОВЛЕНИЕ 4:
Мне удалось загрузить файл application.properties по внешнему пути, используя опцию -jar.
Ключ был PropertiesLauncher.
Чтобы использовать PropertiesLauncher, файл pom.xml должен быть изменен следующим образом:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <!-- added -->
<layout>ZIP</layout> <!-- to use PropertiesLaunchar -->
</configuration>
</plugin>
</plugins>
</build>
Для этого я сослался на следующий вопрос Stackru: средство запуска весенней загрузки не может быть использовано. Кстати, в документе Spring Boot Maven Plugin ( http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html) нет упоминания об указании триггеров ZIP что PropertiesLauncher используется. (Возможно в другом документе?)
После того, как файл jar был собран, я увидел, что PropertiesLauncher используется, проверив свойство Main-Class в META-INF/MENIFEST.MF в jar.
Теперь я могу запустить jar следующим образом (в Windows):
java -Dloader.path=file:///C:/My/External/Dir,MyApp-0.0.1-SNAPSHOT.jar -jar MyApp-0.0.1-SNAPSHOT.jar
Обратите внимание, что файл jar приложения включен в файл loader.path.
Теперь файл application.properties загружен в C:\My\External\Dir\config.
В качестве бонуса, любой файл (например, статический html-файл) в этом каталоге также может быть доступен для jar, поскольку он находится в пути к загрузчику.
Что касается не-jar (расширенной) версии, упомянутой в UPDATE 2, возможно, возникла проблема с порядком пути к классам.
(Кстати, я изменил название вопроса, чтобы быть более конкретным для этой проблемы.)
12 ответов
Мне удалось загрузить файл application.properties по внешнему пути, используя опцию -jar.
Ключ был PropertiesLauncher.
Чтобы использовать PropertiesLauncher, файл pom.xml должен быть изменен следующим образом:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <!-- added -->
<layout>ZIP</layout> <!-- to use PropertiesLaunchar -->
</configuration>
</plugin>
</plugins>
</build>
Для этого я сослался на следующий вопрос Stackru: средство запуска весенней загрузки не может быть использовано. Кстати, в документе Spring Boot Maven Plugin ( http://docs.spring.io/spring-boot/docs/1.1.7.RELEASE/maven-plugin/repackage-mojo.html) нет упоминания об указании триггеров ZIP что PropertiesLauncher используется. (Возможно в другом документе?)
После того, как файл jar был собран, я увидел, что PropertiesLauncher используется, проверив свойство Main-Class в META-INF/MENIFEST.MF в jar.
Теперь я могу запустить jar следующим образом (в Windows):
java -Dloader.path=file:///C:/My/External/Dir,MyApp-0.0.1-SNAPSHOT.jar -jar MyApp-0.0.1-SNAPSHOT.jar
Обратите внимание, что файл jar приложения включен в файл loader.path.
Теперь файл application.properties загружен в C:\My\External\Dir\config.
В качестве бонуса, любой файл (например, статический html-файл) в этом каталоге также может быть доступен для jar, поскольку он находится в пути к загрузчику.
Что касается не-jar (расширенной) версии, упомянутой в UPDATE 2, возможно, возникла проблема с порядком пути к классам.
Если вы не изменили настройки Spring Boot по умолчанию (это означает, что вы используете @EnableAutoConfiguration
или же @SpringBootApplication
и не изменили никакой обработки источника свойств), тогда он будет искать свойства в следующем порядке (наивысший переопределяет наименьший):
/config
Подкаталог текущего каталога- Текущий каталог
- Классный путь
/config
пакет - Корень пути к классам
Список выше упоминается в этой части документации
Это означает, что если свойство найдено, например, application.properties
под src/resources
будет переопределено свойством с тем же именем, найденным в application.properties
в /config
каталог, следующий за упакованным флягой.
Этот порядок по умолчанию, используемый Spring Boot, обеспечивает очень простую экстернализацию конфигурации, что, в свою очередь, упрощает настройку приложений в нескольких средах (dev, staging, production, cloud и т. Д.)
Чтобы увидеть весь набор функций, предоставляемых Spring Boot для чтения свойств (подсказка: доступно намного больше, чем чтение из application.properties
) проверить эту часть документации.
Как видно из моего короткого описания выше или из полной документации, приложения Spring Boot очень удобны для DevOps!
Это все объясняется здесь, в документации:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Что объясняет, что это порядок приоритета:
- Подкаталог A / config текущего каталога.
- Текущий каталог
- Пакет classpath / config
- Корень пути к классам
Это также указывает на то, что вы можете определить дополнительные файлы свойств для переопределений, например, так:
java -jar myproject.jar
--spring.config.location=classpath:/overrides.properties
Если вы используете spring.config.location
, то все местоположения по умолчанию для application.properties
также включены. Это означает, что вы можете установить значения по умолчанию в application.properties
и переопределить, как требуется для конкретной среды.
Вы сможете запустить приложение весенней загрузки с путем к файлу внешних свойств следующим образом:
java -jar {jar-file-name}.jar
--spring.config.location=file:///C:/{file-path}/{file-name}.properties
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
</plugin>
</plugins>
</build>
java -Dloader.path=file:///absolute_path/external.jar -jar example.jar
java -jar server-0.0.1-SNAPSHOT.jar --spring.config.location=application-prod.properties
Я знаю, что это заостренный вопрос, и ОП хотел загрузить другой файл свойств.
Мой ответ таков: делать пользовательские хаки, как это, ужасная идея.
Если вы используете весеннюю загрузку с облачным провайдером, таким как облачный литейный завод, сделайте себе одолжение и воспользуйтесь услугами облачной конфигурации.
https://spring.io/projects/spring-cloud-config
Он загружает и объединяет определенные свойства по умолчанию / dev / project-default / project-dev, такие как magic
Опять же, загрузка Spring уже дает вам достаточно способов сделать это правильно https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Пожалуйста, не изобретайте велосипед заново.
Это может произойти в конце, но я думаю, что я нашел лучший способ загрузить внешние конфигурации, особенно когда вы запускаете приложение весенней загрузки, используя java jar myapp.war
вместо @PropertySource("classpath:some.properties")
Конфигурация будет загружена из корня проекта или из места, из которого запускается файл war/jar
public class Application implements EnvironmentAware {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Override
public void setEnvironment(Environment environment) {
//Set up Relative path of Configuration directory/folder, should be at the root of the project or the same folder where the jar/war is placed or being run from
String configFolder = "config";
//All static property file names here
List<String> propertyFiles = Arrays.asList("application.properties","server.properties");
//This is also useful for appending the profile names
Arrays.asList(environment.getActiveProfiles()).stream().forEach(environmentName -> propertyFiles.add(String.format("application-%s.properties", environmentName)));
for (String configFileName : propertyFiles) {
File configFile = new File(configFolder, configFileName);
LOGGER.info("\n\n\n\n");
LOGGER.info(String.format("looking for configuration %s from %s", configFileName, configFolder));
FileSystemResource springResource = new FileSystemResource(configFile);
LOGGER.log(Level.INFO, "Config file : {0}", (configFile.exists() ? "FOund" : "Not Found"));
if (configFile.exists()) {
try {
LOGGER.info(String.format("Loading configuration file %s", configFileName));
PropertiesFactoryBean pfb = new PropertiesFactoryBean();
pfb.setFileEncoding("UTF-8");
pfb.setLocation(springResource);
pfb.afterPropertiesSet();
Properties properties = pfb.getObject();
PropertiesPropertySource externalConfig = new PropertiesPropertySource("externalConfig", properties);
((ConfigurableEnvironment) environment).getPropertySources().addFirst(externalConfig);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
} else {
LOGGER.info(String.format("Cannot find Configuration file %s... \n\n\n\n", configFileName));
}
}
}
}
Надеюсь, поможет.
Решение для файла yml:
1. Скопируйте yml в тот же каталог, в котором находится jar-приложение.
2. Запустите команду, пример для xxx.yml
:
java -jar app.jar --spring.config.location=xxx.yml
Работает нормально, но при запуске логгера есть INFO:
No active profile set .........
Другой гибкий способ - использование classpath, содержащего толстый jar (-cp fat.jar) или всех jar (-cp "$JARS_DIR/*"), и другой настраиваемый путь к classpath или папку, содержащую файлы конфигурации, обычно в других местах и за пределами jar. Поэтому вместо ограниченного java -jar используйте более гибкий путь к классам следующим образом:
java \
-cp fat_app.jar \
-Dloader.path=<path_to_your_additional_jars or config folder> \
org.springframework.boot.loader.PropertiesLauncher
Смотрите Spring-boot исполняемый файл jar doc и эту ссылку
Если у вас есть несколько распространенных MainApps, вы можете использовать Как мне сказать Spring Boot, какой основной класс использовать для исполняемого файла jar?
Вы можете добавить дополнительные местоположения, установив переменную среды LOADER_PATH или loader.path в loader.properties (разделенный запятыми список каталогов, архивов или каталогов внутри архивов). В основном loader.path работает как для java -jar, так и для java -cp.
И, как всегда, вы можете переопределить и точно указать application.yml, который он должен использовать для отладки.
--spring.config.location=/some-location/application.yml --debug
Когда вы создаете весенний загрузочный jar с помощью maven install и хотите, чтобы все ресурсы, такие как файл свойств и папка lib, создавались вне jar ..., добавьте следующий код в pom.xml, где я определяю выходную папку, где я хочу извлечь и сохранить нужные ресурсы банку.
<build>
<finalName>project_name_Build/project_name</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/project_name_Build/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>write here the qualified or complete path of main class of application</mainClass>
</manifest>
<manifestEntries>
<Class-Path>. resources/</Class-Path>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>application.properties</include>
<include>log4j.properties</include>
</includes>
<targetPath>${project.build.directory}/ConsentGatewayOfflineBuild/resources</targetPath>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>application.properties</include>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
<pluginManagement>
<plugins>
<!-- Ignore/Execute plugin execution -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<!-- copy-dependency plugin -->
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<versionRange>[1.0.0,)</versionRange>
<goals>
<goal>copy-dependencies</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Поместите свойства, которые вы хотите внедрить, в файл .properties или yml вне вашей банки.