Spring - @Resource, @Autowire, @Inject

2019/11/30

如何查看Spring容器中的所有Bean?

@Autowired
private ApplicationContext applicationContext;

public void printAllBeanNames(){
    String beanNames = Arrays.toString(applicationContext.getBeanDefinitionNames());
    String result = beanNames.replaceAll(",", "\n");
    System.out.println(result);
}


为什么要使用@Resouce, @Autowire, @Inject

我的理解是,通过Spring从容器中获得需要对象的三种方式。

这样做的好处是,软件工程师不用操心如何创建对象,而是把这个任务全权交给Spring,当你需要用到某个对象时,直接从Spring容器中取即可。

首先来看下这三种方式的概况:


Ambiguous Beans

先介绍下需要的接口与实现类:

public interface Party {

    /**
     * Just for test.
     */
    void printDefault();
}


@Component
public class Person implements Party {

    @Bean(value = "personBean")
    public Person buildPersonForTest(){
        return new Person();
    }

    @Override
    public void printDefault(){
        System.out.println("Hi Person.");
    }
}

@Component
public class Organization implements Party {
    @Override
    public void printDefault() {
        System.out.println("Hi Organization.");
    }
}

/**
 * Ambiguous Beans.
 */
@Resource
private Party party;

@Autowired
private Party party;

@Inject
private Party party;

三种方式都会有如下问题:

Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type ‘com.frankie.demo.interfaces.Party’ available:
expected single matching bean but found 3: organization,person,personBean

也就是说,它只想要一个合适的对象,但是Spring容器中有三个,因此无法完成精准匹配。


Field Name

/**
 * Filed Type
 */
@Resource
private Party person;

@Autowired
private Party person;

@Inject
private Party person;

@Resource(name = "person")
private Party party;

以上四种情况都会正常获得Person类的实例。

先说下@Resource,首先它会根据field name,也就是person尝试从spring容器中获得对应的Bean,很巧,容器中正好有这个Bean

然后说下@Autowired、@Inject,他两首先会根据field type也就是party,尝试从spring容器中获得对应的Bean,但是容器中并没有这个Bean,由于没有使用@Qualifier注解,因此尝试通过filed name获得Bean,bingo!

至于第四种写法,虽然通过field namefile type都没有从Spring容器中获得对于的Bean,但是可以通过@Resource加上name property指定bean name的方式去获得。


Field Type

/**
 * Filed Type
 */
@Resource
private Person party;

@Autowired
private Person party;

@Inject
private Person party;

以上三种情况都会根据field type也就是Person,尝试从Spring容器中获得person bean,注意喔,根据field type去查找Bean时,用的是首字母小写的形式喔。


Qualifier

/**
 * Qualifier
 */

@Resource
@Qualifier(value = "personBean")
private Person frankie;

@Autowired
@Qualifier(value = "personBean")
private Person frankie;

@Inject
@Qualifier(value = "personBean")
private Person frankie;

@Resource(name = "personBean")
private Person frankie;

当软件工程师自定义bean name时,就有可能需要用到@Qualifier注解,有一种常见的场景:配置多数据源。

当然,除了使用@Qualifier注解,我觉得使用@Resource加上name property的方式更加简洁明了。

最后总结下,在真实的开发场景中,尽量避免构建field namebean name的匹配关系,因为filed name随时可能会被你Shift + F6改变。
一般情况下,直接使用@Resource(name = "lowercase_class_name")
当一个类或接口对应多个Bean时,使用@Resource(name = "specified_bean_name")

Reference


一位喜欢提问、尝试的程序员

(转载本站文章请注明作者和出处 姚屹晨-yaoyichen

Post Directory