温州中豪网站建设推广宁波企业网站优化报价

web/2025/9/25 17:22:08/文章来源:
温州中豪网站建设推广,宁波企业网站优化报价,仓储设备东莞网站建设,前端网页设计师简介 前面介绍了scanner可以扫描某个包路径下的所有bean#xff0c;我们最常用的也是通过ComponentScan指定包路径去扫描#xff0c;在SpringBoot中也是如此#xff0c;本文将介绍spring扫描的逻辑 BeanDefinitionRegistryPostProcessor 知道了ComponentScan的作用#…简介 前面介绍了scanner可以扫描某个包路径下的所有bean我们最常用的也是通过ComponentScan指定包路径去扫描在SpringBoot中也是如此本文将介绍spring扫描的逻辑 BeanDefinitionRegistryPostProcessor 知道了ComponentScan的作用那么spring什么时候开始解析ComponentScan去扫描bean呢 这个时候就要知道spring的其中一个生命周期 BeanDefinitionRegistryPostProcessor public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException; }该生命周期可以说是最早的一个还在BeanFactoryPostProcessor#postProcessBeanFactory之前执行 从接口提供的方法就很明确可以自己去注册一些bean 那么在该接口实现类里面就可以将最开始注册的AppConfig类拿出来确定有ComponentScan注解就可以拿到路径去扫描最终注册bean ConfigurationClassPostProcessor ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 在spring中通过该类进行配置类的解析并且注册bean只不过在spring中标名是一个配置类的注解多种多样 ComponentScan 也只是其中一个 本文主要讲 ComponentScan 其它配置类后面讲 注册 源码链路 AnnotationConfigApplicationContext(Class?… componentClasses) # 进入this() AnnotationConfigApplicationContext() AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) AnnotationConfigUtils#registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Nullable Object source) 可以看到这么一行 注册ConfigurationClassPostProcessor if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)); }获取注册的ConfigurationClassPostProcessor 进入refresh方案spring最重要的一个方法整个生命周期都在这 AnnotationConfigApplicationContext(Class?… componentClasses) # 进入this()AbstractApplicationContext#refresh()AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory); 处理 BeanFactory的后置处理器PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) 会看到如下代码 // 获取BeanDefinitionRegistryPostProcessor一般来说就只有一个 ConfigurationClassPostProcessor String[] postProcessorNames beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);} } // 排个序 sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 执行 BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear();// 扫描完之后还有可能生成BeanFactoryPostProcessor postProcessorNames beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) {// 过滤之前执行过的BeanFactoryPostProcessorif (!processedBeans.contains(ppName) beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);} } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear();以上就是获取 ConfigurationClassPostProcessor 到执行它的 postProcessBeanDefinitionRegistry方法的 逻辑通过beanFactory.getBeanNamesForType 获取 BeanDefinitionRegistryPostProcessor 将获取到的BeanDefinitionRegistryPostProcessor 排个序通过Order注解或者javax.annotation.Priority注解确定排序 遍历执行postProcessBeanDefinitionRegistry方法 解析 ComponentScan 那么在ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry又是怎么解析ComponentScan注册bean呢 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistryConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry) 在这里会有一个检查判断是不是配置类 ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) 那么什么是配置类呢 public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {// getFactoryMethodName表示是Bean方式注入的bean这种不作为配置类String className beanDef.getBeanClassName();// 注解信息通过MetadataReader获取ASM技术 并没有加载类AnnotationMetadata metadata;// 如果AnnotatedBeanDefinition则直接取AnnotationMetadataif (beanDef instanceof AnnotatedBeanDefinition className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {metadata ((AnnotatedBeanDefinition) beanDef).getMetadata();}// 如果是AbstractBeanDefinition则解析beanClass得到AnnotationMetadataelse if (beanDef instanceof AbstractBeanDefinition ((AbstractBeanDefinition) beanDef).hasBeanClass()) {metadata AnnotationMetadata.introspect(beanClass);}else {// ASM技术这里其实也是spring提供的一个工具我们也可以使用后续文章介绍MetadataReader metadataReader metadataReaderFactory.getMetadataReader(className);metadata metadataReader.getAnnotationMetadata();}MapString, Object config metadata.getAnnotationAttributes(Configuration.class.getName());// 存在Configuration并且proxyBeanMethods不为false就是配置类 配置类型为Fullif (config ! null !Boolean.FALSE.equals(config.get(proxyBeanMethods))) {// 设置属性configurationClass表示是配置类beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}// 存在Configuration并且proxyBeanMethods为false时也是配置类配置类型为lite// 不存在Configuration存在Component、ComponentScan、Import、ImportResource中的某一个也是配置类 配置类型为lite// 有Bean标注的方法也是配置类else if (config ! null || isConfigurationCandidate(metadata)) {beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);}else {return false;}// Its a full or lite configuration candidate... Lets determine the order value, if any.Integer order getOrder(metadata);if (order ! null) {// 配置类也可以排序使用 Order注解beanDef.setAttribute(ORDER_ATTRIBUTE, order);}return true;}private static final SetString candidateIndicators new HashSet(8);static {candidateIndicators.add(Component.class.getName());candidateIndicators.add(ComponentScan.class.getName());candidateIndicators.add(Import.class.getName());candidateIndicators.add(ImportResource.class.getName());}public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {// 接口不管if (metadata.isInterface()) {return false;}// 只要存在Component、ComponentScan、Import、ImportResource四个中的一个就是lite配置类for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, lets look for Bean methods...// 只要存在Bean注解了的方法就是lite配置类return hasBeanMethods(metadata); }根据上面的代码逻辑分析拥有Configuration Component、ComponentScan、Import、ImportResource 或者方法有Bean注解那么就是一个配置类继续后面代码分析 parser.parse(candidates); candidates 就是找出的所有配置累会进入 ConfigurationClassParser#parse(AnnotationMetadata metadata, String beanName)ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass, Predicate filter)ConfigurationClassParser#doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate filter) 其它配置类先不看那么会看到会看到如下代码 // 查看是否有ComponentScan注解 SetAnnotationAttributes componentScans AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with ComponentScan - perform the scan immediatelySetBeanDefinitionHolder scannedBeanDefinitions this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand null) {bdCand holder.getBeanDefinition();}// 解析出来还有配置类继续解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}} }查看该Bean的有没有ComponentScans或者ComponentScan注解如果有那么使用ComponentScanAnnotationParser解析 public SetBeanDefinitionHolder parse(AnnotationAttributes componentScan, final String declaringClass) {ClassPathBeanDefinitionScanner scanner new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean(useDefaultFilters), this.environment, this.resourceLoader);// bean的名字生成器默认是首字母小写的类名可以自己定义其它规则比如类的全限定名Class? extends BeanNameGenerator generatorClass componentScan.getClass(nameGenerator);boolean useInheritedGenerator (BeanNameGenerator.class generatorClass);// 默认为AnnotationBeanNameGeneratorscanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :BeanUtils.instantiateClass(generatorClass));// 默认就是扫描包下面的class文件scanner.setResourcePattern(componentScan.getString(resourcePattern));for (AnnotationAttributes filter : componentScan.getAnnotationArray(includeFilters)) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addIncludeFilter(typeFilter);}}for (AnnotationAttributes filter : componentScan.getAnnotationArray(excludeFilters)) {for (TypeFilter typeFilter : typeFiltersFor(filter)) {scanner.addExcludeFilter(typeFilter);}}boolean lazyInit componentScan.getBoolean(lazyInit);if (lazyInit) {scanner.getBeanDefinitionDefaults().setLazyInit(true);}SetString basePackages new LinkedHashSet();String[] basePackagesArray componentScan.getStringArray(basePackages);for (String pkg : basePackagesArray) {String[] tokenized StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);Collections.addAll(basePackages, tokenized);}for (Class? clazz : componentScan.getClassArray(basePackageClasses)) {basePackages.add(ClassUtils.getPackageName(clazz));}if (basePackages.isEmpty()) {basePackages.add(ClassUtils.getPackageName(declaringClass));}scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {Overrideprotected boolean matchClassName(String className) {// 排除掉自己return declaringClass.equals(className);}});// 开始扫描注册beanreturn scanner.doScan(StringUtils.toStringArray(basePackages));}以上就是如何解析ComponentScan的逻辑解析完后开始扫描进行BeanDefinition注册注意是BeanDefinition注册还不是实例化bean ClassPathBeanDefinitionScanner#doScanClassPathBeanDefinitionScanner#registerBeanDefinitionBeanDefinitionReaderUtils#registerBeanDefinitionDefaultListableBeanFactory#registerBeanDefinition 最终存放在 beanDefinitionMap beanDefinitionNames 记住这两个属性特别重要 private final MapString, BeanDefinition beanDefinitionMap new ConcurrentHashMap(256); private volatile List beanDefinitionNames new ArrayList(256); 以上就是通过ComponentScan注解注册Bean的逻辑了其它配置类以及实例化bean的逻辑后面文章在介绍 欢迎关注学习不迷路

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/81736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

子网站 两微一端的建设方案南昌地宝网二手车出售信息

目录 一、使用正则表达式进行基本字符匹配 1.使用regexp关键字 2.使用正则表达式 . 二、进行OR匹配 1.为搜索两个串之一,使用 | 2.匹配几个字符之一[] 3.匹配范围 4.匹配特殊字符 过滤数据允许使用匹配、比较、通配符操作来寻找数据,但是随…

如何建立一个带论坛的网站怎样提升企业网站的访问

将表格二次封装,方便以后开发中的复用。每次只需调用表格组件后,在父组件中往子组件标签上写入dataSource(表格数据)和columns(表格列标题)即可。 此案例中最后一列是删除按钮,动态生成&#xf…

宾县建设局网站上海外贸上市公司有哪些

1024程序员节当当网计算机图书每满100减50!满200减100!满300-150!机械工业出版社华章公司联合当当网特意为【DotNET技术圈】用户申请了一批可与满减叠加使用的“满200减30”的图书优惠码,优惠码使用后相当于:400减230 …

网址导航网站如何做毕节地seo

电力通信规约-104实战 概述 104规约在广泛应用于电力系统远动过程中,主要用来进行数据传输和转发,本文将结合实际开发实例来讲解104规约的真实使用情况。 实例讲解 因为个人技术栈是Java,所以本篇将采用Java实例来进行讲解。首先我们搭建一…

网站建设优化服务咨询wordpress 数据调用api接口

单片机实现可调时钟设计 在许多嵌入式系统中,时钟功能是非常重要的,尤其是在需要实时显示或调节时间的应用中。例如,我们可以设计一个可调时钟,用户可以通过按键或者外部信号调节时钟的时间(例如调节时、分、秒&#…

台州网站建设方案托管wordpress添加搜索关键字

fastadmin表格右侧操作栏增加审核成功和审核失败按钮,点击提交ajax到后端 效果如下 js {field: operate, title: __(Operate), table: table, events

免费网页代理ip地址网站wordpress模板网站模板

文章目录编辑查询/替换导航调试重构其他自定义快捷键技巧编辑 快捷键功能说明Ctrl1快速修复(最经典的快捷键,就不用多说了,可以解决很多问题,比如import类、try catch包围等)CtrlShiftF格式化代码。团队有统一的代码格式&#xf…

一般网站维护要多久陕西 建设工程有限公司网站

一.项目介绍 前台功能:用户进入系统可以实现首页,系统公告,个人中心,后台管理等功能进行操作 后台由管理员,实习单位,教师和学生,主要功能包括首页,个人中心,班级管理&am…

宿迁网站建设联系电话网站建设项目外包网站

假设目标是去掉页码为4的那一页 点击第4页中的任意空行,之后点击“页面布局”选项卡中的“分隔符”,之后选择“连续” 双击页脚部分,点击第4页页眉的任意位置,之后取消掉“链接到前一条页眉” 之后第4页的页脚,第5页的…

用家用路由器ip做网站怎么判断一个网站做的好

1、应用构建及提示词 在 Dify 中,一个“应用”是指基于 GPT 等大型语言模型构建的实际场景应用。通过创建应用,您可以将智能 AI 技术应用于特定的需求。它既包含了开发 AI 应用的工程范式,也包含了具体的交付物。 简而言之,一个应…

dlink nas做网站wordpress 取消做这

目录 一、引入特征缩放:二、特征缩放介绍:三、如何实现特征缩放:1.分别除特征中最大值缩放到0—1:2.均值归一化缩放到-1—1:3.Z-Score归一化: 四、特征缩放合理范围: 一、引入特征缩放&#xff…

福州网站制作托管维护html代码大全免费

Java 8之前和之后的几个示例程序的快速指南。Java8 Concepts进一步简化了代码,并且对核心逻辑(而不是语法)产生了深远影响。 1.简介 在本教程中,我们将学习如何使用Java 8编写程序 lambda和Stream概念以及示例。 许多开发人员认…

合肥网站建设q479185700強公司 网站建设

有点离谱,笨笨的脑子才犯的错误 首先发现问题:转移项目的时候 直接复制粘贴libs文件夹下的jar包到新项目,在build.gradle文件下 使用语句并应用也没反应(jar包没有出现箭头且代码报错,找不到) implementa…

陕西高端品牌网站建设价格wordpress模板响应式

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

网站模板预览太平洋汽车网址大全

基于springboot实现企业客户管理系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个企业客户管理系统,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述企…

公司网站怎么修改内容网站建设实现后台数据导出excel

背景:知乎上常有非常精彩的回答/文章,必须要点赞收藏,日后回想起该回答/文章时翻看自己的动态和收藏夹却怎么也找不到,即使之前保存了链接网络不好也打不开了(。所以我一般碰到好的回答/文章都会想办法保存它的离线版本…

网站界面技术方案韩漫网站建设

在任何系统的UI框架中,动画原理都是类似的,即:在一段时间内,快速地多次改变UI外观;由于人眼会产生视觉暂留,所以最终看到的就是一个“连续”的动画。 Flutter中对动画进行了抽象,主要涉及 Anim…

企业微信下载官方网站discover wordpress

力扣题-12.12 [力扣刷题攻略] Re:从零开始的力扣刷题生活 力扣题1:539. 最小时间差 解题思想:将字符串的时间形式换成数字形式的时间,然后计算差值即可,最重要的是最小的值加上一天的时间加入到数组最后&#xff08…

江苏省住房和城乡建设厅网站首页抖音珠宝代运营

问题分析: SpringMVC 是一种基于 Java 语言开发,实现了 Web MVC 设计模式,请求驱动类型 的轻量级 Web 框架。 SpringMVC采用了 MVC 架构模式的思想,通过把 Model,View,Controller 分离,将 Web 层…