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