@Autowired @Resource @Inject的区别

本文详细解析了Spring框架中@Autowired、@Resource及@Inject三种依赖注入方式的区别与应用,并通过实例演示了不同情况下的注入行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我知道在Spring中,可以用@autowired @resource @Inject三种方式进行依赖注入,三种方式的区别在什么地方呢?

定义测试用例

如果没有兴趣可以直接跳到下面的结论

如果不知道如何测试Spring项目的可以点击这里。

首先我们定义一个Person接口:

package site.abely.service;

public interface Person {
    void sayHello();
}

然后定义两个实现类Chinese,American

package site.abely.service;

import org.springframework.stereotype.Component;

@Component
public class Chinese implements Person {
    @Override
    public void sayHello() {
        System.out.println("你好");
    }
}
package site.abely.service;

import org.springframework.stereotype.Component;

@Component
public class American implements Person {
    @Override
    public void sayHello() {
        System.out.println("Hello");
    }
}

结论

@Autowired

先按类型注入,然后按照名字注入,都无法找到唯一的一个实现类出错。

我们将American类中@Component注释,这样在Spring环境中只有Chinese一个实现类,测试代码如下:

@Autowired
Person person;
@Test
public void testSay(){
    person.sayHello();
}

输出你好

因为只有Chinese实现了Person,所以会正确运行(通过类型查找)。

我们取消American类中@Component的注释,运行程序会出现异常:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'site.abely.service.Person' available: expected single matching bean but found 2: american,chinese

因为有American和Chinese两个实现类,Spring不知道该用哪一个注入。

修改测试代码:

@Resource
Person chinese;
@Test
public void testSay(){
    chinese.sayHello();
}

结果会输出你好。此时变量名chinese等于Chinese默认的Qualifier名字。

如果只有一个实现类Chinese(删除American类),而且Chinese不实现Person接口,此时怎么注入Person chinese都会出错(请求的是Person对象,注入的却不是)。

@Autowired(required=false)中如果设置required为false(默认为true),则注入失败时不会抛出异常,但person.sayHello();调用时会出现空指针异常。

@Inject

在Spring的环境下,@Inject和@Autowired是相同的,都是使用AutowiredAnnotationBeanPostProcessor来处理依赖注入,@Inject是jsr-330定义的规范,还是比较推荐使用这种方式进行依赖注入,如果使用这种方式,切换到Guice也是可以的。

如果硬要说两个的区别,首先@Inject是Java EE包里的,在SE环境需要单独引入。另一个区别在于@Autowired可以设置required=false而@Inject并没有这个设置选项。

@Resource

先按名字注入,在按类型注入,都无法找到唯一的一个出现异常

这是jsr-250定义的规范,相对于jsr-330算是比较老的了。这里不推荐使用这种注入方式,下面讨论一下其注入的问题。

首先我们注释American里的@Component,这样在Spring托管的Bean里只有Chinese实现了Person接口,测试用例如下:

@Resource
Person person;
@Test
public void testSay(){
    person.sayHello();
}

输出结果:你好。 此时@Resource先按名字person,并未找到person的bean,然后按照类型来找,只有Chinese,注入成功。

取消American中的@Component注释,出现如下异常:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'site.abely.service.Person' available: expected single matching bean but found 2: american,chinese

此时无论通过名字无法确定,然后通过类型还是无法确定,抛出异常。

修改测试代码

@Resource
Person chinese;
@Test
public void testSay(){
    chinese.sayHello();
}

输出结果你好,此时按名字找到了chinese。

特殊情况

我们上面也说了,我们推荐是用@Inject,不会与Spring产生耦合,当然如果有必要也可以使用@Autowired,为什么不推荐使用@Resouce呢?

现在我们让Chinese不实现Person接口,但仍然被Spring管理,测试代码如下:

@Resource
Person chinese;
@Test
public void testSay(){
    chinese.sayHello();
}

结果如下:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'site.abely.service.TestTest': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'chinese' is expected to be of type 'site.abely.service.Person' but was actually of type 'site.abely.service.Chinese'

结果的问题在于,American是Person的唯一实现类而且被Spring托管,此时却不会被注入。

使用@Autowired输出Hello

对比你可以发现@Resource的问题所在,也许你认为@Resouce的结果是合理的,但是你要考虑到@Qualifier或@Named的作用,我们可以用如下代码取得和@Resouce类似的效果:

@Autowired
@Qualifier("chinese")
Person chinese;

@Test
public void testSay() {
    chinese.sayHello();
}

出现异常:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'site.abely.service.Person' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=chinese)}

这样也会去找一个bean id为chinese的bean,在这种情况下(只有一个实现类),@Resouce要想获得正确的注入只有一个方式,正确的命名Person americanPerson person(person能成功的原因在于Spring中没有bean的id为person的托管类),如果命名不正确,即使使用@Qualifier("american")也不会正确注入(@Resouce不会鸟它的),这会给开发者带来额外的负担,即使只有一个实现类,@Resouce也有可能无法注入。这也是开发中常见的事情,如果你的命名和Sping中某个bean的id相同,@Resouce会出现一些意想不到的问题。

转载于:https://my.oschina.net/abely/blog/806800

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值