@Resource vs @Autowired


380

Яку анотацію, @Resource ( jsr250 ) або @Autowired (специфічна для весни), я повинен використовувати в DI?

Я успішно використовував і раніше, @Resource(name="blah")і@Autowired @Qualifier("blah")

Мій інстинкт полягає в дотриманні @Resourceтегів, оскільки його ратифікували люди jsr.
Хтось має сильні думки з цього приводу?


FYI - "Оновлення" я видалив, його слід було задати як окреме запитання. Відповідно до цього відхиленого коментаря, "Ця редакція відхиляється від початкового наміру публікації. Навіть зміни, які мають внести кардинальні зміни, повинні прагнути зберегти цілі власника допису"
mlo55

Відповіді:


194

Навесні перед 3.0 - не має значення, який саме.

Навесні 3.0 є підтримка стандартної анотації ( JSR-330 ) @javax.inject.Inject- використовуйте її з комбінацією @Qualifier. Зауважте, що весна зараз також підтримує @javax.inject.Qualifierмета-анотацію:

@Qualifier
@Retention(RUNTIME)
public @interface YourQualifier {}

Тож можна мати

<bean class="com.pkg.SomeBean">
   <qualifier type="YourQualifier"/>
</bean>

або

@YourQualifier
@Component
public class SomeBean implements Foo { .. }

І потім:

@Inject @YourQualifier private Foo foo;

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


Що стосується початкового запитання: обидва, не вказуючи атрибутів анотації, виконують ін'єкцію за типом. Різниця полягає в:

  • @Resource дозволяє вказати назву введеної квасолі
  • @Autowired дозволяє позначити його як необов'язкове.

Це може здатися нерозумним питанням, але коли ви використовуєте цей стиль ін'єкції, чи потрібен вам публічний сетер fooабо конструктор SomeBeanз Fooпарам?
Снексе

@Snekse - Отримав моя відповідь: stackoverflow.com/questions/3536674 / ...
Snekse

ніпе. Вам нічого цього не потрібно. Просто поле. (Весна заповнює її за допомогою відображення)
Божо

@Bozho Ця відповідь насправді не показує різниці між @Resourceі @Autowired, фактична відповідь - це відповідь, яку опублікував @Ichthyo, я думаю, що цю потрібно оновити.
Борис Треухов

1
так. Насправді я іноді відповідаю на питання, пропонуючи кращу альтернативу підходу. Але я включив відповідь на початкове запитання нижче, для повноти
Божо

508

І те, і інше @Autowired@Inject) @Resourceпрацюють однаково добре. Але є концептуальна різниця або різниця в значенні

  • @Resourceозначає отримати мені відомий ресурс по імені . Ім'я витягується з імені анотованого сеттера або поля, або воно береться з імені-Параметр.
  • @Injectабо @Autowiredспробуйте підключити відповідний інший компонент за типом .

Отже, в основному це дві досить чіткі концепції. На жаль, Spring-Implementation @Resourceмає вбудований резервний модуль, який починається, коли дозвіл назви не вдасться. У цьому випадку вона повертається до @Autowired-доброї роздільної здатності за типом. Незважаючи на те, що ця резервна зручність є зручною, IMHO викликає багато плутанини, оскільки люди не знають про концептуальну різницю і, як правило, використовують @Resourceдля типового автопроводки.


81
Так, саме це має бути прийнятою відповіддю. Наприклад, якщо у вас є @Resourceанотоване поле, а назва поля збігається з ідентифікатором квасолі в контейнері, тоді Spring буде викинути, org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionякщо їх типи відрізняються - це тому, що боби спочатку співпадають за назвою в @Resourceанотації, а не за типом. Але якщо назва ресурсу не відповідає назві квасолі, то Spring передасть їх за типом.
Борис Треухов

Ви можете посилатися на інший пост, який повідомляє про різницю між цими двома, коли ви намагаєтесь використовувати простий MAP. stackoverflow.com/questions/13913752 / ...
Анвер Sadhat

4
+1 за те, що насправді відповів на питання, а не просто рекомендував зовсім іншу "найкращу практику", як це прийнято. Я також знайшов цю публікацію в блозі, де відображаються результати кількох загальних сценаріїв з усіма трьома стилями анотацій, корисними: blogs.sourceallies.com/2011/08/…
Jules

1
Для читача, будь ласка , знайти резюме статті , про яку йдеться @Jules тут: stackoverflow.com/a/23887596/363573
Stephan

3
Одне з наслідків цього: Коли ви хочете ввести квасолі Map / List, @Autowireце не може і не спрацює. У @Resourceцьому випадку вам доведеться скористатися .
Рікардо ван ден Брук

76

Основна відмінність - @Autowiredвесняна анотація. Тоді як@Resource як визначено JSR-250, як ви самі вказали. Таким чином, остання є частиною Java, тоді як перша є специфікою Spring.

Отже, ви маєте рацію в тому, що пропонуєте це. Я знайшов людей використовувати @Autowiredз , @Qualifierтому що це більш потужний. Перехід від якихось рамок до деяких інших вважається дуже малоймовірним, якщо не міфом, особливо у випадку Весни.


7
+1, тому що @Autowiredз @Qualifierдійсно є більш потужним , ніж стандартний JSR @Resourceанотацію (думаю , необов'язкових залежностей, наприклад , з @Autowired(required=false). Ви не можете зробити це з @Resource)
Stefan Haberl

70

Я хотів би підкреслити один коментар від @Jules до цієї відповіді на це питання. Коментар приносить корисне посилання: Spring Injection з @Resource, @Autowired та @Inject . Я закликаю вас прочитати його повністю, проте ось короткий підсумок його корисності:

Як анотації вибирають правильну реалізацію?

@Autowired і @Inject

  1. Відповідає за типом
  2. Обмеження кваліфікованими особами
  3. Збіги за назвою

@Resource

  1. Збіги за назвою
  2. Відповідає за типом
  3. Обмеження кваліфікаційними особами (ігнорується, якщо відповідність знайдено за назвою)

Які анотації (або їх комбінації) слід використовувати для введення бобів?

  1. Явно називайте свій компонент [@Component ("beanName")]

  2. Використовувати @Resourceз nameатрибутом [@Resource (name = "beanName")]

Чому я не повинен використовувати @Qualifier?

Уникайте @Qualifierприміток, якщо ви не хочете створити список подібних бобів. Наприклад, ви можете позначити набір правил певною @Qualifierанотацією. Цей підхід спрощує введення групи класів правил у список, який можна використовувати для обробки даних.

Чи сповільнює ін’єкція квасоля мою програму?

Сканувати конкретні пакети для компонентів [context:component-scan base-package="com.sourceallies.person"]. Хоча це призведе до отримання більшої кількості component-scanконфігурацій, це зменшує ймовірність того, що ви додасте непотрібні компоненти до свого весняного контексту.


Довідка: весняна ін'єкція за допомогою @Resource, @Autowired та @Inject


39

Ось що я отримав із довідника керівництва Spring 3.0.x : -

Порада

Якщо ви маєте намір висловити ін'єкцію, керовану анотацією, не використовуйте в першу чергу @Autowired, навіть якщо це технічно здатне посилатися на ім'я квасолі через значення @Qualifier. Натомість використовуйте анотацію JSR-250 @Resource, яка семантично визначена для ідентифікації конкретного цільового компонента за його унікальним іменем, при цьому оголошений тип не має значення для процесу відповідності.

Як специфічний наслідок цієї смислової різниці, квасоля, яка сама визначається як колекція чи тип карти, не може бути введена через @Autowired, оскільки відповідність типів до них належним чином не застосовується. Використовуйте @Resource для такої квасолі, посилаючись на конкретну колекцію чи боб карти за унікальною назвою.

@Autowired застосовується до полів, конструкторів та методів з багато аргументів, що дозволяє звужувати анотації класифікатора на рівні параметра. Навпаки, @Resource підтримується лише для полів та методів встановлення властивостей bean з одним аргументом. Як наслідок, дотримуйтесь класифікаторів, якщо ваша ціль для ін'єкцій - це конструктор або метод, що має багато аргументів.


Для поточної версії див. Docs.spring.io/spring/docs/current/spring-framework-reference/… (підказка оновлена)
Lu55

27

@Autowired + @Qualifier працюватиме лише з весною DI, якщо ви хочете використовувати якийсь інший DI в майбутньому @Resource - це хороший варіант.

інша різниця, яку я вважав дуже важливою, це те, що @Qualifier не підтримує динамічну проводку бобів, так як @Qualifier не підтримує заповнювач, а @Resource робить це дуже добре.

Наприклад: якщо у вас є інтерфейс з декількома реалізаціями на кшталт цієї

interface parent {

}
@Service("actualService")
class ActualService implements parent{

}
@Service("stubbedService")
class SubbedService implements parent{

}

за допомогою @Autowired & @Qualifier потрібно встановити конкретні дочірні програми, як-от

@Autowired
@Qualifier("actualService") or 
@Qualifier("stubbedService") 
Parent object;

який не забезпечує заповнення місця, тоді як за допомогою @Resource можна поставити заповнювач і використовувати файл властивостей для введення конкретної дочірньої реалізації, наприклад

@Resource(name="${service.name}")
Parent object;  

де service.name встановлено у файлі властивості як

#service.name=actualService
 service.name=stubbedService

Сподіваюся, що хтось допомагає :)


16

Обидва вони однаково хороші. Перевага використання Resource полягає в майбутньому, якщо ви хочете в інший рамки DI, крім весняного, зміни вашого коду будуть набагато простішими. Використовуючи функцію Autowired, ваш код щільно поєднується з пружинами DI.


17
Ніколи не трапиться. І навіть якщо це зробиться - пошук / заміна імен анотацій стане найменшою вашою проблемою.
Даніель Алексюк

13

Коли ви критично аналізуєте базові класи цих двох анотацій. Ви зрозумієте наступні відмінності.

@Autowiredвикористовує AutowiredAnnotationBeanPostProcessor для введення залежностей.
@Resourceвикористовує CommonAnnotationBeanPostProcessorдля введення залежностей.

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

@Autowired / @Inject

1.Мачі за типом 2.
Обмеження кваліфікатами
3. Матчі за назвою

@Resource

1.Мачі за назвою
2.Мачі за типом
3.Рестрики кваліфікованими (ігнорується, якщо збіг знайдено за назвою)


6

З @Resource ви можете зробити самоінжекцію квасолі, це може знадобитися для запуску всієї додаткової логіки, доданої процесорами бін-пост, такими як трансакція або речі, пов'язані з безпекою.

З Spring 4.3+ @Autowiredтакож це вдається .


2

@Resourceчасто використовується об'єктами високого рівня, визначеними за допомогою JNDI. @Autowiredабо @Injectбудуть використовуватися більш звичайні боби.

Наскільки я знаю, це не специфікація, ані навіть конвенція. Це більш логічний спосіб, коли стандартний код буде використовувати ці примітки.


0

Як зауваження тут: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContextі SpringBeanAutowiringSupport.processInjectionBasedOnServletContext НЕ працює з @Resource анотацією. Отже, є різниця.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.