Spring源码十:BeanPostProcess

上一篇Spring源码九:BeanFactoryPostProcessor,我们看到ApplicationContext容器通过refresh方法中的postProcessBeanFactory方法和BeanFactoryPostProcessor类提供预留扩展点,他可以在Spring容器的层面对BeanFactroy或其他属性进行修改,所以我们经常说BeanFactoryPost Processor是Spring容器层面的一个扩展点。

但是,我们除了在容器层面外我们有没有粒度更小一点的扩展处理呢?比我们能否直接修改我们的Bean呢?

接下来咱们进入Spring给我们预留另外一个比较重要的扩展点,也就是我们bean的后置处理器BeanPost Processor。

BeanPostProcessor初探

在Spring框架中,BeanPostProcessor是一个核心接口,它允许我们在Spring容器实例化、配置和初始化Bean之前或之后进行一些额外的处理。通过实现这个接口,我们可以在Bean的生命周期的特定点插入自定义逻辑,以增强或修改Bean的行为。本文将深入探讨BeanPostProcessor的定义、用途、使用实例、注册方式以及其在Spring应用中的重要性和应用场景。

1. BeanPostProcessor接口定义

BeanPostProcessor接口定义了两个主要方法:

public interface BeanPostProcessor {Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
  • postProcessBeforeInitialization:在Bean初始化之前被调用。这通常指的是在Bean的init-method或者实现了InitializingBean接口的afterPropertiesSet方法之前。
  • postProcessAfterInitialization:在Bean初始化之后被调用。

这些方法的主要作用是允许开发者在Bean的初始化过程中进行定制化处理,这种处理可以是对Bean属性的修改、添加日志、检查标记接口或对Bean进行代理等操作。

2. BeanPostProcessor的目的与应用

BeanPostProcessor的主要目的是通过改进Bean的初始化过程,提高Spring容器中Bean的管理和使用效率。具体应用场景包括:

  • 属性修改:在Bean初始化之前或之后,对Bean的某些属性进行修改,以满足特定需求。
  • 日志记录:在Bean的初始化过程中,记录日志信息,以便于调试和监控。
  • 标记接口检查:检查Bean是否实现了特定的标记接口,并根据检查结果进行相应处理。
  • 代理增强:对Bean进行代理,以添加额外的功能,例如AOP(面向切面编程)中的增强功能。
3. BeanPostProcessor使用实例

下面是一个简单的使用实例,展示了如何在Bean初始化前后添加日志:

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Before Initialization: " + beanName);return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("After Initialization: " + beanName);return bean;}
}

在这个例子中,我们实现了BeanPostProcessor接口,并在postProcessBeforeInitializationpostProcessAfterInitialization方法中分别添加了日志输出。这使得每当一个Bean在初始化之前或之后,这两个方法都会被调用,并输出相应的日志信息。

4. BeanPostProcessor的注册

要使BeanPostProcessor生效,必须将其注册到Spring容器中。注册方式有多种,包括注解配置、XML配置和Java配置。

  • 注解配置:如果使用@Component注解,Spring会自动检测并注册BeanPostProcessor:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {// 方法实现如上
}
  • XML配置:在XML文件中显式声明BeanPostProcessor:
<bean class="com.example.CustomBeanPostProcessor" />
  • Java配置:通过@Bean注解注册BeanPostProcessor:
@Configuration
public class AppConfig {@Beanpublic BeanPostProcessor customBeanPostProcessor() {return new CustomBeanPostProcessor();}
}
5. BeanPostProcessor的工程化应用

BeanPostProcessor在工程化应用中具有重要意义。通过在Bean的生命周期中插入定制化逻辑,开发者可以实现许多高级功能,例如:

  • AOP(面向切面编程):通过代理技术,在Bean的方法调用前后添加额外逻辑,例如日志记录、事务管理、安全检查等。
  • 依赖注入的增强:在Bean初始化前后对其依赖进行进一步的配置和优化,例如动态注入特定依赖。
  • Bean管理:在Bean的整个生命周期中,进行统一的管理和监控,例如资源的初始化和释放、性能监控等。
6. 深入理解BeanPostProcessor的工作机制

为了更好地理解BeanPostProcessor的工作机制,我们需要了解Spring容器的初始化过程。Spring容器在启动时,会进行以下几个主要步骤:

  1. 实例化Bean:Spring容器根据配置文件或注解,实例化所有的Bean。
  2. 属性注入:为每个Bean注入其依赖的属性,这些属性可以是其他Bean、基本类型、集合等。
  3. 调用BeanPostProcessor:在Bean初始化前后,调用所有注册的BeanPostProcessor的方法。
  4. 调用初始化方法:如果Bean实现了InitializingBean接口,调用其afterPropertiesSet方法;如果配置了init-method,则调用该方法。
  5. Bean就绪:Bean已经准备好,可以被应用程序使用。

在这个过程中,BeanPostProcessor的两个方法分别在第3步和第4步之间被调用,允许开发者在Bean的生命周期的关键节点进行干预和自定义操作。

7. 实践中的BeanPostProcessor应用

在实际开发中,BeanPostProcessor的应用非常广泛,下面列举几个常见的使用场景:

  • 自定义初始化逻辑:通过在postProcessBeforeInitialization方法中添加逻辑,可以在Bean初始化之前执行一些自定义操作。例如,为Bean的某些属性设置默认值,或进行特定的初始化操作。
  • 动态代理:在postProcessAfterInitialization方法中,可以使用JDK动态代理或CGLIB代理,为Bean添加AOP增强。例如,为某些方法添加事务管理、日志记录或安全检查。
  • 注解处理:通过在Bean初始化前后扫描特定注解,可以实现注解驱动的配置。例如,自定义注解用于标记需要进行特定处理的Bean,并在BeanPostProcessor中实现相应的逻辑。
8. BeanPostProcessor与其他Spring机制的结合

BeanPostProcessor常常与Spring的其他机制结合使用,以实现更复杂和强大的功能。例如:

  • BeanFactoryPostProcessor结合BeanFactoryPostProcessor允许在Bean定义加载后、Bean实例化前进行配置修改。通过结合使用这两个接口,可以在Bean定义和实例化的不同阶段进行干预,提供更细粒度的控制。
  • ApplicationContextAware结合:实现ApplicationContextAware接口的Bean可以获取到ApplicationContext实例,通过在BeanPostProcessor中对这些Bean进行处理,可以实现对整个应用上下文的操作。
  • @PostConstruct@PreDestroy结合:在Bean的生命周期中,通过BeanPostProcessor和这两个注解,可以实现复杂的初始化和销毁逻辑。例如,在Bean初始化后,调用特定方法进行资源的分配或初始化。
9. 高级使用技巧

在高级使用场景中,BeanPostProcessor可以用于实现更复杂的功能,例如:

  • 多层次代理:通过在postProcessAfterInitialization方法中多次对Bean进行代理,可以实现多层次的功能增强。例如,先添加事务管理,再添加日志记录。
  • 条件处理:在BeanPostProcessor中,可以根据特定条件对Bean进行不同的处理。例如,根据Bean的类型或注解,选择性地进行某些操作。
  • 性能优化:通过在Bean初始化前后进行性能监控,可以识别出性能瓶颈,并采取相应的优化措施。例如,记录Bean初始化的时间,找出耗时较长的操作。

BeanPostProcessor源码跟踪

refresh方法中的registerBeanPostProcessors

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing. 1、初始化上下文信息,替换占位符、必要参数的校验prepareRefresh();// Tell the subclass to refresh the internal bean factory. 2、解析类Xml、初始化BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 这一步主要是对初级容器的基础设计// Prepare the bean factory for use in this context. 	3、准备BeanFactory内容:prepareBeanFactory(beanFactory); // 对beanFactory容器的功能的扩展:try {// Allows post-processing of the bean factory in context subclasses. 4、扩展点加一:空实现,主要用于处理特殊Bean的后置处理器postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context. 	5、spring bean容器的后置处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation. 	6、注册bean的后置处理器//!!!!!!!!!!!!  这里 这里 今天看这里  !!!!!!!!!!!//registerBeanPostProcessors(beanFactory);//!!!!!!!!!!!!  这里 这里 今天看这里  !!!!!!!!!!!//// Initialize message source for this context.	7、初始化消息源initMessageSource();// Initialize event multicaster for this context.	8、初始化事件广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses. 9、扩展点加一:空实现;主要是在实例化之前做些bean初始化扩展onRefresh();// Check for listener beans and register them.	10、初始化监听器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.	11、实例化:非兰加载BeanfinishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.	 12、发布相应的事件通知finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

/*** Instantiate and register all BeanPostProcessor beans,* respecting explicit order if given.* <p>Must be called before any instantiation of application beans.*/protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}

registerBeanPostProcessors详解

	/**** @param beanFactory* @param applicationContext*/public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {// 1、获取所有实现BeanPostProcessor接口的类String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);// Register BeanPostProcessorChecker that logs an info message when a bean is created during BeanPostProcessor instantiation, i.e. when a bean is not eligible for getting processed by all BeanPostProcessors.// 记录下BeanPostProcessor的目标计数// +1是因为在此方法的最后会添加一个BeanPostProcessorChecker的类int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;// 2、添加BeanPostProcessorChecker(主要用于记录信息)到beanFactory中beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// Separate between BeanPostProcessors that implement PriorityOrdered,// Ordered, and the rest.// 3、初始化根据BeanPostProcessor是否实现Priority、Order接口进行分类,初始化各种类型的集合,分类装这些对象List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();// Spring自己内部的Bean后置处理器List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();// 4、遍历步骤一中所有后置处理器的名称for (String ppName : postProcessorNames) {// 实现PriorityOrdered类型的Beanif (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);//  实现PriorityOrdered同时也实现类MergedBeanDefinitionPostProcessor接口,//  那么对应的bean实例添加到internalPostProcessors中,与实例化相关注解如@Autowired @Bean等关系密切,需要注意if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}// 实现Ordered类型的Beanelse if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, register the BeanPostProcessors that implement PriorityOrdered.// 5、将实现类PriorityOrder接口类型的bean先注入到BeanFactory中sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// Next, register the BeanPostProcessors that implement Ordered.// 6、将实现类Order接口类型的bean先注入到BeanFactory中List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}// 6、将实现类Order接口类型的bean先注入到BeanFactory中sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors);// Now, register all regular BeanPostProcessors.List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}// 7.将无序普通的bean后处理器,注册到容器beanFactory中registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// Finally, re-register all internal BeanPostProcessors.// 8、最后,将Spring容器内部的BeanPostProcessor注册到Bean后置处理器中sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);// Re-register post-processor for detecting inner beans as ApplicationListeners,// moving it to the end of the processor chain (for picking up proxies etc).beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));}

代码解析与重点总结
1. 获取所有实现BeanPostProcessor接口的类
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

此步骤从BeanFactory中获取所有实现了BeanPostProcessor接口的Bean名称。这是为了后续将这些Bean按照不同的规则进行处理和注册。

2. 添加BeanPostProcessorChecker
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

BeanPostProcessorChecker的作用是记录信息,当在BeanPostProcessor实例化过程中创建一个Bean时,它会输出一条信息日志。这一步是为了确保在BeanPostProcessor注册过程中Bean创建的可追溯性。

3. 根据类型分类BeanPostProcessor
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);} else {nonOrderedPostProcessorNames.add(ppName);}
}

在这一步,所有的BeanPostProcessor根据是否实现了PriorityOrdered、Ordered接口进行分类,分别放入不同的列表中。这是为了后续按照优先级进行注册。

4. 按优先级顺序注册BeanPostProcessor
// 注册实现PriorityOrdered接口的BeanPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// 注册实现Ordered接口的BeanPostProcessor
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);// 注册普通的BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

按照实现PriorityOrdered、Ordered接口以及普通BeanPostProcessor的顺序,分别注册这些BeanPostProcessor。这确保了不同优先级的BeanPostProcessor按正确的顺序执行。

5. 注册内部BeanPostProcessor
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

将Spring内部使用的BeanPostProcessor(实现MergedBeanDefinitionPostProcessor接口的)单独处理并注册。这些内部BeanPostProcessor与Bean的实例化相关注解(如@Autowired、@Bean)关系密切,需要特别注意。

6. 添加ApplicationListenerDetector
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

最后,添加一个ApplicationListenerDetector,用于检测内部Bean是否作为ApplicationListeners(应用监听器),并将其移动到处理链的末尾,以便捕获代理等操作。

小结

BeanPostProcessor是Spring框架提供的一个强大工具,它允许我们开发者在Bean的生命周期中的特定点进行自定义操作。通过实现BeanPostProcessor接口,开发者可以插入自己的逻辑,以增强或修改Bean的行为。这个接口在AOP、依赖注入和Bean管理等方面都有着广泛的应用。正确地使用BeanPostProcessor可以极大地提高Spring应用的灵活性和可扩展性。

通过本文的详细介绍,相信大家对BeanPostProcessor有了更深入的理解。在实际开发中,合理地应用BeanPostProcessor,可以帮助我们更好地控制和管理Bean的生命周期,实现复杂的业务需求。

整体总结

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

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

相关文章

科技赋能智慧应急:“数字孪生+无人机”在防汛救灾中的应用

近期&#xff0c;全国多地暴雨持续&#xff0c;“麻辣王子工厂停工”“水上派出所成水上的派出所了”等相关词条冲上热搜&#xff0c;让人们看到了全国各地城市内涝、洪涝带来的严重灾情。暴雨带来的影响可见一斑&#xff0c;潜在的洪水、泥石流、山体滑坡等地质灾害更应提高警…

MYSQL的简易安装

先下载好安装包 官网&#xff1a;https://www.mysql.com 双击运行进入界面 打开之后将左侧的产品移到右侧 点击使用的产品设置路径 之后一直下一步即可 选择主机类型 同时要记住端口号 设置密码 设置系统服务列表中的服务名称 之后一直下一步就可以了 安装完成记得配置环…

解决前端登录成功之后,往后端发请求携带cookie问题

项目背景&#xff1a; 今天在做伙伴匹配系统&#xff1a; 我现在实现的功能是&#xff1a; 在我登录成功之后&#xff0c;就进入了主页&#xff08;默认页&#xff09;&#xff0c;在我访问用户页的时候产生的问题 首先说明一下这个Cookie的问题&#xff1a; 我们登录成功…

Echarts折线图 自适应窗口大小

实现效果&#xff1a; 代码&#xff1a; <template><div class"echarts"><div class"select-box"><div v-for"(item,index) in trendList":key"index":class"[period item.id?active:,item]"click&…

2024微信小程序期末大作业-点奶茶微信小程序(后端nodejs-server)(附下载链接)_微信小程序期末大作业百度网盘下载

菜单展示 购物车展示&#xff1a; 提交订单&#xff1a; 支付详情页展示&#xff1a; 订单查看&#xff1a; 查看历史消费&#xff1a; 部分代码展示&#xff1a; <!--pages/home/home.wxml--> <block wx:for"{{listData}}" wx:key"itemlist&qu…

Python 项目依赖离线管理 pip + requirements.txt

背景 项目研发环境不支持联网&#xff0c;无法通过常规 pip install 来安装依赖&#xff0c;此时需要在联网设备下载依赖&#xff0c;然后拷贝到离线设备进行本地安装。 两台设备的操作系统、Python 版本尽可能一致。 离线安装依赖 # 在联网设备上安装项目所需的依赖 # -d …

cuda编程快速了解

原文链接 https://zhuanlan.zhihu.com/p/34587739 一、Gpu的线程结构 要深刻理解kernel&#xff0c;必须要对kernel的线程层次结构有一个清晰的认识。首先GPU上很多并行化的轻量级线程。kernel在device上执行时实际上是启动很多线程&#xff0c;一个kernel所启动的所有线程称…

2024年过半,新能源车谁在掉链子?

2024年过半之际&#xff0c;各品牌上半年的销量数据也相继出炉&#xff0c;是时候考察今年以来的表现了。 理想和鸿蒙智行两大增程霸主占据头两名&#xff0c;仍处于焦灼状态&#xff1b;极氪和蔚来作为高端纯电品牌紧随其后&#xff0c;两者之间差距很小&#xff1b;零跑和哪…

Truenas scale入坑

家里有一台刚上大学时配的电脑&#xff0c;看着无用武之地&#xff0c;又还能用&#xff0c;于是想那它来搞个私有云nas。 一、选择想要入的坑 一开始对这块没什么了解和概念&#xff0c;最早是在旧主机上安装了个Ubuntu&#xff0c;然后再安装CassOS小尝试了下。可能CassOS里…

商家转账到零钱申请必过办法详解

微信支付平台会对商家转账到零钱的申请进行严格审核&#xff0c;以确保符合相关规定和政策。但可以通过专业机构协助并遵循正确的流程来实现一次通过&#xff0c;以下是一些建议&#xff1a; 1. 确认主体资格&#xff1a;申请商家转账到零钱必须为企业主体&#xff08;有限公司…

78110A雷达信号模拟软件

78110A雷达信号模拟软件 78110A雷达信号模拟软件(简称雷达信号模拟软件)主要用于模拟产生雷达发射信号和目标回波信号&#xff0c;软件将编译生成的雷达信号任意波数据下载到信号发生器中&#xff0c;主要是1466-V矢量信号发生器&#xff0c;可实现雷达信号模拟产生。软件可模…

HDFS读写流程详细过程

HDFS读写流程详细过程 HDFS的定义一、组成架构二、优缺点三、读流程四、NameNode和SeconderyNameNode五、写流程 HDFS的定义 HDFS&#xff08;Hadoop Distributed File System&#xff09;&#xff0c;它是一个文件系统&#xff0c;用于存储文件&#xff0c;通过目录树来定位文…

opencv实现人脸检测功能----20240704

opencv实现人脸检测 早在 2017 年 8 月,OpenCV 3.3 正式发布,带来了高度改进的“深度神经网络”(dnn)模块。 该模块支持多种深度学习框架,包括 Caffe、TensorFlow 和 Torch/PyTorch。OpenCV 的官方版本中包含了一个更准确、基于深度学习的人脸检测器, 链接:基于深度学习…

码云项目如何弄到gitlab上面

码云项目如何弄到gitlab上面 git remote -v 可查看当前的远程仓库git remote remove origin 删除当前的远程仓库git remote add origin gitXXXX:XXXX/shares.git 添加新的远程仓库 这个是你在远程gitlab上面创建的一个空仓库的ssh 地址git remote -v 验证新的远程仓库是否添加…

C++之boost智能指针

1、boost智能指针 资源获取即初始化&#xff1a;在构造函数中对资源进行初始化&#xff0c;在析构函数中释放。 智能指针的本质思想是&#xff1a;将堆对象的生存期&#xff0c;用栈对象来管理。这个栈对象就是智能指针。 当new 一个堆对象的时候&#xff0c;立刻用智能指针…

AI免费文档处理在线工具:文档总结;论文阅读

1、文档总结 NoteGPT 支持各种类型文档ppt、word、pdf等总结 https://notegpt.io/pdf-summary 另外各种大模型工具一般都支持文档上传总结&#xff1a; 例如kimi、通义等 参考&#xff1a;https://blog.csdn.net/weixin_42357472/article/details/138205261 2、论文阅读 h…

plugin:vite:import-analysis]No known conditions for“./lib/locale/lang/zh-cn“

将原有引入&#xff1a; import zhCn from element-plus/lib/locale/lang/zh-cn 改成&#xff1a; import zhCn from element-plus/es/locale/lang/zh-cn; 原因版本升级&#xff0c;引入路径改变&#xff08;原先的包在node_modules\element-plus\lib找不到&#xff09; 新…

c++习题09-分离整数的各个数

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 二&#xff0c;思路 一开始我想到的是将简单容易输出的1000以内的数先进行相应的运算&#xff0c;再输出之后再对1000以上的数字进行判断&#xff08;主要还是想先将很大的数变小&#x…

如何自动筛选螺丝不良品?

四角螺丝是一种特殊设计的螺丝&#xff0c;其螺纹头部呈四个平行的角状结构&#xff0c;与传统的六角螺丝相比具有独特的外观和功能。这种设计使得四角螺丝在安装和拆卸时更容易使用&#xff0c;并提供了更好的扭矩传递效率。四角螺丝头部呈现四个平行的角&#xff0c;与常见的…

如何通过IP地址查询地理位置及运营商信息

在数字时代&#xff0c;IP地址&#xff08;Internet Protocol Address&#xff0c;互联网协议地址&#xff09;已经成为我们日常网络活动的重要组成部分。每台连接到互联网的设备都被分配了一个唯一的IP地址&#xff0c;它不仅可以识别设备&#xff0c;还可以揭示设备的地理位置…