Різниця між <контекстом: аннотація-конфігурація> та <контекстом: сканування компонентів>


691

Я вивчаю Весну 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> використовується для активації приміток у квасолі, вже зареєстрованій у контексті програми (незалежно від того, чи були вони визначені за допомогою XML або шляхом сканування пакетів).

<context:component-scan>може також робити те, що <context:annotation-config>робить, але <context:component-scan>також сканує пакети, щоб знайти та зареєструвати боби в контексті програми.

Я буду використовувати кілька прикладів, щоб показати відмінності / схожість.

Почне з базової налаштуванням трьох квасолі типу 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>на допомогу. Це активує дії для анотацій, які він знаходить на квасолі, визначеній у тому самому контексті програми, де визначено саме це.

Якщо я зміню свій 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 />єдині роботи на квасолі, зареєстровані в контексті заявки. Оскільки я видалив конфігурацію 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

Навіть якщо квасоля для класу 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>працювати.


8
Цитата: "<контекст: annotation-config /> можна пропустити, якщо вказано <контекст: сканування компонента>". Навіщо взагалі тоді використовувати конфігурацію приміток? Чому воно існує?
CodeClimber

2
Чудова відповідь! Нічого, як короткий чіткий приклад із стислим описом. Розуміли всю справу в одному прочитаному.
Джигіш

19
Бажаю, щоб ви написали весь весняний посібник! Найкраще пояснення щодо всього, що стосується заплутаної програми Spring Framework. Дякую.
eskalera

7
Настільки просте і видатне пояснення. Окрім отримання відповіді, я також навчився добре розповідати речі :)
Амір Аль

2
Ваш стиль письма для початківців дуже легко зрозуміти. Я сподіваюся, що ви можете написати книгу про базову весну. Обіцяю придбати.
смарагдовий

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 посилання вниз :(
Anand Rockzz

95

Весна дозволяє зробити дві речі:

  1. Автомобіль квасолі
  2. Автовідкриття квасолі

1. Автоматичне підключення
Зазвичай у applicationContext.xml ви визначаєте, як квасоля та інші боби проводяться за допомогою конструкторських або сетерних методів. Ви можете з’єднати боби за допомогою XML або приміток. Якщо ви використовуєте примітки, вам потрібно активувати примітки, і вам потрібно додати їх <context:annotation-config />у applicationContext.xml . Це спростить структуру тегу від applicationContext.xml , тому що вам не доведеться вручну підключати боби (конструктор або сетер). Можна використовувати @Autowireанотацію, і квасоля буде з'єднана за типом.

Крок вперед для виходу з конфігурації XML вручну

2. Autodiscovery
Autodiscovery спрощує XML ще на крок далі, в тому сенсі, що вам навіть не потрібно занадто додавати <bean>тег у applicationContext.xml . Ви просто позначте конкретні боби однією з наведених нижче приміток, і Весна автоматично занесе марковану квасолю та їх залежність у контейнер Весна. Анотації такі: @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> активує безліч різних приміток у квасолі, незалежно від того, чи визначено вони в XML або за допомогою сканування компонентів.

<context:component-scan> призначений для визначення бобів без використання XML

Для отримання додаткової інформації читайте:


Чи можете ви поясніть далі? Якщо я використовую, <context:component-scan>я не зможу замінити визначення бобу за допомогою XML?
user938214097

@ user938214097 ви можете визначити квасоля або в XML, або за допомогою анотацій із компонентним скануванням
Шон Патрік Флойд

Чи достатньо використовувати <context:component-scan>? Я щось втрачаю, якщо не користуюся <context:annotation-config>?
user938214097

@Tomasz, схоже, відповів на це
Шон Патрік Флойд

31

Різниця між ними дійсно проста !.

<context:annotation-config /> 

Дозволяє використовувати примітки, які обмежуються проводкою властивостей та конструкторами лише з бобів !.

Де як

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

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


31

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

<context:component-scan>: Реєстрація квасолі +<context:annotation-config>


@Autowired та @Required є цільовим рівнем властивостей, тому бін слід зареєструвати навесні МОК перед використанням цих анотацій. Щоб увімкнути ці анотації, необхідно зареєструвати відповідні боби або включити їх <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 анотації.

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

Взяте з весняної документації конфігурації на основі анотацій


Spring забезпечує можливість автоматичного виявлення "стереотипних" класів та реєстрації відповідних BeanDefinitions за допомогою ApplicationContext.

За даними javadoc of 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>.

Це все

Поширеним сценарієм було, наприклад, оголосити лише боб через 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 для компонентів своїх Репозиторіїв, а Репозиторії використовують @Autowired для JdbcTemplate, DataSource тощо. Компоненти


1
чудове пояснення Спасибі @Manuel Jordan
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-контейнер не буде обробляти анотації з автоматичним підключенням.


Це допомогло мені зрозуміти, що <контекст: компонент-сканування /> неявно дозволяє <контекст: annotation-config />; тобто це сканування визначень квасолі, а також необхідна ін'єкція. Я експериментував з annotation-config = "false", і ін'єкція не спрацювала, якщо явно не встановив, використовуючи <контекст: 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активувати примітки на бобах. Добре, якщо ви не хочете context:component-scanнеявно активувати анотації для вас, можна перейти до налаштування елемента конфігурації анотації 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 -->

1

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

Це використовується для того, щоб сказати контейнеру, що в моєму пакеті є сканування цих бобів. Для того, щоб сканувати класи квасолі в контейнері на верхній частині квасолі, ми повинні написати одну з анотацій стерео типу, наприклад, наступну.

@Component, @Service,@Repository ,@Controller

<context:annotation-config />:

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


0

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

Якщо з якоїсь причини слід уникати реєстрації визначень бобів за замовчуванням, спосіб зробити це - вказати додатковий атрибут "annotation-config" в компонентному скануванні таким чином:

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

Довідка: http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html


0

<context:annotation-config>:

Це говорить весною, що я збираюсь використовувати помічені боби в якості весняної квасолі, і ті, які будуть прокладені наскрізь @Autowired анотацію, замість того, щоб оголосити у весняному xml-файлі config.

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

Це підказує весняний контейнер, з чого почати пошук цих помічених бобів. Тут весна буде шукати всі підпакети базового пакету.


0

ви можете знайти більше інформації у весняному контекстному файлі схеми. далі - у весняному контексті-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.