@Resource vs @Autowired


381

Какую аннотацию, @Resource ( jsr250 ) или @Autowired (для Spring) следует использовать в DI?

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

Мой инстинкт состоит в том, чтобы придерживаться @Resourceтега, так как он был утвержден людьми jsr.
У кого-нибудь есть сильные мысли по этому поводу?


К вашему сведению - я удалил «обновление», его следовало задать как отдельный вопрос. Согласно этому отклоненному комментарию: «Это изменение отличается от первоначального намерения поста. Даже изменения, которые должны внести радикальные изменения, должны стремиться сохранить цели владельца поста»
mlo55

Ответы:


195

Весной до 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

нет. Вам не нужно ничего из этого. Просто поле. (Весна населяет это через отражение)
Божо

@ Божо Этот ответ на самом деле не показывает разницу между, @Resourceи @Autowiredфактический ответ тот, который опубликовал @Ichthyo, я думаю, что этот вопрос должен быть обновлен.
Борис Треухов

1
да. На самом деле я иногда отвечаю на вопросы, предлагая лучшую альтернативу подходу. Но я включил ответ на оригинальный вопрос ниже, для полноты
Божо

509

И @Autowired(или @Inject) и @Resourceодинаково хорошо работают. Но есть концептуальная разница или разница в значении

  • @Resourceзначит достань мне известный ресурс по имени . Имя извлекается из имени аннотированного установщика или поля или берется из name-Parameter.
  • @Injectили @Autowiredпопробуйте подключить подходящий другой компонент по типу .

Итак, в основном это две совершенно разные концепции. К сожалению, в Spring -ализации @Resourceесть встроенный запасной вариант, который срабатывает при сбое разрешения по имени. В этом случае он возвращается к @Autowiredразрешению -kind по типу. Хотя этот запасной вариант удобен, ИМХО он вызывает много путаницы, поскольку люди не знают о концептуальных различиях и склонны использовать их @Resourceдля автопроводки на основе типов.


81
Да, это то, что должен быть принятым ответом. Например, если у вас есть @Resourceаннотированное поле, а имя поля совпадает с идентификатором bean-компонента в контейнере, то Spring выдаст, org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionесли их типы различаются - это потому, что сначала bean-компоненты сопоставляются по имени в @Resourceаннотации, а не по типу. Но если имя свойства не совпадает с именем компонента, Spring связывает их по типу.
Борис Треухов

Вы можете сослаться на другой пост, который рассказывает о разнице между этими двумя, когда вы пытаетесь использовать простой MAP. stackoverflow.com/questions/13913752/…
Анвер Садхат

4
+1 за фактический ответ на вопрос, а не просто за рекомендацию совершенно другой «наилучшей практики», как принятый ответ. Я также нашел этот пост в блоге, в котором показаны результаты нескольких распространенных сценариев со всеми тремя стилями аннотаций, полезным: blogs.sourceallies.com/2011/08/…
Жюль

1
Читатель может найти краткое изложение статьи, на которую указывает @Jules, здесь: stackoverflow.com/a/23887596/363573
Stephan

3
Одно из следствий этого: когда вы хотите внедрить bean-компонент 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конфигураций, это уменьшит вероятность того, что вы добавите ненужные компоненты в свой контекст Spring.


Ссылка: Spring Injection с помощью @Resource, @Autowired и @Inject


39

Вот что я получил из справочного руководства Spring 3.0.x :

Подсказка

Если вы намерены выражать внедрение, основанное на аннотациях, по имени, не используйте в первую очередь @Autowired, даже если он технически способен ссылаться на имя компонента с помощью значений @Qualifier. Вместо этого используйте аннотацию JSR-250 @Resource, которая семантически определена для идентификации конкретного целевого компонента по его уникальному имени, причем объявленный тип не имеет значения для процесса сопоставления.

Как конкретное следствие этого семантического различия, bean-компоненты, которые сами определены как тип коллекции или карты, не могут быть внедрены через @Autowired, потому что сопоставление типов не применимо к ним должным образом. Используйте @Resource для таких bean-компонентов, ссылаясь на конкретный bean-компонент коллекции или карты с уникальным именем.

@Autowired применяется к полям, конструкторам и методам с несколькими аргументами, что позволяет сужать аннотации квалификаторов на уровне параметров. Напротив, @Resource поддерживается только для полей и методов установки свойств бинов с одним аргументом. Как следствие, придерживайтесь квалификаторов, если ваша цель внедрения - конструктор или метод с несколькими аргументами.


Для текущей версии см. Docs.spring.io/spring/docs/current/spring-framework-reference/… (совет был обновлен)
Lu55

28

@Autowired + @Qualifier будет работать только с пружинным DI, если вы хотите использовать другие DI в будущем. @Resource - хороший вариант.

Другое отличие, которое я нашел очень существенным, заключается в том, что @Qualifier не поддерживает динамическое связывание bean-компонентов, так как @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, отличную от Spring, изменения в вашем коде будут намного проще. При использовании 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.