我们都知道springboot的最大特点是:自动装配。它是怎么实现自动装配的呢?说起来比较low,用一句话概括起来就是:在META-INF/spring.factory配置文件下预先配置好需要装载入ioc容器的bean,实现自动装配。
1 绕不开的springframework
首先,理清一下spring生态的发展历程(本人是从spring4.x开始接触java的)。
在spring的整个生态中,有几个重要的接口
1 beanfactory (ioc容器的基础)
2 ApplicationContext(ioc容器的对外api,对ioc容器做扩展,包括容器的层次性,环境信息)
3 BeanFactoryPostProcessor----BeanDefinitionRegistryPostProcessor(ioc容器的扩展点)
4 BeanPostProcessor(扩展点)
5 ClassPathBeanDefinitionScanner(扫描器)
6 NamespaceHandlerSupport(配置文件解析处理器)
在spring3.0之前,spring容器的实现是通过xml配置文件的形式往ioc容器中注入bean来实现的。在之后的版本,通过引入一些相关的注解,实现通过注解往ioc容器中注入bean
在这个过程中就会设计到上面说的扫描器接口ClassPathBeanDefinitionScanner
看看源码中是怎么体现的:
当我们在xml中配置context:componentScannspring为我们做了什么呢?
spring在解析这个标签时会注入这个Parser,我们看看这个parser做了什么?
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
这里就是去扫描我们配置的package里面包含了component注解的bean
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190706190922290.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MjAzMzM3,size_16,color_FFFFFF,t_70)
2 从xml到Annotation的转变
从xml驱动配置到注解驱动配置的入口:AnnotationConfigApplicationContext
这个类是spring3.0的时候引入的;
首先看看这个类层次关系:
AbstractApplicationContext
GenericApplicationContext
AnnotationConfigApplicationContext
和ClassPathXmlApplicationContext有共同的抽象类,AbstractApplicationContext
具体的用法:
AnnotationConfigApplicationContext context= new AnnotationConfigApplicationContext();
context.refresh();
可以说springboot就是基于这个类做的一层封装!
在这个类的创建过程中做了什么呢?这个是基于注解驱动的关键,翻开源码,我们发现,在这个的创建过程中,会首先向ioc容器中注入6个类:
org.springframework.context.annotation.ConfigurationClassPostProcessor
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
org.springframework.context.event.EventListenerMethodProcessor
org.springframework.context.event.DefaultEventListenerFactory
这里最关键的类:ConfigurationClassPostProcessor是springboot实现自动装配的关键类
ConfigurationClassPostProcessor是一个BeanDefinitionRegistryPostProcessor类,在这个类里面:processConfigBeanDefinitions(BeanDefinitionRegistry registry);方法里面完成对自动装配的处理逻辑
这里就是去判断 容器里面的bean是否有以下注解:
Configuration
Component
ComponentScan
Import
ImportResource
如果包含这些注解,会创建一个ConfigurationClassParser对象对这些bean做相应的处理
processDeferredImportSelectors()即是对:import注解的处理
3 再来看看springbootApplication注解
该注解由三个注解组成:
@SpringBootConfiguration----@Configuration
@EnableAutoConfiguration—@@Import(AutoConfigurationImportSelector.class),@AutoConfigurationPackage
@ComponentScan
实现自动装配是依靠EnableAutoConfiguration实现的,在前门咱们说到:
ConfigurationClassPostProcessor会对import的注解做处理
就是在这里做处理
springboot通过引入AutoConfigurationImportSelector类,在这个类中会通过
SpringFactoriesLoader.loadFactoryNames();方法对项目中的META-INF/factory.properties文件里面配置的类装在入ioc容器实现自动装配
到这里,springboot完成了对外部依赖的bean的注入
那本项目的中配置的bean又是通过什么注入到ioc容器的呢?
注意到:在SpringApplication这个类的创建过程中有个变量,primarySources,该变量存储的就是在调用SpringApplication.run()方法传入的类
通过对componentScann注解的处理,实现本项目的相应bean的注入
由于篇幅和精力有限,文中写的难免有些粗陋和简略的地方。希望致力于springboot的源码研究的同学有所帮助,也算是对自己对spring生态源码的总结