Как Spring вызывает методы @Bean, если класс @Configuration содержит неразрешимые ссылки на классы

Spring может анализировать классы @Configuration, используя ClassReader.

Предположим, что у нас есть следующий сценарий

У нас есть класс автоконфигурации с несколькими определениями @Bean.

У одного из @Bean все условия выполнены, а у второго @Bean есть @ConditionalOnClass, и класс отсутствует в пути к классу.

@Configuration
class CustomConfiguration {
  @Bean
  @ConditionalOnClass(String.class)
  String knownClass() {
    return "Hello";
  }

  @Bean
  @ConditionalOnClass(MissingClass.class)
  MissingClass secondBean() {
    return new MissingClass();
  }
}

В этом сценарии у меня есть пара вопросов

  1. Регистрирует ли Spring Boot AutoConfiguration первый компонент в ApplicationContext?
  2. Если (1) верно, будет ли моя точка останова внутри первого метода @Bean срабатывать во время отладки?
  3. Если (2) верно, как класс *AutoConfiguration загружается в JVM, поскольку этот класс будет ссылаться на другие классы (из второго @Bean), которые не могут быть разрешены во время загрузки класса.
  4. Если (2) ложно, генерирует ли Spring класс во время выполнения только с первым методом @Bean и вызывает ли этот метод?

Спасибо

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

Ответы 2

Ответ принят как подходящий

Вообще говоря, вам следует избегать использования @ConditionalOnClass в методе @Bean именно по этой причине. Эта ситуация описана в справочная документация, где рекомендуется использовать отдельный класс @Configuration для изоляции состояния @ConditionalOnClass.

Чтобы ответить на ваши конкретные вопросы:

  1. Да, первый bean-компонент будет зарегистрирован до тех пор, пока может быть загружен класс конфигурации
  2. Да, во время отладки должна быть достигнута точка останова в первом методе @Bean.
  3. Это зависит от того, как ссылаются на неразрешимый класс. Если он используется только в теле метода @Bean, класс должен успешно загрузиться. Если неразрешимый класс используется в сигнатуре метода @Bean (обычно тип возвращаемого значения), класс не загрузится.
  4. Н/Д

Как отмечено в документации, указанной выше, вместо того, чтобы беспокоиться о сценариях, описанных в 3, и о том, что будет работать, а что нет, рекомендуется использовать отдельный, возможно, вложенный класс @Configuration с условием на уровне класса. Для вашего конкретного примера это будет выглядеть так:

@Configuration
class CustomConfiguration {

  @Bean
  @ConditionalOnClass(String.class)
  String knownClass() {
    return "Hello";
  }

  @Configuration
  @ConditionalOnClass(MissingClass.class)
  static class DoubtfulBeanConfiguration {

    @Bean
    MissingClass missingClass() {
      return new MissingClass();
    }

  }

}

Обновил вопрос с примером

Ashok Koyi 05.02.2019 15:45

Я считаю, что образец в моем примере выдаст ошибку NoClassDefFound.

Ashok Koyi 05.02.2019 15:46

Да, это будет. Отсюда рекомендация не делать то, что делает ваш пример.

Andy Wilkinson 05.02.2019 15:47

Я добавил пример с предложенным вами решением самого вопроса. Если это правильно, можете ли вы добавить это к своему ответу, чтобы я мог удалить его из вопроса. Спасибо за вашу помощь!!

Ashok Koyi 05.02.2019 15:48

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

Andy Wilkinson 05.02.2019 15:52

Энди выше ответил на вопрос "как", т.е. как пользоваться библиотекой. Но в этом ответе я попытался ответить на вопрос, почему

вот мое понимание

  1. Spring читает метаданные файла автоконфигурации из /META-INF/spring-autoconfigure-metadata.properties из пути к классам (один такой файл присутствует в spring-boot-autoconfigure).

    • Этот файл генерируется плагином на основе @Configuration. классы, перечисленные в ключ org.springframework.boot.autoconfigure.EnableAutoConfiguration в файле /META-INF/spring.factories плагином spring-boot-autoconfigure-processor
    • Сгенерированный файл содержит аннотации уровня класса @Configuration, такие как @ConditionalOnClass, @AutoConfigureBefore, и т.д]
  2. Spring создает метаданные о каждом из классов @Configuration, полученных из указанного выше файла свойств.
  3. Затем Spring оценивает все условия уровня класса @Configuration, включая @ConditionalOnClass, в сравнении с текущим путем к классам и фабрикой компонентов. Если условия выполняются, он загружает класс @Configuration, используя стандартную загрузку классов Java.
  4. Если мы сохраним @ConditionalOnClass(MissingClass.class) на уровне @Configuration, spring просто не загрузит класс, загрузит класс конфигурации, если условия уровня класса не оцениваются как истинные, скажем, если класс отсутствует в пути к классам
  5. Но если мы сохраним @ConditionalOnClass(MissingClass.class) на уровне @Bean, spring попытается загрузить наш класс @Configuration (при условии, что все условия на уровне класса @Configuration выполнены), и мы получим NoClassDefFoundError во время загрузки класса.

В целом, по этой причине нам нужно следовать решению @Andy.

@Энди

Спасибо, если вы можете высказать свое мнение о том, как Spring реализовал внутри себя функцию @ConditionalOnClass.

Спасибо

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