Sping源码(七)— 后置处理器

news2024/11/24 23:11:32

简单回顾一下上一篇文章,是在BeanFacroty创建完之后,可以通过Editor和EditorRegistrar实现对类属性的自定义扩展,以及忽略要自动装配的Aware接口。
本篇帖子会顺着refresh()主流程方法接着向下执行。在讲invokeBeanFactoryPostProcessors方法的具体逻辑之前,先简单介绍BeanFactoryPostProcessor接口和整个invokeBeanFactoryPostProcessors方法的执行流程。

refresh

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			/**
			 * 前戏,做容器刷新前的准备工作
			 * 1、设置容器的启动时间
			 * 2、设置活跃状态为true
			 * 3、设置关闭状态为false
			 * 4、获取Environment对象,并加载当前系统的属性值到Environment对象中
			 * 5、准备监听器和事件的集合对象,默认为空的集合
			 */

			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 创建容器对象:DefaultListableBeanFactory
			// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinition
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// beanFactory的准备工作,对各种属性进行填充
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				// 调用各种beanFactory处理器
				invokeBeanFactoryPostProcessors(beanFactory);
			}		
		}
	}

在这里插入图片描述

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}

BFPP和BDRPP

根据上面的流程图以及代码块可以看出BFPP和BDRPP的关系,其中BFPP类中只有一个postProcessBeanFactory()方法,而BDRPP中只有postProcessBeanDefinitionRegistry()方法,因为是继承的关系,所以所有实现BDRPP接口的类,也会有postProcessBeanFactory()方法。
而BFPP和BDRPP其中有一个很重要的区别就在于,它们两个方法接收的参数不同,其中BFPP接收BeanFactory参数,针对整个BeanFactory做操作,而BDRPP接收的参数是BeanDefinitionRegistry(可以理解是对Definition做一些正删改查的操作)

BeanDefinitionRegistry

public interface BeanDefinitionRegistry extends AliasRegistry {

	/**
	 * 注册BeanDefinition到注册表
	 *
	 * Register a new bean definition with this registry.
	 * Must support RootBeanDefinition and ChildBeanDefinition.
	 * @param beanName the name of the bean instance to register
	 * @param beanDefinition definition of the bean instance to register
	 * @throws BeanDefinitionStoreException if the BeanDefinition is invalid
	 * @throws BeanDefinitionOverrideException if there is already a BeanDefinition
	 * for the specified bean name and we are not allowed to override it
	 * @see GenericBeanDefinition
	 * @see RootBeanDefinition
	 * @see ChildBeanDefinition
	 */
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	/**
	 * 移除注册表中beanName的BeanDefinition
	 *
	 * Remove the BeanDefinition for the given name.
	 * @param beanName the name of the bean instance to register
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 */
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 获取注册表中beanName的BeanDefinition
	 *
	 * Return the BeanDefinition for the given bean name.
	 * @param beanName name of the bean to find a definition for
	 * @return the BeanDefinition for the given name (never {@code null})
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 */
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 检查此注册表是否包含具有给定名称的BeanDefinition
	 *
	 * Check if this registry contains a bean definition with the given name.
	 * @param beanName the name of the bean to look for
	 * @return if this registry contains a bean definition with the given name
	 */
	boolean containsBeanDefinition(String beanName);

	/**
	 * 返回此注册表中定义的所有bean的名称
	 *
	 * Return the names of all beans defined in this registry.
	 * @return the names of all beans defined in this registry,
	 * or an empty array if none defined
	 */
	String[] getBeanDefinitionNames();

	/**
	 * 返回注册表中定义的bean的数目
	 *
	 * Return the number of beans defined in the registry.
	 * @return the number of beans defined in the registry
	 */
	int getBeanDefinitionCount();

	/**
	 *  确定给定bean名称是否已在该注册表中使用
	 *
	 * Determine whether the given bean name is already in use within this registry,
	 * i.e. whether there is a local bean or alias registered under this name.
	 * @param beanName the name to check
	 * @return whether the given bean name is already in use
	 */
	boolean isBeanNameInUse(String beanName);

}

接口的作用和整体的执行流程已经介绍完成,下面看看invokeBeanFactoryPostProcessors方法的具体执行逻辑。

invokeBeanFactoryPostProcessors

主要是调用delegate中的同名invokeBeanFactoryPostProcessors方法,对BaenFactory中和自定义注册进来的BFPP的实现类进行处理。
其中getBeanFactoryPostProcessors()是如果类继承了AbstractApplicationContext后,可以有add方法自行注册BeanFactoryPostProcessor。处理时也会先处理这部分的BFPP。

invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		// 获取到当前应用程序上下文的beanFactoryPostProcessors变量的值,并且实例化调用执行所有已经注册的beanFactoryPostProcessor
		// 默认情况下,通过getBeanFactoryPostProcessors()来获取已经注册的BFPP,但是默认是空的
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

AbstractApplicationContext
如果想要自己注册进来,要实现AbstractApplicationContext并调用addBeanFactoryPostProcessor方法将自定义BFPP实现类加进来,就可以get到。

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	@Override
	public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
		this.beanFactoryPostProcessors.add(postProcessor);
	}

	/**
	 * Return the list of BeanFactoryPostProcessors that will get applied
	 * to the internal BeanFactory.
	 */
	public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
		return this.beanFactoryPostProcessors;
	}
	//删除其他代码
}	

具体处理逻辑
如最开始图片中标注的处理流程一样,

  1. 处理过的BFPP都放入processedBeans集合,避免后续重复执行。
  2. 先遍历beanFactoryPostProcessors中BDRPP类型的,并直接调用postProcessBeanDefinitionRegistry进行逻辑处理。非BDRPP类型放入regularPostProcessors集合,后续统一处理。
  3. 找到BeanFactory中BDRPP类型,并根据PriorityOrdered,Order进行优先级排序,最后再执行没有优先级的。
  4. 因为继承了BDRPP的肯定也会有BFPP中的方法,所以还会统一处理执行BDRPP中的postProcessBeanFactory方法。
  5. 执行完BeanFactory中的BDRPP类型后,再查找BeanFactory中BFPP类型,同样按照PriorityOrdered,Order进行优先级排序。并执行postProcessBeanFactory方法。
class PostProcessorRegistrationDelegate {

	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
        //所有已经执行过BFPP的存储在processedBeans,防止重复执行
		Set<String> processedBeans = new HashSet<String>();
        
        //判断beanFactory是否属于BeanDefinitionRegistry类型,默认的beanFactory是DefaultListableBeanFactory,
        //实现了BeanDefinitionRegistry 所以为true
		if (beanFactory instanceof BeanDefinitionRegistry) {
            //强制类型转换
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            
            //存放BFPP类型的集合
			List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
            
            //存放BDRPP类型的集合
			List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
					new LinkedList<BeanDefinitionRegistryPostProcessor>();
            
            //优先处理入参中的beanFactoryPostProcessors,遍历所有beanFactoryPostProcessors,
            //并将参数中的BFPP和BDRPP区分开
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                //如果是BDRPP类型
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryPostProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
                            
                    //直接调用BDRPP中的postProcessBeanDefinitionRegistry具体方法进行处理
					registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
                    //放入registryPostProcessors集合中
					registryPostProcessors.add(registryPostProcessor);
				}
				else {
                    //否则,只是普通的BeanFactoryPostProcessor,则放入regularPostProcessors集合
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
            
            //根据type获取BeanFactory中所有类型为BDRPP的postProcessorNames
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            
            //将实现了BDRPP和priorityOrder接口的类放入该集合
			List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
			for (String ppName : postProcessorNames) {
                //如果是PriorityOrdered类型的
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    //放入priorityOrderedPostProcessors集合
					priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //放入processedBeans集合,避免重复执行
					processedBeans.add(ppName);
				}
			}
            //按照优先级进行排序
			OrderComparator.sort(priorityOrderedPostProcessors);
            //添加到registryPostProcessors中
			registryPostProcessors.addAll(priorityOrderedPostProcessors);
            //遍历priorityOrderedPostProcessors集合,执行postProcessBeanDefinitionRegistry方法
			invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            //再次获取BDRPP类型的所有postProcessorNames
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            //实现了Order接口的BeanDefinitionRegistryPostProcessor放入该集合
			List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
			for (String ppName : postProcessorNames) {
                //如果是没执行过,并且实现了Order接口的
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    //放到Order集合中
					orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //放入processedBeans集合,避免重复执行
					processedBeans.add(ppName);
				}
			}
            //按照优先级排序
			OrderComparator.sort(orderedPostProcessors);
            //放入registryPostProcessors集合
			registryPostProcessors.addAll(orderedPostProcessors);
            //遍历orderedPostProcessors集合,执行postProcessBeanDefinitionRegistry方法
			invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
                //找出所有实现了BDRPP接口的类
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
                    //跳过执行过BDRPP的类
					if (!processedBeans.contains(ppName)) {
                        //根据name获取实例
						BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
                        //添加到registryPostProcessors集合中
                        registryPostProcessors.add(pp);
                        //添加到processedBeans集合中
						processedBeans.add(ppName);
                        //直接执行BDRPP
						pp.postProcessBeanDefinitionRegistry(registry);
						reiterate = true;
					}
				}
			}   
            
			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            //遍历registryPostProcessors和regularPostProcessors中有所的bean,
            //执行BFPP接口postProcessBeanFactory方法
			invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}
        //如果beanFactory不属于BeanDefinitionRegistry,直接执行具体方法
		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}
        
        //到这为止,入参的beanFactoryPostProcessors和BeanFactory中BDRPP类型的方法已经全部处理完成
        //后面开始都是操作BFPP类型
        //到这位置
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
        
        //找到所有实现BeanFactoryPostProcessor的类
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
        //依次声明priorityOrderedPostProcessors、orderedPostProcessorNames和nonOrderedPostProcessorNames分别用来存放对应
        //实现了priorityOrdered、ordered和没实现排序接口的类
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
		List<String> orderedPostProcessorNames = new ArrayList<String>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
        //遍历所有postProcessorNames,将没执行过的BFPP方法的类放入对应集合中。
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        //按照优先级进行排序,并执行具体的BFPP方法
		OrderComparator.sort(priorityOrderedPostProcessors);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		OrderComparator.sort(orderedPostProcessors);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
	}

看完上面这段源码之后,不知道大家有没有这样的一个疑问,为什么重复代码较多?每次都要根据类型重新获取String[] postProcessorNames,第一次获取后,根据postProcessorNames按照PriorityOrdered和Order进行优先级排序、分组执行不行么?
是因为在执行BDRPP的方法postProcessBeanDefinitionRegistry时,有可能会有新增的额外的BDRPP的类,每次都重新获取,能避免BDRPP类执行的不完全。

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

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

相关文章

FastDeploy部署(C++ Win10)

参考链接&#xff1a;FastDeploy C部署保姆级教程 FastDeploy是百度为了解决AI部署落地难题&#xff0c;发布的新一代面向产业实践的推理部署工具。它旨在为AI开发者提供模型部署最优解&#xff0c;具备全场景、简单易用、极致高效三大特点。项目地址&#xff1a;FastDeploy项…

聊聊调制解调器

目录 1.什么是调制解调器 2.调制解调器的工作原理 3.调制解调器的作用 4.调制解调器未来发展 1.什么是调制解调器 调制解调器&#xff08;Modem&#xff09;是一种用于在数字设备和模拟设备之间进行数据传输的设备。调制解调器将数字数据转换为模拟信号进行传输&#xff0c;…

ArcGIS:如何给栅格数据创建属性表

问题描述&#xff1a;使用ArcMap加载栅格数据后发现没有属性表&#xff0c;如下图&#xff0c;如何创建属性表 解决方法&#xff1a; 方法一&#xff1a; 鼠标右键点击栅格数据&#xff0c;然后选择【属性】&#xff0c;接着点击【符号系统】–【唯一值】&#xff0c;选择计算…

如何提升IT业务安全性?收藏起来照着做!

UPS作为一种关键设备&#xff0c;能够在电力中断时为电子设备提供临时的电力支持&#xff0c;从而防止数据丢失、设备损坏以及生产中断。因此&#xff0c;UPS系统的正常运行对于持续的监控和管理至关重要。 UPS监控不仅仅是关于监视UPS系统的运行状态&#xff0c;更是一项综合性…

微信开发之一键发布群公告的技术实现

简要描述&#xff1a; 设置群公告 请求URL&#xff1a; http://域名地址/setChatRoomAnnouncement 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必…

深度学习入门(三):卷积神经网络(CNN)

引入 给定一张图片&#xff0c;计算机需要模型判断图里的东西是什么&#xff1f; &#xff08;car、truck、airplane、ship、horse&#xff09; 一、卷积神经网络整体架构 CONV&#xff1a;卷积计算层&#xff0c;线性乘积求和RELU&#xff1a;激励层&#xff0c;激活函数P…

css选择器,选择div标签里的span标签,选最后一个span

CSS3 :last-child 选择器 | 菜鸟教程 CSS 6种选择器(超详细)_scss 选择器_想念的博客-CSDN博客

人大金仓(kingbase8)安装与初始化超详细教程

人大金仓 KingbaseES V8 R3 安装包、驱动包和 License 下载地址 - 博客文章 - 任霏的个人博客网站 人大金仓Kingbase8安装与基本使用_码农茶叶蛋的博客-CSDN博客 80篇国产数据库实操文档汇总&#xff08;含TiDB、达梦、openGauss等&#xff09; 禁用防火墙 systemctl stop fi…

uni-app的nvue文件国际化不翻译问题解决办法

官网上的nvue国际化方式介绍的实在是太简单了&#xff0c;记得要引入下message文件&#xff0c;还要用uni.setLocale()设置下&#xff0c;但是不管我怎么引入都会报错。 所以我直接把文件拿过来了&#xff0c;通过对象的方式去取。 <!-- index.nvue 文件 --> <view&g…

Spring复习:(55)ApplicationContext中BeanFactoryPostProcessor是怎么添加到容器的?

容器创建时会调用AbstractApplicationContext的refresh方法&#xff0c;其中会调用invokeBeanFactoryPostProcessor方法&#xff0c;如下图 invokeBeanFactoryPostProcessors代码如下&#xff1a; 其中调用的PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcess…

【Linux】线程篇Ⅰ:线程和task_struct 执行流的理解、相关接口命令、线程异常、线程的私有和共享

线程Ⅰ 一、概念0. 线程1. 线程的优缺点2. 页框和页帧3. 页表的设计、虚拟地址的解析方式、以及块为什么设计成 4kb4. 对进程的一些整体理解 二、一些接口 和 命令1. ps -aL - - 查看执行流2. pthread_create 函数&#xff1a;创建线程3. ptread_join 线程等待4. ptread_exit 线…

5G随身wifi如何选择?简单分类一下

最近5g随身wifi越来越多了&#xff0c;价格也一直走低&#xff0c;根据我的观察和总结&#xff0c;5g随身wifi可以分为这几档&#xff1a;&#xff08;普遍来说&#xff09; 1&#xff0c;紫光udx710基带芯片&#xff08;也叫v510&#xff09; 代表产品&#xff1a;r106&#x…

Sulfo-CY5 NH2荧光光谱特性-激发波长与发射波长【星戈瑞】

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a;Sulfo-CY5 NH2荧光光谱特性-激发波长与发射波长 Sulfo-CY5 NH2是一种荧光染料&#xff0c;其荧光特性使其在生物标记、细胞成像和其他荧光应用中得到诸多应用。荧光是一种发光现象&#xff0c;当Sulfo-CY…

Web容器简介

容器与组件 Java EE&#xff08;Java Platform Enterprise Edition&#xff09;是一种企业级的Java版本。 Java EE是SUN公司提出来的企业版Java开发中间件&#xff0c;它主要用于企业级互联网系统的搭建。 Java EE的本质是一种容器加组件技术&#xff0c;这句话里包含了两个…

1.2亿成都市城市安全风险综合监测预警平台建设项目

导读&#xff1a;原文《1.2亿&#xff01;成都市城市安全风险综合监测预警平台建设项目WORD》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 部分页面&#xff1a; …

牛股预测器V1.0实战(工银瑞信金融科技挑战赛排名第二)

全代码和数据关注公众号《三个篱笆三个班》免费提供&#xff01;一键可跑&#xff0c;每日选股。 对AI炒股感兴趣的小伙伴可加WX群&#xff1a; 赛题概述&#xff1a; 基于人工智能的量化选股投资策略建模挑战 任务描述&#xff1a; 通过数学和计算机技术分析市场数据&…

随身wifi刷超频版Debian系统教程-随身wifi折腾入门

本人折腾Debian的一些记录&#xff0c;有需要的可以参考一下。本文所用到的命令&#xff0c;请先确保已获得root权限执行。 1.更新和升级系统中已安装的软件包 apt-get update && apt-get upgrade &&; apt-get update --fix-missing •apt-get update&#xff…

解锁人工智能项目开发的关键:Python 基础库详解与进阶学习

“ Python 是一种通用的编程语言&#xff0c;广泛用于人工智能项目开发。它有很多可用的库&#xff0c;可以帮助开发人员构建各种人工智能应用程序&#xff0c;如自然语言处理和机器学习。在本文中&#xff0c;我们将介绍一些最流行的 Python 库&#xff0c;以及它们在人工智能…

【机密计算实践】支持 Intel SGX 的 LibOS 项目介绍(二)

续上一篇 【机密计算实践】支持 Intel SGX 的 LibOS 项目介绍(一) 四、Mystikos Mystikos 是一个运行库和一组工具,用于在硬件可信执行环境(TEE)中运行 Linux 应用程序。当前版本支持英特尔 SGX,而未来版本可能支持其他 TEE。 4.1 目标 通过使用硬件 TEE,在…