Разница между <context: annotation-config> и <context: component-scan>


691

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

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

Для того, чтобы запутать меня еще больше, есть annotation-config атрибут на <context:component-scan>.

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


5
techidiocy.com/annotation-config-vs-component-scan-spring-core вот блестящее объяснение
VdeX,

Подводя итог: используйте по component-scanвозможности.
Джерри Чин

Ответы:


1420

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

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

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

Давайте начнем с базовой настройки трех 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и к бину следующим образом:cccA

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>работать.


8
Цитата: «<context: annotation-config /> можно опустить, если указан <context: component-scan>». Зачем тогда использовать annotation-config? Почему это существует?
CodeClimber

2
Отличный ответ! Ничего подобного короткому ясному примеру с кратким описанием. Понял все это в одном прочтении.
Джигиш

19
Я желаю, чтобы вы написали всю инструкцию по весне! Лучшее объяснение обо всем, что связано с запутанной Spring Framework. Спасибо.
Эскалера

7
Так простое и выдающееся объяснение. Помимо получения ответа, я также узнал хороший способ рассказать вещи :)
Амир Аль

2
Ваш стиль письма очень прост для начинающего. Я надеюсь, что вы можете написать книгу об основной Spring. Я обещаю купить это.
Emeraldhieu

167

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


16
@Tomasz ссылка внизу :(
Ананд Рокзз

95

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

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

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

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

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


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

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

1
Можно ли как-то использовать компонентное сканирование, а не аннотирование?
Корай Тугай

Используйте annotation-config = "false" в контексте: тег annotation-config.
Сара

38

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

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

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


Не могли бы вы объяснить подробнее? Если я использую, <context:component-scan>я не смогу переопределить определение бина, используя XML?
user938214097

@ user938214097 Вы можете определять bean-компоненты либо в XML, либо с помощью аннотаций с помощью сканирования компонентов
Шон Патрик Флойд

Достаточно ли использовать <context:component-scan>? Потеряю ли я что-то, если не пользуюсь <context:annotation-config>?
user938214097

@Tomasz, кажется, ответил на это
Шон Патрик Флойд

31

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

<context:annotation-config /> 

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

В то время как

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

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


31

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

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


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

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

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


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

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

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


15

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

В Spring 2.5 также добавлена ​​поддержка аннотаций JSR-250, таких как @Resource, @PostConstruct и @ PreDestroy. Использование этих аннотаций также требует регистрации определенных 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 сканировать код на наличие бобов для инъекций в указанном пакете (и всех его подпакетах).


14
<context:annotation-config>

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

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

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

Теперь с

<context:component-scan>

Это делает две вещи:

  • Он сканирует все классы, аннотированные @Component, @Service, @Repository, @Controller и @Configuration, и создает Bean-компонент
  • Это делает ту же работу, что и <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 для своих компонентов Repositories, а Репозитории используют @Autowired для JdbcTemplate, DataSource и т.д..components


1
превосходное объяснение Спасибо. @Manuel Иордания
BALS

7
<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.


Этот помог мне понять, что <context: component-scan /> неявно включает <context: annotation-config />; то есть он сканирует определения бинов, а также делает необходимые инъекции. Я экспериментировал с annotation-config = "false", и внедрение не работало, если я не установил явно с помощью <context: annotation-config />. Наконец, мое понимание лучше, чем раньше!
CuriousMind

5
<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-scanto 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 -->

1

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

Это используется, чтобы сообщить контейнеру, что в моем пакете есть классы bean-компонентов, которые сканируют эти классы bean-компонентов. Чтобы сканировать классы bean-компонентов по контейнеру поверх bean-компонента, нам нужно написать одну из аннотаций стереофонического типа, как показано ниже.

@Component, @Service, @Repository,@Controller

<context:annotation-config />:

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


0

<context:component-scan/>Пользовательские теги регистрируют тот же набор бин как это делаются, помимо своей основной ответственности за сканирование пакетов Java и регистрации определений боба из пути к классам.

Если по какой-то причине следует избегать этой регистрации определений bean-компонентов по умолчанию, то для этого нужно указать дополнительный атрибут «annotation-config» в компонентном сканировании следующим образом:

<context:component-scan basePackages="" annotation-config="false"/>

Ссылка: http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html


0

<context:annotation-config>:

Это говорит Spring, что я собираюсь использовать Annotated bean-компоненты в качестве Spring-bean-компонентов, и они будут подключаться через @Autowiredаннотацию вместо объявления в Spring config xml file.

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

Это сообщает контейнеру Spring, с чего начать поиск аннотированных бинов. Здесь весна будет искать все подпакеты базового пакета.


0

Вы можете найти больше информации в файле контекста Spring. следующее находится в spring-context-4.3.xsd

<conxtext:annotation-config />
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.

Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
<context:component-scan>
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes    will be detected.

Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.

Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definitions
being registered; Spring's PropertySourcesPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.

0

В качестве дополнения, вы можете использовать @ComponentScanдля <context:component-scan>аннотации.

Это также описано на spring.io

Настраивает директивы сканирования компонентов для использования с классами @Configuration. Обеспечивает поддержку параллельно с элементом Spring XML.

Стоит отметить, что если вы используете Spring Boot, @Configuration и @ComponentScan могут подразумеваться с помощью аннотации @SpringBootApplication.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.