@Resource vs @Autowired

380

Qual anotação, @Resource ( jsr250 ) ou @Autowired (específico da Primavera) devo usar no DI?

Eu usei com sucesso tanto no passado @Resource(name="blah")quanto@Autowired @Qualifier("blah")

Meu instinto é ficar com a @Resourceetiqueta, uma vez que foi ratificada pelo povo jsr.
Alguém tem pensamentos fortes sobre isso?

mlo55
fonte
FYI - Eu removi a 'atualização', ela deveria ter sido feita como uma pergunta separada. De acordo com este comentário rejeitado, "Esta edição se desvia da intenção original da postagem. Mesmo as edições que precisam fazer mudanças drásticas devem se esforçar para preservar as metas do proprietário da postagem"
mlo55

Respostas:

194

Na primavera pré-3.0, não importa qual.

Na primavera 3.0, há suporte para a anotação padrão ( JSR-330 ) @javax.inject.Inject- use-a com uma combinação de @Qualifier. Observe que o spring agora também suporta a @javax.inject.Qualifiermeta-anotação:

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

Então você pode ter

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

ou

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

E depois:

@Inject @YourQualifier private Foo foo;

Isso faz menos uso de nomes de string, que podem ser digitados incorretamente e são mais difíceis de manter.


Quanto à pergunta original: ambos, sem especificar nenhum atributo da anotação, executam a injeção por tipo. A diferença é:

  • @Resource permite que você especifique um nome do feijão injetado
  • @Autowired permite marcar como não obrigatório.
Bozho
fonte
Isso pode parecer uma pergunta boba, mas quando você usa esse estilo de injeção, precisa de um setter público para fooou de um construtor SomeBeancom um Fooparâmetro?
Snekse
@Snekse - Tenho minha resposta: stackoverflow.com/questions/3536674/…
Snekse
Não. Você não precisa disso. Apenas o campo. (Primavera preenche-lo através de reflexão)
Bozho
@Bozho Na verdade, essa resposta não mostra a diferença entre @Resourcee @Autowired, a resposta real é a postada por @Ichthyo, acho que essa deve ser atualizada.
Boris Treukhov
11
sim. De fato, às vezes respondo perguntas, fornecendo uma alternativa melhor à abordagem. Mas eu incluiu a resposta para a pergunta original abaixo, para a completude
Bozho
509

Ambos @Autowired(ou @Inject) e @Resourcefuncionam igualmente bem. Mas há uma diferença conceitual ou uma diferença no significado

  • @Resourcesignifica obter um recurso conhecido por nome . O nome é extraído do nome do setter ou campo anotado ou do nome-Parameter.
  • @Injectou @Autowiredtente conectar um outro componente adequado por tipo .

Então, basicamente, esses são dois conceitos bastante distintos. Infelizmente, o Spring-Implementation of @Resourcepossui um fallback interno, que entra em ação quando a resolução por nome falha. Nesse caso, ele volta ao @Autowiredtipo de resolução do tipo. Embora esse fallback seja conveniente, IMHO causa muita confusão, porque as pessoas desconhecem a diferença conceitual e tendem a usar @Resourcepara a fiação automática baseada em tipo.

Ichthyo
fonte
81
Sim, é isso que deve ser uma resposta aceita. Por exemplo, se você tiver um @Resourcecampo anotado e o nome do campo corresponder ao ID de um bean no contêiner, o Spring lançará org.springframework.beans.factory.BeanNotOfRequiredTypeExceptionse seus tipos diferirem - isso ocorre porque os grãos são correspondidos primeiro pelo nome na @Resourceanotação, não pelo tipo. Mas se o nome da propriedade não corresponder ao nome do bean, o Spring os conectará por tipo.
Boris Treukhov
Você pode consultar a outra postagem que informa a diferença entre essas duas quando tenta usar um MAP simples. stackoverflow.com/questions/13913752/…
Anver Sadhat 6/13
4
+1 por responder realmente à pergunta em vez de simplesmente recomendar uma "melhor prática" completamente diferente da resposta aceita. Também encontrei esta postagem no blog, que mostra os resultados de vários cenários comuns com os três estilos de anotação, úteis: blogs.sourceallies.com/2011/08/…
Jules
11
Para o leitor, por favor encontrar um resumo do artigo apontado por @Jules aqui: stackoverflow.com/a/23887596/363573
Stephan
3
Uma implicação disso: quando você deseja injetar um bean Map / List, @Autowirenão pode e não funciona. Você terá que usar @Resourcenesse caso.
Ricardo van den Broek
76

A principal diferença é que @Autowiredé uma anotação de primavera. Considerando que @Resourceé especificado pelo JSR-250, como você apontou. Portanto, o último faz parte do Java, enquanto o primeiro é específico do Spring.

Portanto, você está certo ao sugerir isso, em certo sentido. Eu encontrei pessoas usam @Autowiredcom @Qualifierporque é mais poderoso. Mudar de uma estrutura para outra é considerado muito improvável, se não um mito, especialmente no caso da primavera.

Adeel Ansari
fonte
7
+1, porque @Autowiredcom @Qualifierrealmente é mais poderoso do que o padrão JSR @Resourceanotação (pense em dependências opcionais, por exemplo, com @Autowired(required=false). Você não pode fazer isso com @Resource)
Stefan Haberl
70

Gostaria de enfatizar um comentário de @Jules sobre esta resposta a esta pergunta. O comentário traz um link útil: Injeção de mola com @Resource, @Autowired e @Inject . Convido você a lê-lo por inteiro, no entanto, aqui está um rápido resumo de sua utilidade:

Como as anotações selecionam a implementação correta?

@Autowired e @Inject

  1. Jogos por Tipo
  2. Restrições por qualificadores
  3. Jogos por Nome

@Resource

  1. Jogos por Nome
  2. Jogos por Tipo
  3. Restrições por qualificadores (ignoradas se a correspondência for encontrada pelo nome)

Quais anotações (ou combinação de) devo usar para injetar meus beans?

  1. Nomeie explicitamente seu componente [@Component ("beanName")]

  2. Use @Resourcecom o nameatributo [@Resource (name = "beanName")]

Por que não devo usar @Qualifier?

Evite @Qualifieranotações, a menos que deseje criar uma lista de beans semelhantes. Por exemplo, você pode marcar um conjunto de regras com uma @Qualifieranotação específica . Essa abordagem simplifica a injeção de um grupo de classes de regra em uma lista que pode ser usada para o processamento de dados.

A injeção de feijão atrasa meu programa?

Examine pacotes específicos em busca de componentes [context:component-scan base-package="com.sourceallies.person"]. Embora isso resulte em mais component-scanconfigurações, reduz a chance de adicionar componentes desnecessários ao seu contexto do Spring.


Referência: injeção de mola com @Resource, @Autowired e @Inject

Stephan
fonte
39

Foi o que obtive do Manual de Referência do Spring 3.0.x : -

Gorjeta

Se você pretende expressar a injeção acionada por anotação por nome, não use @Autowired, mesmo que seja tecnicamente capaz de se referir a um nome de bean por meio de valores @Qualifier. Em vez disso, use a anotação JSR-250 @Resource, que é definida semanticamente para identificar um componente de destino específico por seu nome exclusivo, com o tipo declarado irrelevante para o processo de correspondência.

Como conseqüência específica dessa diferença semântica, os beans que são definidos como um tipo de coleção ou mapa não podem ser injetados através do @Autowired, porque a correspondência de tipo não é adequada para eles. Use @Resource para esses beans, referindo-se à coleção específica ou bean de mapa por nome exclusivo.

O @Autowired se aplica a campos, construtores e métodos com vários argumentos, permitindo restringir as anotações de qualificador no nível do parâmetro. Por outro lado, o @Resource é suportado apenas para campos e métodos de configuração de propriedades de bean com um único argumento. Como conseqüência, atenha-se aos qualificadores se o seu objetivo de injeção for um construtor ou um método com vários argumentos.

Kartik
fonte
Para a versão atual, consulte docs.spring.io/spring/docs/current/spring-framework-reference/… (a dica foi atualizada)
Lu55
28

O @Autowired + @Qualifier funcionará apenas com o DI de mola, se você quiser usar outro DI no futuro. @Resource é uma boa opção.

outra diferença que achei muito significativa é que o @Qualifier não suporta a fiação dinâmica do bean, pois o @Qualifier não suporta espaço reservado, enquanto o @Resource o faz muito bem.

Por exemplo: se você tiver uma interface com várias implementações como esta

interface parent {

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

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

}

com @Autowired e @Qualifier, você precisa definir uma implementação filho específica, como

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

que não fornece espaço reservado enquanto estiver com @Resource, você pode colocar espaço reservado e usar o arquivo de propriedades para injetar uma implementação filho específica, como

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

em que service.name está definido no arquivo de propriedades como

#service.name=actualService
 service.name=stubbedService

Espero que ajude alguém :)

Todos
fonte
16

Ambos são igualmente bons. A vantagem de usar o recurso é no futuro, se você quiser outra estrutura de DI diferente da primavera, suas alterações de código serão muito mais simples. Usando o Autowired, seu código está fortemente acoplado às molas DI.

Teja Kantamneni
fonte
17
Nunca vai acontecer. E mesmo que isso acontecesse - encontrar / substituir nomes de anotações será o menor dos seus problemas.
Daniel Alexiuc
13

Ao analisar criticamente a partir das classes base dessas duas anotações, você perceberá as seguintes diferenças.

@Autowiredusa AutowiredAnnotationBeanPostProcessor para injetar dependências.
@Resourceusa CommonAnnotationBeanPostProcessorpara injetar dependências.

Embora eles usem classes de pós-processador diferentes, todos se comportam quase de forma idêntica. As diferenças estão criticamente em seus caminhos de execução, que destacamos abaixo.

@Autowired / @Inject

1.Matches por tipo
2.Restricts por Qualifiers
3.Matches por nome

@Resource

1. Correspondências por nome
2. Correspondências por tipo
3. Restrições por qualificadores (ignoradas se a correspondência for encontrada por nome)

Amos Kosgei
fonte
6

Com a @Resourceauto-injeção do bean, pode ser necessário executar toda a lógica extra adicionada pelos processadores pós-bean, como coisas relacionadas a transações ou segurança.

Com o Spring 4.3+ @Autowiredtambém é capaz de fazer isso.

Bohdan Levchenko
fonte
2

@Resourceé frequentemente usado por objetos de alto nível, definidos via JNDI. @Autowiredou @Injectserá usado por feijões mais comuns.

Até onde eu sei, não é uma especificação, nem mesmo uma convenção. É mais a maneira lógica do código padrão usar essas anotações.

Nicolas Zozol
fonte
0

Como uma observação aqui: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContexte SpringBeanAutowiringSupport.processInjectionBasedOnServletContext NÃO funciona com @Resource anotação. Então, há diferença.

msangel
fonte