Разница между <context: annotation-config> и <context: component-scan>
Я изучаю Spring 3, и я, кажется, не понимаю функциональности позади <context:annotation-config>
а также <context:component-scan>
,
Из того, что я прочитал, они, кажется, обрабатывают разные аннотации (@Required, @Autowired и т. Д. Против @Component, @Repository, @Service и т. Д.), Но также и из того, что я читал, они регистрируют одни и те же классы постпроцессора бина.
Чтобы запутать меня еще больше, есть annotation-config
атрибут на <context:component-scan>
,
Может кто-нибудь пролить свет на эти метки? Что похоже, что отличается, одно вытесняется другим, они дополняют друг друга, нужен ли мне один из них, оба?
13 ответов
<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 для трех bean-компонентов, не было создано 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
Хм... чего-то не хватает. Зачем?
Если вы пристально смотрите на классы, класс 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
Даже если боб для класса A
не получается при сканировании, инструменты обработки все еще применяются <context:component-scan>
на всех бобах, зарегистрированных в контексте приложения, даже для 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>
Работа.
Я нашел это хорошее резюме, какие аннотации подобраны какими объявлениями. Изучая его, вы обнаружите, что <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.
Spring позволяет делать две вещи:
- Автопроводка бобов
- Автообнаружение бобов
1. Автопроводка
Обычно в applicationContext.xml вы определяете bean-компоненты, а другие bean-компоненты связываются с использованием методов конструктора или сеттера. Вы можете связывать бины, используя 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 />
используется для определения поиска конкретных бинов и попытки автоматического подключения.
<context:annotation-config>
активирует множество различных аннотаций в bean-компонентах, независимо от того, определены они в XML или путем сканирования компонентов.
<context:component-scan>
для определения бинов без использования XML
Для получения дополнительной информации читайте:
<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 />
,
Разница между ними действительно проста!
<context:annotation-config />
Позволяет использовать аннотации, которые ограничены подключением свойств и конструкторов только для bean-компонентов!
В то время как
<context:component-scan base-package="org.package"/>
Включает все, что <context:annotation-config />
может сделать, с добавлением использования стереотипов, например.. @Component
, @Service
, @Repository
, Таким образом, вы можете связывать целые бины, а не только конструкторы или свойства!
<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" />
Мы только объявили бобы, ничего о <constructor-arg>
а также <property>
DI настраивается в своих собственных классах через @Autowired. Это означает, что Сервисы используют @Autowired для своих компонентов Repositories, а Репозитории используют @Autowired для JdbcTemplate, DataSource и т.д..components
<context:annotation-config>
тег указывает Spring сканировать кодовую базу для автоматического разрешения требований зависимостей классов, содержащих аннотацию @Autowired.
В Spring 2.5 также добавлена поддержка аннотаций JSR-250, таких как @Resource, @PostConstruct и @PreDestroy. Использование этих аннотаций также требует, чтобы определенные BeanPostProcessors были зарегистрированы в контейнере Spring. Как всегда, они могут быть зарегистрированы как отдельные определения бинов, но они также могут быть неявно зарегистрированы путем включения <context:annotation-config>
тег в весенней комплектации.
Взято из Spring документации о конфигурации на основе аннотаций
Spring предоставляет возможность автоматического определения "стереотипных" классов и регистрации соответствующих BeanDefinitions с помощью ApplicationContext.
Согласно javadoc org.springframework.stereotype:
Стереотипы - это аннотации, обозначающие роли типов или методов в общей архитектуре (на концептуальном уровне, а не на уровне реализации). Пример: @Controller @Service @Repository и т. Д. Они предназначены для использования инструментами и аспектами (что делает идеальную цель для точечных копий).
Чтобы автоматически определять такие "стереотипные" классы, <context:component-scan>
тег обязателен.
<context:component-scan>
тег также сообщает Spring, чтобы он сканировал код на предмет наличия бобов для инъекций в указанном пакете (и всех его подпакетах).
<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: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
активировать аннотации на бобах. Ну если не хочешь 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 -->
<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
,
<context:component-scan/>
Пользовательский тег регистрирует тот же набор определений bean-компонентов, что и выполняется, помимо его основной ответственности за сканирование java-пакетов и регистрацию определений bean-компонентов из classpath.
Если по какой-то причине следует избегать этой регистрации определений bean-компонентов по умолчанию, то для этого нужно указать дополнительный атрибут "annotation-config" в компонентном сканировании следующим образом:
<context:component-scan basePackages="" annotation-config="false"/>
Ссылка: http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html
В качестве дополнения вы можете использовать @ComponentScan
использовать <context:component-scan>
в аннотации.
Это также описано на spring.io
Настраивает директивы сканирования компонентов для использования с классами @Configuration. Обеспечивает поддержку параллельно с элементом Spring XML.
Стоит отметить, что если вы используете Spring Boot, @Configuration и @ComponentScan могут подразумеваться с помощью аннотации @SpringBootApplication.
<context:annotation-config>
:
Это говорит Spring, что я собираюсь использовать Annotated bean в качестве Spring Bean, и они будут подключены через @Autowired
аннотации, вместо того, чтобы декларировать весной конфигурационный XML-файл.
<context:component-scan base-package="com.test...">
:
Это сообщает контейнеру Spring, с чего начать поиск аннотированных бинов. Здесь весна будет искать все подпакеты базового пакета.
Вы можете найти больше информации в файле контекста 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.