Spring Boot не выбирает application.properties в среде пользовательского загрузчика классов

В настоящее время я работаю над проектом, который включает запуск 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();
}

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

это может быть бесполезно, поскольку это обходной путь, но вы можете прочитать этот файл перед запуском Spring, проанализировать его (вероятно, класс свойств сборки Java мог бы это сделать), а затем использовать System.setProperty("key",value). Если системное свойство установлено, то Spring будет использовать его.

mlecz 14.07.2024 09:55

@mlecz Я реализовал ваше предложение и заметил что-то странное ... атрибуты пользовательских свойств, подобные тем, которые показаны в моем сообщении (plugin.name, plugin.main), подбираются весной, а другие - нет ??? Я протестировал его, удалив свои пользовательские свойства, что привело к сбою моего приложения при запуске (что и ожидалось, поскольку я регистрирую bean-компоненты, которые полагаются на эти значения конфигурации). Используя ConfigurableEnvironment#getSystemProperties(), я могу видеть все свойства, установленные в моем файле конфигурации. Как Spring не использует «spring.profiles.active» для определения активных профилей при запуске?

xRa1ny 14.07.2024 22:40
stackoverflow.com/questions/45822326/… может быть, вы не устанавливаете свои окружения до начала весны?
mlecz 14.07.2024 22:46

кстати, проверьте эти 2 конфигурации: Spring.config.location Spring.config.name

mlecz 14.07.2024 22:46

И «spring.config.location», и «spring.config.name» имеют значение null при проверке свойств системы и свойств среды Spring.

xRa1ny 14.07.2024 22:57

погуглите эти конфигурации, возможно, вы захотите использовать их

mlecz 14.07.2024 23:04

да, даже если для обоих свойств установлены либо местоположения пути к классам, либо внешние, как определено в документах Spring, это не будет работать. Я могу только предположить, что Spring не нравится собственный загрузчик классов, который я ему предоставляю. Я упускаю какую-то важную зависимость или это, возможно, внутренняя ошибка Spring?

xRa1ny 14.07.2024 23:41
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Изоляция загрузчика классов и методы загрузки ресурсов, которые не согласованы должным образом, часто являются причиной проблемы, когда 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.

Другие вопросы по теме