转载

Spring Boot教程(23) – 容器中对象的命名和查找

Spring容器中的对象(Bean)都有自己的标识符(identifier),多数情况下一个Bean只对应一个标识符,你也可以给Bean指定多个标识符。另外在网上的教程里你可能看到id或者name的概念,其实他们和标识符指的是同一种东西。一个对象如果有多个标识符,还会有一个别名(alias)的概念,它是一种相对的叫法,你挑一个标识符出来,剩下的标识符都叫别名。我通常就把Bean的标识符称为Bean的名字。

Bean的命名

对于加了 @Component 注解(包括 @Controller@Service 等)的对象,也就是通过组件扫描而加入容器的对象,通常Bean的名字就是类名(首字母小写),如图:

Spring Boot教程(23) – 容器中对象的命名和查找

如果你想自定义名字,可以给注解添加参数:

Spring Boot教程(23) – 容器中对象的命名和查找

对于在 @Configuration 配置类中通过 @Bean 方法添加的对象来说,Bean的名字就是方法的名字,还可以通过 @Bean 的默认参数自定义名字。

Spring Boot教程(23) – 容器中对象的命名和查找

同时 @Bean 还可以给对象定义多个名字,直接传递个String数组个 @Bean 作为默认参数就行。数组中第一个为主名字,其他的都算是它的别名。

给Bean命名貌似是比较简单的一件事情,当容器准备好的时候,容器中的每个对象都有自己的类型,每个对象都有一个或多个名字,一个名字只对应一个对象。

Bean的查找

ApplicationContext 提供了很多方法来查找Bean,总的来说就是 通过名字查找通过类型查找 。通过名字查找还是比较简单的,毕竟一个名字只对应了一个对象,要么找到,要么找不到(抛出异常)。

Spring Boot教程(23) – 容器中对象的命名和查找
object和mc是同一个对象

通过类型来查找就比较复杂一点,因为一个对象,必定有着父类,父类也有父类,直到Object,用继承链上任何一个类型都可以找到对象。更不用说继承链上的类很可能实现了一个或者多个接口。

Spring Boot教程(23) – 容器中对象的命名和查找

从上图中可以看出,在我写的这个演示程序中,Spring Boot已经自动帮我在容器中扔了300多个对象,其中有163个实现了 Aware 接口,真多。。

消除歧义

99%的情况下,你不会去直接使用 ApplicationContext ,而是通过 @Autowired 引入依赖,你通常会把这个注解加在成员变量、构造方法或者setter方法之上。 @Autowired 默认是按照类型在容器中查找对象的:

Spring Boot教程(23) – 容器中对象的命名和查找
最常见的使用方式

但是呢,有的时候同个类型可能会有多个对象,这个时候选哪个好呢?有很多种方法可以做到。

@Primary 注解帮助你选择一个“主要”的对象。在使用 @Bean 创建Bean的时候,可以添加一个 @Primary 注解,以告诉框架,这个对象是首选的。这样上图在装配的额时候,会选择这个首选的OrderService。

Spring Boot教程(23) – 容器中对象的命名和查找

@Qualifier 注解提供了更细致的控制方式,他的字面意思是“限定符”,我刚开始学习的就搞不懂限定符的意义是啥。后来逐渐明白,限定符就跟标签一样,你在写博客的时候经常会给文章添加标签,一篇文章可能有多个标签,一个标签也能对应多篇文章。限定符也是一样的,一个对象可能有多个限定符,一个限定符可能对应多个对象。你需要分别在对象创建的时候和装配的时候指定限定符:

Spring Boot教程(23) – 容器中对象的命名和查找
添加限定符
Spring Boot教程(23) – 容器中对象的命名和查找
根据限定符装配

事实上,容器中每个对象,都给了个默认的限定符,那就是对象的名字。所以,当你直接指定名字的时候,就不会有歧义了,因为一个名字只对应一个对象。

Spring Boot教程(23) – 容器中对象的命名和查找

如果你在项目里经常通过 @Autowired + @Qualifier 的方式用名字来查找对象,那么你的使用方式,其实和 @Qualifier 的语义有点相悖。更好的选择是使用JSR-250提供了的 @Resource 注解,你直接通过名字来装配对象。

Spring Boot教程(23) – 容器中对象的命名和查找

我更倾向于避免在项目中用名字来查找对象,因为如果你进行类的重构或者方法的重构之后,会导致对象的名字被更改,导致装配的时候可能找不到对象。

说点其他的

目前Spring Boot教程已经写了23篇,关于Spring核心的一些东西,比如IoC容器以及AOP都介绍了不少,目前写出来的知识,日常开发至少够用个三年吧。

你要是问我还有没有可以继续深入挖掘的东西,我说有。但是实在是写不出来了,一是看的人少,二是暂时用不到。继续深入的确可以使我对Spring的了解更细致,但是这非常容易陷入一个怪圈,就是耗费大量时间在钻牛角尖,而不是其他更有价值的事情上,比如用已有的技术去做点小产品。

接下来我规划写一点数据库相关的东西,JDBC,JPA(Hiberante)等内容,然后是一些运维相关的东西,再然后会根据场景写如果实现某某功能等等。Spring Cloud相关的东西就先放一放,因为如果项目里没有需求的话,学习起来其实挺枯燥的。

原文  https://fookwood.com/spring-boot-tutorial-23-beanname
正文到此结束
Loading...