В настоящее время я работаю над проектом, который включает запуск Spring Boot в плагине Minecraft Spigot/Paper.
Мой проект настроен для запуска пользовательской платформы, которую я создал при инициализации плагина:
// MyPlugin class
override fun onEnable() {
MyFramework.run(javaClass, name)
}
Моя структура отвечает за инициализацию приложения Spring, которое работает нормально...
Внедрение зависимостей и любая другая часть самого Spring работает без проблем, но меня смущает один момент.
Я не могу заставить файл application.properties
работать с Spring Boot.
Кажется, Spring просто игнорирует мой файл свойств и любой другой внешний файл конфигурации, если он объявлен в моем плагине Minecraft....
Я уже пробовал несколько вещей:
Пользовательский загрузчик ресурсов при создании приложения Spring с использованием SpringApplicationBuilder
Установка местоположения файла свойств с помощью spring.config.location
при создании приложения с помощью SpringApplicationBuilder
Добавление @PropertySources
в основной класс моего приложения Spring.
Добавление файла application.properties вручную в выходной JAR ROOT перед запуском.
Я убедился, что файл конфигурации правильно размещен в корневом каталоге моего плагина.
Файл также найден приложением, проверенным следующим тестом:
public static void checkPropertiesFile() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL resource = classLoader.getResource("application.properties");
if (resource != null) {
System.out.println("Found application.properties at " + resource.getPath());
} else {
System.out.println("application.properties not found in classpath.");
}
}
Это фрагмент кода, относящийся к запуску приложения Spring:
public static void run(Class<?> plugin, String pluginName) {
final ClassLoader pluginClassLoader = plugin.getClassLoader();
// needed or else spring startup fails
Thread.currentThread().setContextClassLoader(pluginClassLoader);
final ResourceLoader loader = new DefaultResourceLoader(pluginClassLoader);
final SpringApplicationBuilder builder = new SpringApplicationBuilder();
// auto generated "main spring class"
// needed since when using the actual plugin main class, spring tries to instantiate a new instance of our plugin class, which fails
final Class<?> pluginConfiguration = Class.forName(plugin.getPackageName() + ".PluginConfiguration");
final Class<?>[] sources = {pluginConfiguration, SpigotConfiguration.class, BungeecordConfiguration.class};
context = builder.sources(sources)
.initializers(applicationContext -> {
applicationContext.setClassLoader(pluginClassLoader);
})
.resourceLoader(loader)
.properties("plugin.name = " + pluginName)
.properties("plugin.main = " + plugin.getName())
.run();
}
Я действительно потерялся здесь, вы, ребята, моя последняя надежда, я медленно схожу с ума.
@mlecz Я реализовал ваше предложение и заметил что-то странное ... атрибуты пользовательских свойств, подобные тем, которые показаны в моем сообщении (plugin.name, plugin.main), подбираются весной, а другие - нет ??? Я протестировал его, удалив свои пользовательские свойства, что привело к сбою моего приложения при запуске (что и ожидалось, поскольку я регистрирую bean-компоненты, которые полагаются на эти значения конфигурации). Используя ConfigurableEnvironment#getSystemProperties()
, я могу видеть все свойства, установленные в моем файле конфигурации. Как Spring не использует «spring.profiles.active» для определения активных профилей при запуске?
кстати, проверьте эти 2 конфигурации: Spring.config.location Spring.config.name
И «spring.config.location», и «spring.config.name» имеют значение null при проверке свойств системы и свойств среды Spring.
погуглите эти конфигурации, возможно, вы захотите использовать их
да, даже если для обоих свойств установлены либо местоположения пути к классам, либо внешние, как определено в документах Spring, это не будет работать. Я могу только предположить, что Spring не нравится собственный загрузчик классов, который я ему предоставляю. Я упускаю какую-то важную зависимость или это, возможно, внутренняя ошибка Spring?
Изоляция загрузчика классов и методы загрузки ресурсов, которые не согласованы должным образом, часто являются причиной проблемы, когда Spring Boot не может загрузить файл application.properties в пользовательской среде загрузчика классов. Вы можете выявить и устранить проблему более успешно, если убедитесь, что используется правильный загрузчик классов, конкретно задаете расположение файла конфигурации и включаете ведение журнала отладки.
Это обновленный пример установки явного местоположения файла конфигурации для приложения Spring Boot:
public static void run(Class<?> plugin, String pluginName) {
final ClassLoader pluginClassLoader = plugin.getClassLoader();
// needed or else spring startup fails
Thread.currentThread().setContextClassLoader(pluginClassLoader);
final ResourceLoader loader = new DefaultResourceLoader(pluginClassLoader);
final SpringApplicationBuilder builder = new SpringApplicationBuilder();
final Class<?> pluginConfiguration = Class.forName(plugin.getPackageName() + ".PluginConfiguration");
final Class<?>[] sources = {pluginConfiguration, SpigotConfiguration.class, BungeecordConfiguration.class};
context = builder.sources(sources)
.initializers(applicationContext -> {
applicationContext.setClassLoader(pluginClassLoader);
})
.resourceLoader(loader)
.properties("spring.config.location=classpath:/application.properties")
.properties("plugin.name = " + pluginName)
.properties("plugin.main = " + plugin.getName())
.run();
}
Я нашел способ решить свою проблему.
Когда Spring сообщает Spring использовать «StandardEnvironment» во время сборки, Spring выбирает любой набор системных свойств перед запуском:
builder.initializers(applicationContext -> {
applicationContext.setEnvironment(new StandardEnvironment());
})
Теперь я могу использовать предложение @mlecz (загрузка application.properties с объектом Properties
и перебор каждой пары ключ-значение, а затем установка системного свойства для каждой пары).
Это обходной путь, а не та функциональность, на которую я надеялся, но она работает.
Вот отредактированный фрагмент кода для тех, у кого есть подобные проблемы с реализацией Spring в такой среде:
public static void run(Class<?> plugin, String pluginName) {
final ClassLoader pluginClassLoader = plugin.getClassLoader();
// needed or else spring startup fails
Thread.currentThread().setContextClassLoader(pluginClassLoader);
final ResourceLoader loader = new DefaultResourceLoader(pluginClassLoader);
final SpringApplicationBuilder builder = new SpringApplicationBuilder();
final Class<?> pluginConfiguration = Class.forName(plugin.getPackageName() + ".PluginConfiguration");
final Class<?>[] sources = {pluginConfiguration, SpigotConfiguration.class, BungeecordConfiguration.class};
System.setProperty("plugin.name", pluginName);
System.setProperty("plugin.main", plugin.getName());
try {
final Properties properties = new Properties();
properties.load(pluginClassLoader.getResourceAsStream("application.properties"));
properties.forEach((key, value) -> {
System.setProperty(key.toString(), value.toString());
});
} catch (Exception ignored) {}
context = builder.sources(sources)
.initializers(applicationContext -> {
applicationContext.setClassLoader(pluginClassLoader);
// this somehow enables spring to pickup the system properties
applicationContext.setEnvironment(new StandardEnvironment());
})
.resourceLoader(loader)
.run();
}
Благодаря этой реализации я смог установить свой активный профиль с помощью «application.properties», который находится в КОРНЕВОМ каталоге моего встроенного JAR.
это может быть бесполезно, поскольку это обходной путь, но вы можете прочитать этот файл перед запуском Spring, проанализировать его (вероятно, класс свойств сборки Java мог бы это сделать), а затем использовать System.setProperty("key",value). Если системное свойство установлено, то Spring будет использовать его.