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

633

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

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

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

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

Теги:
spring
configuration
annotations
spring-3

14 ответов

1398

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

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

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

Давайте начнем с базовой установки трех beans типов 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

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

Сначала давайте autowire свойства bbb и ccc на bean 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> на помощь. Это активирует действия для аннотаций, которые он находит на beans, определенных в том же контексте приложения, где он определен.

Если я изменил свой 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 />

Мы загружаем контекст, и результат... Ничего. Нет beans, нет beans. Ничего!

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

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

Если вы посмотрите на классы, class 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> для всех beans зарегистрированных в контексте приложения, даже для A, который был зарегистрирован вручную в XML.

Но что, если у нас есть следующий XML, мы получим дублированный beans, потому что мы указали как <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> работают.

  • 25
    +1 за отличное объяснение!
  • 7
    Цитата: «<context: annotation-config /> можно опустить, если указан <context: component-scan>». Зачем тогда использовать annotation-config? Почему это существует?
Показать ещё 39 комментариев
152

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

  • 12
    @ Tomasz ссылка внизу :(
84

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

  • Autowiring beans
  • Автообнаружение beans

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

Шаг вперед для выхода из ручной конфигурации XML:

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


Как вывод:

  • <context:annotation-config /> используется, чтобы иметь возможность использовать @Автоматическая аннотация
  • <context:component-scan /> используется для определения поиска специфический beans и попытка автоустройства.
  • 1
    Можно ли как-то использовать компонентное сканирование, а не аннотирование-конфигурация?
  • 0
    Используйте annotation-config = "false" в контексте: тег annotation-config.
31

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

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

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

  • 0
    Не могли бы вы объяснить подробнее? Если я использую <context:component-scan> я не смогу переопределить определение компонента, используя XML?
  • 0
    @ user938214097 вы можете определять bean-компоненты либо в XML, либо с помощью аннотаций с помощью сканирования компонентов.
Показать ещё 2 комментария
29

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

<context:annotation-config /> 

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

Где

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

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

23

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

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


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

@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 и т.д. Они предназначены для использования инструментами и аспектами (идеальная цель для pointcuts).

Чтобы автоопределить такие классы стереотипа, требуется тег <context:component-scan>.

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

10
<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, и создает 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

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

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

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

<conxtext:annotation-config />
Activates various annotations to be detected in bean classes: Spring @Required and
@Autowired, as well as JSR 250 @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS @WebServiceRef (if available), EJB 3 @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 @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 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

<context:annotation-config>:

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

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

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

0

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

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

@Component, @Service, @Repository, @Controller

<context:annotation-config />:

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

0

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

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню