Как Spring вызывает методы @Bean, если класс @Configuration содержит неразрешимые ссылки на классы - PullRequest
0 голосов
/ 05 февраля 2019

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

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

У нас есть класс автоконфигурации с несколькими @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) имеет значение true, будет ли моя точка останова внутри первого @Bean метода получена во время отладки
  3. Если (2) верно, как класс *AutoConfiguration загружается в JVM, так как этот класс будет ссылаться на другие классы (из второго @Bean), которые не могут быть разрешены во время загрузки класса
  4. Если(2) false, генерирует ли Spring класс во время выполнения только с помощью первого метода @Bean и вызывает метод?

Спасибо

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

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

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

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

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

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

@ Andy

Благодарим вас, если вы можете высказать свое мнение о том, как Spring реализовал внутреннюю функцию @ConditionalOnClass

Спасибо

0 голосов
/ 05 февраля 2019

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

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

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

Как отмечено вДокументация, связанная с вышеупомянутым, вместо того, чтобы беспокоиться о сценариях, описанных в 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();
    }

  }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...