我们知道在Spring项目中,如果我们想将一个类注入到Spring的ICO容器中,我们可以用@Component,@Service,@Controller等注解,但是如果我们想注入一个第三方包的类,我们无法将这些注解标注上去(我们修改不了别人打包的类的代码)。所以如果面试官问你怎么注入一个第三方包的类,你就可以回答用@Import注解给容器中注入组件了。(这个问题,我还真被面试官问过。另外你也可以用@Bean注解,像我们平时项目里面注册一个客户端client,大多也是通过配置类和@Bean实现的)
先看一下@Import的源码:
结合源码分析,我们使用@Import,主要有三种方式:
(@Import的源码里面可以看到,有一个属性 value,是Class数组类型)
那么用起来就很简单了,比如这样:@Import({A.class,B.class}),用一个我项目里面的写法给大家看看吧:
上面这个配置类(带有@Configuration注解),是为了实例化一个RocketMq的client,同时用@Import注解,往Spring 容器中注入了一些bean,这些以来,后续其他地方的代码需要用到这些类的时候,就可以直接用@Resource或者@Autowired注解来引入,进行调用了。
ImportSelector接口非常重要,我们SpringBoot自动化装配的实现,就是通过这个接口实现的。
接口的selectImorts方法用于批量导入,主要用于获取所有符合条件的类的全类名(String数组),这些类需要被加载到 IoC 容器中。
看一下ImportSelector接口的源码:
举个例子,我们重写其selectImports方法:
然后在配置类里面的@Import注解里面,把自定义的ImportSelector的实现类也放到@Import注解的属性里面即可。比如@Import({A.class,B.class,TestImportSelector.class}),这样就会有A,B,C,D四个类被注入到Spring容器了。
用ImportBeanDefinitionRegistrar接口和ImportSelector接口类似,都是自己写一个实现类,然后放到@Import注解里面,这里暂时先不细说了(想和其他场景结合起来再说这个的用法)。
这才是我们的重点。因为我希望知识是连贯的,所以每提及一个知识点,都想把它应用的场景带出来。并且知识也不是死记硬背的,知道了原理,看源码也就容易了,会看源码,就只要记一下核心的逻辑就好了,细节不用那么注重,忘记了可以自己再去翻源码。
还是从源码角度来分析,先看springboot启动类上的核心注解,@SpringBootApplication注解,
显然,@SpringBootApplicaton注解是个复合注解,我们主要关注里面的@EnableAutoConfiguration注解,
@EnableAutoConfiguration注解里面用到了@Import注解,并且@Import注解的属性里面是一个叫AutoConfigurationImportSelector.class,什么,xxxImportSelector,它是不是我们刚学的ImportSelector接口的实现类呢?点进去看一下:
继续点进去:
果然,它就是我们刚说的@ImportSelector接口的实现类。那既然如此,它的作用也就显然易见了,就是通过重写其selectImports方法,实现往Spring容器中注入bean。并且,selectImports方法扫描了spring.factories文件,将其中的类注入到IOC容器。
我们从源码角度来证明一下,”selectImports方法扫描了spring.factories文件":
我们先看AutoConfigurationImportSelector的selectImports方法:
我们点进去看getAutoConfigurationEntry方法:
再点进去看getCandidateConfigurations方法:
终于来到了加载spring.factories文件的地方:
好了,就分析到这里了,简单总结一下(面试往这个方向回答就好了):SpringBoot的自动装配是在SpringBoot启动类上的@SpringBootApplication注解中实现的,它是一个复合注解,包括@ComponentScan,@EnableAutoConfiguration等注解,其中,@EnableAutoConfiguration注解里面的@Import注解,加载了一个ImportSelector接口的实现类,AutoConfigurationImportSelector,它重写的selectImports方法,扫描了spring.factories文件中的类,并将其装配到IOC容器中。
有些经典的八股文,其实背后的应用场景还是很广泛的,比如利用SpringBoot自动装配,我们可以对公共组件Starter进行封装,减少大量重复代码。解释一下,在实际项目开发过程中,我们经常会用到一些公共的功能代码,比如说RocketMq消息队列,创建消息队列的生产者和消费者的代码,逻辑都是一样,我们没有必要在每个代码里面都去写一遍,所以我们可以把这部分代码抽出来,单独写在一个模块,写完之后,在Spring.factories文件中指定配置类(配置类中就可以用@Import去注入一些类),最后打包上传到我们的Maven私服,在别的项目里面进行引用,等项目启动的时候就会自动去加载Spring.factories文件里面的配置类。