当前位置: 首页 > news >正文

Spring-包扫描

 一、doScan包扫描

V1.0 doScan
流程图

包扫描

1、根据配置的包扫名路径构建出Beandefinition

2、循环构建出的BeanDefinition集合

3、获取ScopeMetadata元数据读取器

4、对beandefinition进行赋值

5、返回所有的beandefinition

	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {//获取路径下的所有BeanDefinition//具体看代码V1.1Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {//设置bean的作用范围 默认 singleton ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());//对beanDefinition设置bean的名字String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);//对beanDefinition设置默认值if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 解析@Lazy、@Primary、@DependsOn、@Role、@Description//并设置给当前beanDefinitionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查Spring容器中是否已经存在该beanName//见的代码V1.7if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册,将beanName作为key beanDefinition作为value存入beanDefinitionMap中registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
V1.1 isCandidateComponent

判断当前类是否需要当作bean进行处理

	public Set<BeanDefinition> findCandidateComponents(String basePackage) {//componentsIndex 对应META-INF下的spring.components文件,里面的内容全包名类名作为key,注解名作为value//加入该文件后,就会走这边的逻辑,只扫描配置好的类,可以减少扫描时间if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {return scanCandidateComponents(basePackage);}}
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {Set<BeanDefinition> candidates = new LinkedHashSet<>();try {// 获取basePackage下所有的文件资源  CLASSPATH_ALL_URL_PREFIX = "classpath*:"// DEFAULT_RESOURCE_PATTERN = "**/*.class";String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;//获取包路径下的所有的.class文件Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();//遍历每一个文件for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {//获取 元数据读取器,可以读取类名、类中的方法、类上的注解等元素据MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// excludeFilters、includeFilters判断// 代码V1.2if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断//创建BeanDefinition,并将className赋值给BeanClassScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setSource(resource);if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}else {if (traceEnabled) {logger.trace("Ignored because not matching any filter: " + resource);}}}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);}}else {if (traceEnabled) {logger.trace("Ignored because not readable: " + resource);}}}}catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);}return candidates;}
V1.2 isCandidateComponent

	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {for (TypeFilter tf : this.excludeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {return false;}}// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional//spring启动的时候会自动将@Component注解加入includeFilters中// 具体看代码 V1.3for (TypeFilter tf : this.includeFilters) {if (tf.match(metadataReader, getMetadataReaderFactory())) {//当类满足Component注解或其他设定为需要加载Bean的注解// 仍需要判断是否满足条件@Conditional注解中包含的条件return isConditionMatch(metadataReader);}}return false;}

V1.3 registerDefaultFilters

spring在启动的时候就会往includeFilters中加入component注解

protected void registerDefaultFilters() {// 注册@Component对应的AnnotationTypeFilterthis.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.}try {this.includeFilters.add(new AnnotationTypeFilter(((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}}
V1.4 ScannedGenericBeanDefinition

对扫描到的BeanDefinition进行赋值,但是此时只是将className赋值到BeanDefinition中,因为还没有创建该类

	public ScannedGenericBeanDefinition(MetadataReader metadataReader) {Assert.notNull(metadataReader, "MetadataReader must not be null");this.metadata = metadataReader.getAnnotationMetadata();// 这里只是把className设置到BeanDefinition中setBeanClassName(this.metadata.getClassName());setResource(metadataReader.getResource());}↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓@Overridepublic void setBeanClassName(@Nullable String beanClassName) {this.beanClass = beanClassName;}
V1.5 isCandidateComponent

二次判断类是否可独立实例化对象,内部类或者接口,抽象类都会对应生成一个.class文件,但是这些文件部分是不能够实例化的,不可以生成bean,所以在生成BeanDefinition之前需要进行过滤判断

	/***确定给定的bean定义是否符合候选条件。*默认实现检查类是否不是接口并且不依赖于封闭类且可以在子类中重写*(即* 1、是否是顶级类或者静态内部类等独立类,* 2、不是接口并且不是抽象类,* 3、如果是抽象类,含有至少一个方法实现Lookup注解)**/protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {AnnotationMetadata metadata = beanDefinition.getMetadata();return (metadata.isIndependent() && (metadata.isConcrete() ||(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));}↓↓↓↓↓↓↓↓↓↓default boolean isConcrete() {//判断不是接口并且不是抽象类return !(isInterface() || isAbstract());}

V1.6 generateBeanName

获取bean的名字

	@Overridepublic String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {if (definition instanceof AnnotatedBeanDefinition) {// 获取注解所指定的beanNameString beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);if (StringUtils.hasText(beanName)) {// Explicit bean name found.return beanName;}}// 如果注解中没有指定bean的名称,则采用默认名称return buildDefaultBeanName(definition, registry);}↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓protected String buildDefaultBeanName(BeanDefinition definition) {String beanClassName = definition.getBeanClassName();Assert.state(beanClassName != null, "No bean class name set");//获取sortName//如果beanClassName长度小于0返回空//如果beanClassName的第一个第二个字母都是大写,则返回beanClassName//否则将beanClassName的第一个字母设为小写后,返回String shortClassName = ClassUtils.getShortName(beanClassName);return Introspector.decapitalize(shortClassName);}

V1.7 checkCandidate

	protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {//当前bean的名字并没有被注册过,返回trueif (!this.registry.containsBeanDefinition(beanName)) {return true;}BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();if (originatingDef != null) {existingDef = originatingDef;}// 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。if (isCompatible(beanDefinition, existingDef)) {return false;}//大多数情况下,名字重复会直接抛出异常throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");}↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓protected boolean isCompatible(BeanDefinition newDefinition, BeanDefinition existingDefinition) {//判断beanDefinition是否是统一类型,如果是,代表多次扫描统一相同的bean,而非不同的bean使用相同的名称//可兼容,但是跳过本次处理return (!(existingDefinition instanceof ScannedGenericBeanDefinition) ||  // explicitly registered overriding bean(newDefinition.getSource() != null && newDefinition.getSource().equals(existingDefinition.getSource())) ||  // scanned same file twicenewDefinition.equals(existingDefinition));  // scanned equivalent class twice}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Go sdk下载和配置环境变量
  • 60、PHP 实现 单词查找树算法
  • M.2接口
  • STM32 GPIO 模块
  • VsCode无法远程调试
  • 如何理解供应链控制塔?详解供应链控制塔类型与架构!
  • MiniCPM-V: A GPT-4V Level MLLM on Your Phone 手机上的 GPT-4V 级多模态大模型
  • 哪个牌子手持洗拖一机好?多款热门家用洗地机推荐
  • Java | Leetcode Java题解之第324题摆动排序II
  • Mac安装nvm以及配置环境变量
  • Docker高级应用讲解
  • ForkJoin框架的解析
  • Spring boot框架指南
  • 04--Docker
  • 【c++】基础知识——快速入门c++
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 《网管员必读——网络组建》(第2版)电子课件下载
  • 【刷算法】求1+2+3+...+n
  • 07.Android之多媒体问题
  • CentOS 7 防火墙操作
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • JAVA并发编程--1.基础概念
  • jQuery(一)
  • Otto开发初探——微服务依赖管理新利器
  • Python打包系统简单入门
  • text-decoration与color属性
  • Vue 2.3、2.4 知识点小结
  • 创建一个Struts2项目maven 方式
  • 浮现式设计
  • 诡异!React stopPropagation失灵
  • 如何利用MongoDB打造TOP榜小程序
  • 如何实现 font-size 的响应式
  • 三栏布局总结
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • # linux 中使用 visudo 命令,怎么保存退出?
  • ## 1.3.Git命令
  • #if #elif #endif
  • #ubuntu# #git# repository git config --global --add safe.directory
  • ( )的作用是将计算机中的信息传送给用户,计算机应用基础 吉大15春学期《计算机应用基础》在线作业二及答案...
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (2)从源码角度聊聊Jetpack Navigator的工作流程
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (备忘)Java Map 遍历
  • (力扣)循环队列的实现与详解(C语言)
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (一一四)第九章编程练习
  • (转)VC++中ondraw在什么时候调用的
  • (转)编辑寄语:因为爱心,所以美丽
  • (转载)Linux 多线程条件变量同步
  • .gitignore
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes