Разница между <context: annotation-config> и <context: component-scan> - PullRequest
656 голосов
/ 14 сентября 2011

Я изучаю Spring 3, и я, кажется, не понимаю функциональности <context:annotation-config> и <context:component-scan>.

Из того, что я прочитал, они, похоже, обрабатывают разные аннотации (@Required, @Autowired и т. Д. По сравнению с @Component, @Repository, @Service и т. Д.), А также из того, что я прочитал, они регистрируют одни и те же классы постпроцессора бина.

Чтобы запутать меня еще больше, в <context:component-scan>.

есть атрибут annotation-config.

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

Ответы [ 15 ]

1372 голосов
/ 17 сентября 2011

<context:annotation-config> используется для активации аннотаций в bean-компонентах, уже зарегистрированных в контексте приложения (независимо от того, были ли они определены с помощью XML или путем сканирования пакетов).

<context:component-scan> также может делать то, что делает <context:annotation-config>, но <context:component-scan> также сканирует пакеты для поиска и регистрации bean-компонентов в контексте приложения.

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

Давайте начнем с базовой настройки трех бинов типа A, B и C, с B и C, вводимыми в A.

package com.xxx;
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc; 
  }
}

со следующей конфигурацией XML:

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
  <property name="bbb" ref="bBean" />
  <property name="ccc" ref="cBean" />
</bean>

Загрузка контекста приводит к следующему выводу:

creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6

ОК, это ожидаемый результат. Но это «старый стиль» весны. Теперь у нас есть аннотации, поэтому давайте используем их для упрощения XML.

Во-первых, давайте автоматически подключим свойства bbb и ccc к бобу A следующим образом:

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

Это позволяет мне удалить из XML следующие строки:

<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />

Мой XML теперь упрощен до этого:

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

Когда я загружаю контекст, я получаю следующий вывод:

creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf

ОК, это неправильно! Что случилось? Почему мои свойства не подключены автоматически?

Ну, аннотации - хорошая функция, но сами по себе они ничего не делают. Они просто комментируют вещи. Вам нужен инструмент обработки, чтобы найти аннотации и что-то с ними сделать.

<context:annotation-config> на помощь. Это активирует действия для аннотаций, которые он находит в bean-компонентах, определенных в том же контексте приложения, где он определен.

Если я изменю свой XML на это:

<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

когда я загружаю контекст приложения, я получаю правильный результат:

creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b

Хорошо, это хорошо, но я удалил две строки из XML и добавил одну. Это не очень большая разница. Идея с аннотациями состоит в том, что он должен удалить XML.

Итак, давайте удалим определения XML и заменим их всеми аннотациями:

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

В то время как в XML мы сохраняем только это:

<context:annotation-config />

Мы загружаем контекст, и результат ... Ничего. Бины не создаются, бобы не подключаются автоматически. Ничего!

Это потому, что, как я сказал в первом абзаце, <context:annotation-config /> работает только с bean-компонентами, зарегистрированными в контексте приложения. Поскольку я удалил конфигурацию XML для трех компонентов, он не создан, и у <context:annotation-config /> нет «целей» для работы.

Но это не будет проблемой для <context:component-scan>, который может сканировать пакет на предмет "целей" для работы. Давайте изменим содержимое XML-конфигурации на следующую запись:

<context:component-scan base-package="com.xxx" />

Когда я загружаю контекст, я получаю следующий вывод:

creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

Хммм ... чего-то не хватает. Зачем?

Если вы внимательно присмотритесь к классам, у класса A есть пакет com.yyy, но я указал в <context:component-scan>, чтобы использовать пакет com.xxx, так что это полностью пропустило мой A класс и только поднялось B и C, которые находятся в пакете com.xxx.

Чтобы исправить это, я добавляю и другой пакет:

<context:component-scan base-package="com.xxx,com.yyy" />

и теперь мы получаем ожидаемый результат:

creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9

И это все! Теперь у вас больше нет определений XML, у вас есть аннотации.

В качестве последнего примера, сохраняя аннотированные классы A, B и C и добавляя следующее в XML, что мы получим после загрузки контекста?

<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

Мы все еще получаем правильный результат:

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

Даже если bean-компонент для класса A не получен сканированием, инструменты обработки по-прежнему применяются <context:component-scan> ко всем зарегистрированным bean-компонентам в контексте приложения, даже для A, который был вручную зарегистрирован в XML.

Но что, если у нас будет следующий XML, мы получим дублированные бины, потому что мы указали и <context:annotation-config />, и <context:component-scan>?

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

Нет, дубликатов нет, Мы снова получаем ожидаемый результат:

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

Это потому, что оба тега регистрируют одни и те же инструменты обработки (<context:annotation-config /> можно опустить, если указано <context:component-scan>), но Spring позаботится о запуске их только один раз.

Даже если вы зарегистрируете инструменты обработки самостоятельнонесколько раз Spring по-прежнему будет проверять свою магию только один раз;этот XML:

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

будет по-прежнему генерировать следующий результат:

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

Хорошо, что насчет удаления.

Я надеюсь, что эта информация вместе с ответами @Tomasz Nurkiewicz и @Sean Patrick Floyd - все, что вам нужно, чтобы понять, как работают <context:annotation-config> и <context:component-scan>.

161 голосов
/ 14 сентября 2011

Я нашел это хорошее резюме , какие аннотации выбираются какими объявлениями. Изучив его, вы обнаружите, что <context:component-scan/> распознает расширенный набор аннотаций, распознаваемых <context:annotation-config/>, а именно:

  • @Component, @Service, @Repository, @Controller, @Endpoint
  • @Configuration, @Bean, @Lazy, @Scope, @Order, @Primary, @Profile, @DependsOn, @Import, @ImportResource

Как вы можете видеть <context:component-scan/> логически расширяет <context:annotation-config/> с компонентным сканированием CLASSPATH и функциями Java @Configuration.

90 голосов
/ 12 августа 2013

Spring позволяет делать две вещи:

  1. Автопроводка бобов
  2. Автообнаружение бобов

1. * 1010 автоматического связывания *
Обычно в applicationContext.xml вы определяете bean-компоненты, а другие bean-компоненты связываются методы конструктора или сеттера. Вы можете связывать бины, используя XML или аннотации. Если вы используете аннотации, вам нужно активировать аннотации и добавить <context:annotation-config /> в applicationContext.xml . Это упростит структура тега из applicationContext.xml , потому что вам не придется вручную связывать компоненты (конструктор или установщик). Вы можете использовать аннотацию @Autowire, и компоненты будут подключены по типу.

Шаг вперед для выхода из ручной настройки XML -

2. Autodiscovery
Автообнаружение упрощает XML еще на один шаг, в том смысле, что вам даже не нужно добавлять тег <bean> в applicationContext.xml . Вы просто помечаете определенные bean-компоненты одной из следующих аннотаций, и Spring автоматически подключает помеченные bean-компоненты и их зависимости в контейнер Spring. Аннотации следующие: @ Контроллер , @ Сервис , @ Компонент , @ Репозиторий . Используя <context:component-scan> и указав базовый пакет, Spring автоматически обнаружит и подключит компоненты в контейнер Spring.


В заключение:

  • <context:annotation-config /> используется для того, чтобы иметь возможность использовать @ Autowired аннотация
  • <context:component-scan /> используется для определения поиска конкретные бобы и попытка автопроводки.
34 голосов
/ 14 сентября 2011

<context:annotation-config> активирует множество различных аннотаций в bean-компонентах, независимо от того, определены они в XML или путем сканирования компонентов.

<context:component-scan> для определения бинов без использования XML

Для получения дополнительной информации читайте:

29 голосов
/ 02 августа 2013

Разница между ними действительно проста.

<context:annotation-config /> 

Позволяет использовать аннотации, которые ограничены подключением свойств и конструкторов только для bean-компонентов!.

Где как

<context:component-scan base-package="org.package"/> 

Включает все, что может сделать <context:annotation-config />, с добавлением стереотипов, например .. @Component, @Service, @Repository Таким образом, вы можете связывать целые бины, а не ограничиваться только конструкторами или свойствами!

27 голосов
/ 02 января 2016

<context:annotation-config>: Сканирование и активация аннотаций для уже зарегистрированных bean-компонентов в конфигурации весны xml.

<context:component-scan>: Регистрация бина + <context:annotation-config>


@ Autowired и @ Required являются целевым уровнем свойства , поэтому бин должен быть зарегистрирован весной IOC перед использованием этих аннотаций. Чтобы включить эти аннотации, нужно либо зарегистрировать соответствующие бины, либо включить <context:annotation-config />. т.е. <context:annotation-config /> работает только с зарегистрированными bean-компонентами.

@ Обязательно включает RequiredAnnotationBeanPostProcessor инструмент обработки
@ Autowired включает AutowiredAnnotationBeanPostProcessor инструмент обработки

Примечание: Сама аннотация ничего не делает, нам нужен Обрабатывающий инструмент , который является классом внизу и отвечает за основной процесс.


@ Repository, @Service и @Controller являются @ Component , и они имеют целевой уровень класса .

<context:component-scan> сканирует пакет, находит и регистрирует компоненты и включает в себя работу, проделанную <context:annotation-config />.

Перенос XML в аннотации

15 голосов
/ 31 августа 2012

Тег <context:annotation-config> указывает Spring сканировать кодовую базу для автоматического разрешения требований зависимостей классов, содержащих аннотацию @Autowired.

Spring 2.5 также добавляет поддержку аннотаций JSR-250, таких как @Resource, @PostConstruct и @ PreDestroy.Use из этих аннотаций также требует, чтобы определенные BeanPostProcessors были зарегистрированы в контейнере Spring. Как всегда, они могут быть зарегистрированы как отдельные определения bean-компонентов, но они также могут быть неявно зарегистрированы путем включения тега <context:annotation-config> в конфигурацию Spring.

Взято из Spring документации Конфигурация на основе аннотаций


Spring предоставляет возможность автоматического обнаружения «стереотипных» классов и регистрации соответствующих BeanDefinitions с помощью ApplicationContext.

Согласно Javadoc org.springframework.stereotype :

Стереотипы - это аннотации, обозначающие роли типов или методов в общей архитектуре (на концептуальном уровне, а не на уровне реализации). Пример: @Controller @Service @Repository и т. Д. Они предназначены для использования инструментами и аспектами (что делает их идеальной мишенью для точечных).

Для автоматического определения таких «стереотипных» классов требуется тег <context:component-scan>.

Тег <context:component-scan> также указывает Spring сканировать код на наличие бобов для инъекций в указанном пакете (и всех его подпакетах).

12 голосов
/ 06 июня 2014
<context:annotation-config>

Только разрешает аннотации @Autowired и @Qualifer, вот и все, речь идет о Внедрении зависимостей , Есть другие аннотации, которые выполняют ту же работу, я думаю, что @Inject, но все решают DI через аннотации.

Имейте в виду, что даже когда вы объявили элемент <context:annotation-config>, вы должны объявить ваш класс как Bean, помните, у нас есть три доступных варианта

  • XML: <bean>
  • @ Аннотации: @Component, @Service, @Repository, @Controller
  • JavaConfig: @Configuration, @ Bean

Теперь с

<context:component-scan>

Он делает две вещи:

  • Сканирует все классы, помеченные @Component, @Service, @Repository, @Controller и @Configuration и создание компонента
  • Он выполняет ту же работу, что и <context:annotation-config>.

Поэтому, если вы объявляете <context:component-scan>, больше нет необходимости объявлять <context:annotation-config> тоже.

Вот и все

Распространенным сценарием было, например, объявить только bean-компонент через XML и разрешить DI с помощью аннотаций, например

<bean id="serviceBeanA" class="com.something.CarServiceImpl" />
<bean id="serviceBeanB" class="com.something.PersonServiceImpl" />
<bean id="repositoryBeanA" class="com.something.CarRepository" />
<bean id="repositoryBeanB" class="com.something.PersonRepository" />

Мы только объявили bean-компоненты, ничего о <constructor-arg> и <property>, DI настраивается в их собственных классах через @Autowired. Это означает, что Сервисы используют @Autowired для своих компонентов Репозитариев, а Репозитории используют @Autowired для JdbcTemplate, DataSource и т.д..components

7 голосов
/ 03 октября 2014
<context:component-scan /> implicitly enables <context:annotation-config/>

попробуйте <context:component-scan base-package="..." annotation-config="false"/>, в вашей конфигурации @ Service, @Repository, @ Component работает нормально, но @ Autowired, @ Resource и @ Inject не работает.

Это означает, что AutowiredAnnotationBeanPostProcessor не будет включен, и контейнер Spring не будет обрабатывать аннотации Autowiring.

5 голосов
/ 10 апреля 2015
<context:annotation-config/> <!-- is used to activate the annotation for beans -->
<context:component-scan base-package="x.y.MyClass" /> <!-- is for the Spring IOC container to look for the beans in the base package. -->

Другим важным моментом, который следует отметить, является то, что context:component-scan неявно вызывает context:annotation-config, чтобы активировать аннотации на bean-компонентах. Если вы не хотите, чтобы context:component-scan неявно активировал для вас аннотации, вы можете установить для элемента annotation-config параметра context:component-scan значение false.

.

Подведем итог:

<context:annotation-config/> <!-- activates the annotations --> 
<context:component-scan base-package="x.y.MyClass" /> <!-- activates the annotations + register the beans by looking inside the base-package -->
...