Понимание Spring @Configuration class


108

После вопроса « Понимание использования Spring @Autowired» я хотел создать полную базу знаний для другого варианта подключения пружин - @Configurationкласса.

Предположим, у меня есть весенний XML-файл, который выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <import resource="another-application-context.xml"/>

  <bean id="someBean" class="stack.overflow.spring.configuration.SomeClassImpl">
    <constructor-arg value="${some.interesting.property}" />
  </bean>

  <bean id="anotherBean" class="stack.overflow.spring.configuration.AnotherClassImpl">
    <constructor-arg ref="someBean"/>
    <constructor-arg ref="beanFromSomewhereElse"/>
  </bean>
</beans>

Как я могу использовать @Configurationвместо этого? Влияет ли это на сам код?

Ответы:


152

Перенос XML в @Configuration

Перенести xml в a можно @Configurationза несколько шагов:

  1. Создайте @Configurationаннотированный класс:

    @Configuration
    public class MyApplicationContext {
    
    }
  2. Для каждого <bean>тега создайте метод, аннотированный @Bean:

    @Configuration
    public class MyApplicationContext {
    
      @Bean(name = "someBean")
      public SomeClass getSomeClass() {
        return new SomeClassImpl(someInterestingProperty); // We still need to inject someInterestingProperty
      }
    
      @Bean(name = "anotherBean")
      public AnotherClass getAnotherClass() {
        return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse); // We still need to inject beanFromSomewhereElse
      }
    }
  3. Для импорта beanFromSomewhereElseнам нужно импортировать его определение. Его можно определить в XML, и мы будем использовать @ImportResource:

    @ImportResource("another-application-context.xml")
    @Configuration
    public class MyApplicationContext {
      ...  
    }

    Если компонент определен в другом @Configurationклассе, мы можем использовать @Importаннотацию:

    @Import(OtherConfiguration.class)
    @Configuration
    public class MyApplicationContext {
      ...
    }
  4. После того, как мы импортировали другие XML или @Configurationклассы, мы можем использовать bean-компоненты, которые они объявляют в нашем контексте, объявив частный член @Configurationкласса следующим образом:

    @Autowired
    @Qualifier(value = "beanFromSomewhereElse")
    private final StrangeBean beanFromSomewhereElse;

    Или используйте его непосредственно как параметр в методе, который определяет bean-компонент, который зависит от этого, beanFromSomewhereElseиспользуя @Qualifierследующее:

    @Bean(name = "anotherBean")
    public AnotherClass getAnotherClass(@Qualifier (value = "beanFromSomewhereElse") final StrangeBean beanFromSomewhereElse) {
      return new AnotherClassImpl(getSomeClass(), beanFromSomewhereElse);
    }
  5. Импорт свойств очень похож на импорт bean-компонента из другого xml или @Configurationкласса. Вместо использования @Qualifierмы будем использовать @Valueследующие свойства:

    @Autowired
    @Value("${some.interesting.property}")
    private final String someInterestingProperty;

    Это также можно использовать с выражениями SpEL .

  6. Чтобы Spring мог обрабатывать такие классы как контейнеры bean-компонентов, нам нужно отметить это в нашем основном xml, поместив этот тег в контекст:

    <context:annotation-config/>

    Теперь вы можете импортировать @Configurationклассы точно так же, как если бы вы создавали простой bean-компонент:

    <bean class="some.package.MyApplicationContext"/>

    Есть способы вообще избежать использования Spring XML, но они не входят в объем этого ответа. Вы можете найти один из этих вариантов в моем сообщении в блоге, на котором я основываю свой ответ.


Преимущества и недостатки использования этого метода

В основном я считаю этот метод объявления bean-компонентов намного более удобным, чем использование XML, благодаря нескольким преимуществам, которые я вижу:

  1. Опечатки - @Configurationклассы компилируются, а опечатки просто не позволяют компилировать
  2. Быстрый сбой (время компиляции) - если вы забудете внедрить bean-компонент, вы потерпите неудачу во время компиляции, а не во время выполнения, как с XML.
  3. В IDE легче ориентироваться - между конструкторами beans для понимания дерева зависимостей.
  4. Возможность легко отладить запуск конфигурации

На мой взгляд, недостатков не так много, но есть несколько, о которых я мог подумать:

  1. Злоупотребление - кодекс легче злоупотреблять, чем XML
  2. С помощью XML вы можете определять зависимости на основе классов, которые недоступны во время компиляции, но предоставляются во время выполнения. С @Configurationклассами вы должны иметь классы, доступные во время компиляции. Обычно это не проблема, но в некоторых случаях это может быть.

Итог: прекрасно комбинировать XML @Configurationи аннотации в контексте вашего приложения. Spring не заботится о методе объявления bean-компонента.


2
Один из возможных недостатков - потеря конфигурации. Допустим, у вас есть класс, который имитирует некоторые функции в процессе разработки, а затем вы хотите заменить его другим классом в среде UAT. Используя XML, нужно просто изменить конфигурацию и разрешить запуск / перезапуск приложения. С этими новыми конфигурациями классов придется перекомпилировать классы.
Jose

5
@JoseChavez - Это отличный аргумент, который я уже слышал пару раз. И я попытался провести статистическое исследование, в котором я не смог найти ни одного приложения или системы, которые используют XML за пределами своих jar-файлов / войн. Практическое значение этого заключается в том, что вам нужно либо разархивировать банку и изменить XML (что я не смог найти никого, кто бы это сделал), либо перестроить ваши банки (это то, что все, с кем я разговаривал, сказали, что они сделали до сих пор) . Итак, подведем итоги: это может быть весомый аргумент, но в реальной жизни это обычно не важно.
Avi

6
Для этого нужны аннотация @Profile и синтаксис "$ {env.value}". С помощью @Profile ("someName") вы можете пометить всю конфигурацию для использования только тогда, когда профиль активен. В вашем файле application.properties (или .yml) вы можете установить spring.profiles.active = someName, default ... Чтобы установить его динамически на основе переменных среды, используйте синтаксис $ {SOME_ENV_VAR} в качестве значения для spring. active.profiles и установите переменную среды. Теперь Spring рекомендует использовать конфигурацию java - docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
Джек Вирс,

Какая альтернатива определению каждого bean-компонента как метода в файле конфигурации?
Асиф Муштак

@AsifMushtaq - вы можете использовать функцию автосканирования и каждый класс, @Component @Service или другие подобные аннотации, будет автоматически преобразован в bean-компонент (но это не было основной темой этого вопроса)
Avi
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.