Spring Boot自动装配的原理
- 自动装配的实现
- EnableAutoConfiguration
- AutoConfigurationImportSelector
Spring Boot中的自动装配,它是Starter的基础,也是Spring Boot的核心。那么什么叫自动装配呢?或者说什么叫装配呢?
简单来说,就是自动将Bean装配到IoC容器中,接下来,我们通过一个Spring Boot整合Redis的例子来了解一下自动装配。
添加Starter依赖:
在application.properties中配置Redis的数据源:
在HelloController中使用RedisTemplate实现Redis的操作:
在这个案例中,我们并没有通过XML形式或者注解形式把RedisTemplate注入IoC容器中,但是在HelloController中却可以直接使用@Autowired来注入redisTemplate实例,这就说明,IoC容器中已经存在RedisTemplate。这就是Spring Boot的自动装配机制。
在往下探究其原理前,可以大胆猜测一下,如何只添加一个Starter依赖,就能完成该依赖组件相关Bean的自动注入?不难猜出,这个机制的实现一定基于某种约定或者规范,只要Starter组件符合Spring Boot中自动装配约定的规范,就能实现自动装配。
自动装配的实现
自动装配在Spring Boot中是通过@EnableAutoConfiguration注解来开启的,这个注解的声明在启动类注解@SpringBootApplication内。
进入@SpringBootApplication注解,可以看到@EnableAutoConfiguration注解的声明。
这里简单和大家讲解一下@Enable注解。其实Spring 3.1版本就已经支持@Enable注解了,它的主要作用把相关组件的Bean装配到IoC容器中。@Enable注解对JavaConfig的进一步完善,为使用Spring Framework的开发者减少了配置代码量,降低了使用的难度。比如常见的@Enable注解有@EnableWebMvc、@EnableScheduling等。
如果基于JavaConfig的形式来完成Bean的装载,则必须要使用@Configuration注解及@Bean注解。而@Enable本质上就是针对这两个注解的封装,所以大家如果仔细关注过这些注解,就不难发现这些注解中都会携带一个@Import注解,比如@EnableScheduling:
因此,使用@Enable注解后,Spring会解析到@Import导入的配置类,从而根据这个配置类中的描述来实现Bean的装配。大家思考一下,@EnableAutoConfiguration的实现原理是不是也一样呢?
EnableAutoConfiguration
进入@EnableAutoConfiguration注解里,可以看到除@Import注解之外,还多了一个@AutoConfigurationPackage注解(它的作用是把使用了该注解的类所在的包及子包下所有组件扫描到Spring IoC容器中)。并且,@Import注解中导入的并不是一个Configuration的配置类,而是一个AutoConfigurationImportSelector类。从这一点来看,它就和其他的@Enable注解有很大的不同。
不过,不管AutoConfigurationImportSelector是什么,它一定会实现配置类的导入,至于导入的方式和普通的@Configuration有什么区别,这就是我们需要去分析的。
AutoConfigurationImportSelector
AutoConfigurationImportSelector实现了ImportSelector,它只有一个selectImports抽象方法,并且返回一个String数组,在这个数组中可以指定需要装配到IoC容器的类,当在@Import中导入一个ImportSelector的实现类之后,会把该实现类中返回的Class名称都装载到IoC容器中。
和@Configuration不同的是,ImportSelector可以实现批量装配,并且还可以通过逻辑处理来实现Bean的选择性装配,也就是可以根据上下文来决定哪些类能够被IoC容器初始化。接下来通过一个简单的例子带大家了解ImportSelector的使用。
首先创建两个类,我们需要把这两个类装配到IoC容器中。
创建一个ImportSelector的实现类,在实现类中把定义的两个Bean加入String数组,这意味着这两个Bean会装配到IoC容器中。
为了模拟EnableAutoConfiguration,我们可以自定义一个类似的注解,通过@Import导入GpImportSelector。
创建一个启动类,在启动类上使用@EnableAutoImport注解后,即可通过ca.getBean从IoC容器中得到FirstClass对象实例。
这种实现方式相比@Import(*Configuration.class)的好处在于装配的灵活性,还可以实现批量。比如GpImportSelector还可以直接在String数组中定义多个Configuration类,由于一个配置类代表的是某一个技术组件中批量的Bean声明,所以在自动装配这个过程中只需要扫描到指定路径下对应的配置类即可。