@Autowired @Resource @Inject的区别

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

定义测试用例

若是没有兴趣能够直接跳到下面的结论spring

若是不知道如何测试Spring项目的能够点击这里。ide

首先咱们定义一个Person接口:测试

package site.abely.service;

public interface Person {
    void sayHello();
}

而后定义两个实现类Chinese,Americanui

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

先按类型注入,而后按照名字注入,都没法找到惟一的一个实现类出错。.net

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

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

输出你好code

由于只有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会出现一些意想不到的问题。

相关文章
相关标签/搜索