三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

大白话讲明白 把bean对象纳入Spring容器的几种方式,着重讲@Import注解

大白话讲明白 把bean对象纳入Spring容器的几种方式,着重讲@Import注解

今天来说一下,java开发中把一个bean对象放入Spring容器有哪几种方式?

第一种是用xml的方式或者用@controller、@service、@comfigiration等注解;

第二种是使用@Bean注解;

第三种是使用@Import注解

下面,分别展开讲一下

一、第一种是用xml的方式或者用注解

用xml这种方式,就是在Spring的xml配置文件里,写对应bean标签的内容就行了,xml这种方式可能以前用的多,现在实际开发中基本很少用到,而且也很简单,所以就不展开说了

然后就是使用@controller、@service、@comfigiration这一类常见的注解来把你的bean对象纳入Spring容器来管理。这种方式应该是大家平常使用最多的

具体做法,就是在对应的类上加上 这些注解,Spring启动的时候,会自动的去扫描这些类,然后根据注解去解析封装bean的定义信息,封装成对应的BeanDefinition对象,再用BeanDefinitionRegistry把对应的BeanDefinition注册到Spring中来,然后再用反射生成对应的bean对象,最后把bean对象放到Spring的一级缓存中,也就是singletonObjects,singletonObjects它本质上其实就是个map,concureentHashMap

这些内容很多都和Spring的源码有关,还有这个Spring的三级缓存这些,后边有时间的话,再单独写一下,这里先不展开聊。

反正,总之第一种方式就是 在类上使用了@controller、@service、@comfigiration等这些常用的注解后,Spring启动的时候就会给加了这些注解的类生成bean对象,然后纳入Spring管理。

二、使用@Bean注解

第二种方式就是使用@Bean注解来把一个bean交给Spring容器

具体的使用方法如下

@Bean这种方式,还可以跟@Conditional这个注解配合来使用

比如我有个多数据源的场景,要求数据源1 不存在的话,数据源2才交给Spring去生成,类似这种场景就可以使用@Bean 配合 @Conditional 来实现

具体操作如下:

先建一个DataSource 的类

然后写一个类 实现 Condition 接口,Condition这个接口非常简单,里边就一个matches方法,它的返回值是boolean 类型的。把你需要的判断逻辑写到这个方法里,只有当这个方法返回true时,使用@Condition 注解的的这个bean才会被Spring加载并实例化。

下面我写的 matches 这个方法实现的逻辑也非常简单,就是数据源1不存在,才会返回true

接着,使用刚才定义的 Condition 类

最后测试,验证一下:

如下图,先把数据源1打开

然后写一个测试方法

去执行上边的测试方法,执行后的结果如下图,发现 数据源2并没有被Spring实例化

说明数据源1 存在时,数据源2确实没被Spring实例化

如下图,再把数据源1 注释掉

再来看执行结果,发现:确实是,数据源1不存在时,数据源2 被Spring实例化了

三、使用@Import注解

第三种方式是用@Import注解

@Import这种又可以分为三种方式:

一是 @Import(Xxx.class),这种一次只能加入一个类。

二是用ImportSelector,它可以一次加入多个类,虽然能一次加入多个类,但这种方式它也只能

简单的按照全类名去加入,不能做一些复杂的逻辑判断。

三是用ImportBeanDefinitionRegistrar,它可以实现复杂的条件判断

下面分别展开讲

1、@Import(Xxx.class)

写个Animal 接口

写个Dog类实现 Animal 接口

然后使用 @Import注解 把 Dog类纳入Spring管理

最后测试验证一下,这个测试方法很简单,一看就能看懂,第一个是输出所有纳入Spring容器管理的类,第二个是根据Type 输出 纳入Spring容器管理的 Animal类

看结果,输出了Dog类,说明使用@Import(Dog.class) 这种方式把Dog类纳入到Spring中管理了

2、使用ImportSelector

ImportSelector这种方式,它可以一次加入多个类。

虽然能一次加入多个类,但这种方式它也只能简单的按照全类名去加入,不能做一些复杂的逻辑判

断。

操作起来也非常简单,写一个类 实现ImportSelector接口就可以了

下面来操作一下

先写2个新的动物类,实现Animal接口

接着,写一个类 实现ImportSelector接口,实现里面的selectImports 方法

然后使用ImportSelector

最后看测试结果,下图,可以看到,Panda和Tiger,已经使用ImportSelector的方式纳入Spring管理了

ImportSelector这种方式,挺重要的,SpringBoot自动装配的源码里,就是使用ImportSelector这种方式,去把从配置文件中读取进来的候选装配类列表里 过滤完后需要真正执行自动装配的类装配到Spring容器中的,可以截图看下SpringBoot自动装配的源码

看到没,SpringBoot自动装配的源码里,它也是写了一个类去实现ImportSelector接口里的selectImports这个方法。这里就先简单看一下ImportSelector在源码里大概是怎么实际应用的,关于更详细的Spring和SpringBoot源码,得用Debug打断点进去一步一步跟源码,才能讲的比较明白,Spring和SpringBoot源码断点起来一步步调试还是比较麻烦的,所以,这个得等有比较空闲的时间才能单独的来写一篇,时间的原因,今天就先不深入了。

3、使用ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar这种方式呢,它可以实现复杂的条件判断。

操作起来也非常简单,写一个类 实现ImportBeanDefinitionRegistrar接口,这个接口里有个

registerBeanDefinitions 方法,这个方法的参数可以拿到BeanDefinitionRegistry,也就是

BeanDefinition的注册器,前边也提到过这个注册器,它的作用就是把bean的定义信息注册加入

到Spring容器中。在registerBeanDefinitions 这个方法里可以写你具体的条件判断逻辑,然后用这

个注册器去把bean注册到Spring容器中来。

下面写个例子来操作一下,我写的这个例子也非常简单,大概意思就是,进行逻辑判断:如果Spring中已经有 Cat和Dog类了,我就用ImportBeanDefinitionRegistrar这种方式来给Spring注入一个Monkey类。

首先新建一个 Monkey,实现Animal接口

接着,写一个类,实现ImportBeanDefinitionRegistrar接口,并实现里边的registerBeanDefinitions方法,这个方法里我写的逻辑也非常简单,就是上边说的 如果Spring中已经有 Cat和Dog类了,我就用ImportBeanDefinitionRegistrar这种方式来给Spring注入一个Monkey类。

然后,使用刚才写的ImportBeanDefinitionRegistrar实现类

最后看测试结果,下图,可以看到,Cat和Dog在Spring容器中都存在的话,就把Monkey加入Spring容器。已经使用ImportBeanDefinitionRegistrar这种方式把Monkey纳入Spring管理了

上边已经把 常用的把bean对象纳入Spring容器的几种方式都详细的讲完了

其中 @Import注解 的这种方式虽然实际写代码的过程中,相对其他两种方式用的可能会少一些,但是我认为, @Import这种方式 非常非常非常重要,你看SpringBoot的源码,你就会发现,SpringBoot源码中 大量的使用了@Import 这种方式。只有真正搞懂了@Import是干嘛用的,才更容易理解,看懂Spring的源码,这些一点一滴的基础知识搞懂了以后,再去看Spring源码,会容易很多。一点小小的提示,希望对你有用。

ok,今天就写这么多吧

纯手敲 原创不易,如果觉得对你有帮助,可以关注一下,打赏一下,感谢

← 返回列表