@Component及其衍生注解:@Configuration、@Controller、@Service、@Repository标记的类,被Spring IOC扫描到后,即可被容器管理起来。其原理基本涵盖在AnnotationConfigApplicationContext构造函数体的三行代码里。
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
1. this()
这个无参构造方法做了三件事情:
- 首先创建bean工厂,实际上是在父类GenericApplicationContext的构造器里完成的
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
- 然后初始化reader和scanner,这两个类就是AnnotationConfigApplicationContext类中的成员变量,作用是相同的,都是用来注册BeanDefinition对象,只不过场景不同
public AnnotationConfigApplicationContext() {
// 生成并注册5个BeanDefinition
// 1.ConfigurationClassPostProcessor
// 2.AutowiredAnnotationBeanPostProcessor
// 3.CommonAnnotationBeanPostProcessor
// 4.EventListenerMethodProcessor
// 5.DefaultEventListenerFactory
this.reader = new AnnotatedBeanDefinitionReader(this);
// spring提供api用来动态扫描注解
// 一般供扩展spring的时候用,内部扫描也是通过它
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
AnnotatedBeanDefinitionReader用于解析单个类或一组类的注解,并将其转换为相应的BeanDefinition对象。它通常用于编程式地注册bean定义,即在代码中显式地调用AnnotatedBeanDefinitionReader的方法来注册bean定义。
ClassPathBeanDefinitionScanner则用于在类路径下扫描指定的包,查找带有特定注解的类,并将其转换为相应的BeanDefinition对象。它通常用于自动化地注册bean定义,即在Spring容器启动时自动扫描指定包下的类,并将其转换为bean定义。
总的来说,AnnotatedBeanDefinitionReader适用于手动注册bean定义,上述5个Spring提供的类就是通过reader编程试注入的,而ClassPathBeanDefinitionScanner适用于自动化注册bean定义。
继续查看AnnotatedBeanDefinitionReader构造方法,上述5个类即通过AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)注册到beanDefinitionMap中
beanName |
类名 |
是否BeanDefinitionRegistryPostProcessor |
是否BeanFactoryPostProcessor |
是否BeanPostProcessor |
org.springframework.context.annotation.internalConfigurationAnnotationProcessor |
ConfigurationClassPostProcessor |
是 |
是 |
是 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor |
AutowiredAnnotationBeanPostProcessor |
否 |
否 |
是 |
org.springframework.context.annotation.internalCommonAnnotationProcessor |
CommonAnnotationBeanPostProcessor |
否 |
否 |
是 |
org.springframework.context.event.internalEventListenerProcessor |
EventListenerMethodProcessor |
否 |
是 |
否 |
org.springframework.context.event.internalEventListenerFactory |
DefaultEventListenerFactory |
否 |
否 |
否 |
2. scan(basePackages)
在指定的基础包中执行扫描以查找组件类,这里是将扫描的类注册到beanDefinitionMap中。使用的正是上述创建scanner,该在创建的过程中,设置了一个@Component的注解类型过滤器,正是这个过滤器将扫描到的所有类过滤出标记了@Component及其衍生注解的类,逻辑如下:
//判断元信息读取器读取的类是否符合容器定义的注解过滤规则
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 如果读取的类的注解在排除注解过滤规则中,返回false
for (TypeFilter tf : this.excludeFilters) {
// 规则匹配功能
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 如果读取的类的注解在包含的注解的过滤规则中,则返回true
// 这里的includeFilters已经有了@Component过滤器
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
// 如果读取的类的注解既不在排除规则,也不在包含规则中,则返回false
return false;
}
3. refresh()
该方法是Spring应用上下文的核心方法,它负责完成Spring容器的初始化和刷新工作,由于篇幅有限,这里主要讲解与扫描和解析相关的方法:invokeBeanFactoryPostProcessors(beanFactory)
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// getBeanFactoryPostProcessors()得到的是程序员通过API直接添加的BeanFactory
// 这里getBeanFactoryPostProcessors()90%情况都是返回空
// 只有10%情况不为空【程序员通过API手动添加】
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
接下来是invokeBeanFactoryPostProcessors方法了,该方法会调用在上述注入到beanDefinitionMap中的Spring内置的类BeanDefinitionRegistryPostProcessor及BeanFactoryPostProcessor对应的接口方法。整体逻辑可以分成两部分看:
- 先调用BeanDefinitionRegistryPostProcessor的子类;
- 再调用BeanFactoryPostProcessor的子类。
文章来源:https://www.toymoban.com/news/detail-561288.html
这里面会调用一个关键类ConfigurationClassPostProcessor,他会解析@Configuration标记的类,及类中@Bean方法,涉及到full和lite模式,由于篇幅有限,将在下一篇讲解。文章来源地址https://www.toymoban.com/news/detail-561288.html
到了这里,关于Spring IOC - Bean的扫描的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!