上期我们讲解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自动装配的流程
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)