上期我们讲解SpringBoot中使用的Conditional注解以及在自动装配中是如何使用的,这期我们来讲一讲,SpringBoot中的Import注解、官方是如何使用的以及自动装配的源码解析。
一、Import注解
我们先来看一下这个注解的作用:使用@import导入的类都会被加载到ioc容器中
@Import的4种用法
- 导入Bean
- 导入配置类
- 导入ImportSelector实现类,一般用于加载配置文件中的类
- 导入ImportBeanDefinitionRegistrar实现类
下面我们来逐一演示
一、导入Bean、导入配置类(这两个很简单就放到一起演示了)
新建一个类叫User
public class User {
}再建一个User的配置类UserConfig
public class UserConfig {
@Bean
public User getUser(){
return new User();
}
}
然后我们在引导类中添加一个@Import,导入我们刚刚写的UserConfig
@Import(UserConfig.class)
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
// 根据类型获取相对应的对象
User bean = context.getBean(User.class);
System.out.println(bean);
}
}
这时候启动项目就发现控制台输出了该对象

这时候可能就有人好奇了, Import中明明写的UserConfig, 我们却只获取了User,能不能获取UserConfig这个对象, 结果是可以的
@Import(UserConfig.class)
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
// 根据类型获取相对应的对象
User bean = context.getBean(User.class);
UserConfig bean1 = context.getBean(UserConfig.class);
System.out.println(bean);
System.out.println(bean1);
}
}
两者都能输出,并且能看到他们的路径, 这是因为被导入的UserConfig里面的方法将User放入了Ioc
所以当我们只用@import导入User.class时,是会显示报错信息的

意思是在容器中没有找到com.zhm.springboot.UserConfig类型的实例

导入UserConfig本质上就是导入配置类, 只是这个类上的@Configuration可以省略
二、导入ImportSelector实现类
我们先来看一下这个接口

定义了一个方法反悔了一个String[], 然后传参是注解元数据
那我们也定义一个类MyImportSelector来实现它,里面放入两个我们自定义的类的路径
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.zhm.springboot.domain.User","com.zhm.springboot.domain.Student"};
}
}@Import(MyImportSelector.class)
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
System.out.println(context.getBean(Student.class));
System.out.println(context.getBean(User.class));
}
}
启动项目也是成功的打印了

三、导入ImportBeanDefinitionRegistrar实现类
最后一种用法,我们先来看下这个接口

我们也自定义一个类来实现它
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class);
AbstractBeanDefinition definition = beanDefinitionBuilder.getBeanDefinition();
registry.registerBeanDefinition("user",definition);
}
}引导类中我们进行这样的修改
@Import({MyImportBeanDefinitionRegistrar.class})
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
System.out.println(context.getBean(User.class));
System.out.println(context.getBean("user"));
}
}看下启动项目的打印结果
这样写的好处就是可以自定义ioc中的bean的名称
二、SpringBoot的中使用
介绍完@import之后, 开始今天的重点, 跟踪一下springboot中自动装配的源码
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}一切的源头都要从springboot 中的引导类开始说起

引导类中有两个重要的点
- run方法(加载流程)
- @SpringBootApplication (开启自动装配,包扫描,配置类)
第一点我们先不讲, 重点在@SpringbootApplication身上,我们点进去这个注解

被框出来的注解@EnableAutoConfiguration就是开启自动装配(其他的注解暂时先不介绍),我们继续点进去

被红框框中的就是我们上面一直在介绍的@Import, 可以很明显的看到使用的是第三种方法,导入ImportSelector的实现类,我们点进这个实现类继续看

可以看到它跟我们一样, 重写了selectImports这个方法, 返回的结果是一个String[], 有印象的朋友可能还记得我们@Import注解就是存的一个String[],我们点进红框中的方法继续看
红框中的方法返回就是一个类型为String的list,于是我们继续点进去

可以清晰的看到这边有一个断言, 写的就是 在META-INF/spring.factories中没有找到一条配置, 那也就是说我们的自动装配都放在了 META-INF/spring.factories中, 我们点进上面的loadFactoryNames方法
图中FACTORIES_RESOURCE_LOCATION常量的值正是

我们可以打下断点看下启动看下

图中可以看到总共获取了127条需要自动装配的信息, 那么这些路径从哪来的呢, 上一节讲到过了,就在autoconfigure中的路径

同理可得, 如果我们需要在自己的项目中需要自动装配一些配置, 我们只需要在本项目新建路径META-INF/spring.factories,并在文件中按照这样的写法就可以了

以上就是@import的运用以及springboot自动装配的流程