Spring IOC - Bean的扫描

news/2024/11/29 8:00:32/

        @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.DefaultEventListenerFactorythis.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 {// 如果读取的类的注解在排除注解过滤规则中,返回falsefor (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);}}// 如果读取的类的注解既不在排除规则,也不在包含规则中,则返回falsereturn 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的子类。

        这里面会调用一个关键类ConfigurationClassPostProcessor,他会解析@Configuration标记的类,及类中@Bean方法,涉及到full和lite模式,由于篇幅有限,将在下一篇讲解。


http://www.ppmy.cn/news/869202.html

相关文章

信用卡号

一个信用卡号必须是13到16位的整数。它的开头必须是: 4,指Visa卡 5,指Master卡 37,指American Express卡 6,指Discover卡1)从右到左对每个偶数位字翻倍。如果对某个数字翻倍之后的结果是一个两位数,那么就将…

01、识别信用卡卡号

import numpy as np import cv2 as cv import matplotlib.pyplot as plt import myutils #一、绘制图像 def img_show(img_name,img):cv.imshow(img_name,img)cv.waitKey(0)cv.destroyAllWindows()#二、模板操作 #1、读取模板图像 template cv.imread(./images/ocr_a_referenc…

国际信用卡

国际信用卡是一种银行联合国际信用卡组织签发给那些资信良好的人士并可以在全球范围内进行透支消费的卡片,同时该卡也被用于在国际网络上确认用户的身份。 国际发卡组织是一个由全世界银行参与的非营利的国际性组织,会员由银行等金融机构组成&#xff0…

美国visa虚拟信用卡

转载自[url]http://xinlanzero.iteye.com/blog/1141845[/url] 1 http://www.simon.com虚 拟卡20$起的22$.美国等借记卡就可以购买.带名字地址等等资料.激活PP.EBAY都是即时的. 2 http://www-card.com 以 色列网站.虚拟卡特便宜.20$只需要22$.支持所有国家的卡. 3激活美国PP的…

验证6种信用卡卡号的代码

验证6种信用卡卡号的代码 作者:BEUS 日期:2006-08-25 字体大小: 小 中 大 可以验证的信用卡种类有: V - Visa M - MasterCard A - American Express D - Diners ClubDiscover - DiscoverJCB - JCB 以下为ASP代码: Function ValidateCreditCard(ByRef pS…

信用卡卡号验证算法

How to check digits in credit card validation 文章来源:http://platon.sk/article.php?38 Author: Hal Stiles | Section: Dev Resources | Date: 2005-06-25 This document outlines procedures and algorithms for Verifying the accuracy and validity of …

VISA操作

VISA操作 VISA操作表 操作表: 1、VISA资源模板: viClose(vi):关闭特定的对话通道。 viGetAttribute(vi,attribute,attrState):获取资源属性状态值。 viSetAtt…

信用卡卡号有效验证

/*** 信用卡有效性校验* param creditCardNo* private*/ let _checkCardNoValidity (creditCardNo) > {let cardNoArray new Array();for (let i creditCardNo.length - 1; i > 0; i--) {cardNoArray.push(creditCardNo.substr(i, 1));}let oddSum 0;let evenSum 0;…