Sping源码(七)—ConfigurationClassPostProcessor创建流程

序言

前两篇文章介绍了invokeBeanFactoryPostProcessors的执行流程,和自定义实现BeanDefinitionRegistryPostProcessor类的方式方法。

这篇文章会主要介绍Spring启动加载xml时,ConfigurationClassPostProcessor类是如何加载到Spring中,并且看看这个类中都做了些什么。

ConfigurationClassPostProcessor这个类在Spring中非常重要,并且之后在SpringBoot中也有涉及。

component-scan

介绍ConfigurationClassPostProcessor之前就不得不说一下context component-scan标签是如何进行加载解析的。

 <context:component-scan base-package="com.xxx" ></context:component-scan>

我们在Spring中通常都用 < context:component-scan >标签来实现包的扫描,而xml在加载解析时。
如果碰到默认的 bean、beans、import、alias标签,会走一套解析流程。
除此之外,其余每个标签中的每个属性都会有单独的Parser类来进行单独的解析。

component-scan解析流程图

在这里插入图片描述

源码

通过源码来仔细看上面的每一步都做了什么。

custom标签解析流程之前帖子中都有提过,不熟悉的这篇帖子中都有介绍。

spring.handlers
加载handlers文件并转换成Map,通过key找到context对应的handler
在这里插入图片描述

ContextNamespaceHandler
执行Handler下init()方法进行初始化,创建context标签下每一个属性的Parser,解析时通过key value形式获取到具体的Parser

public class ContextNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());}
}

parseCustomElement
通过key获取到具体的Handler

@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 获取对应的命名空间String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间找到对应的NamespaceHandlerspringNamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}// 调用自定义的NamespaceHandler进行解析return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}

parse
handler调用具体的parse()方法进行元素解析。

	@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 获取元素的解析器BeanDefinitionParser parser = findParserForElement(element, parserContext);return (parser != null ? parser.parse(element, parserContext) : null);}

ComponentScanBeanDefinitionParser
解析context标签的 component-scan元素,所以找到具体ComponentScanBeanDefinitionParser类parse方法。

public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 获取<context:component-scan>节点的base-package属性值String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);// 解析占位符basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);// 解析base-package(允许通过,;\t\n中的任一符号填写多个)String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);// Actually scan for bean definitions and register them.// 构建和配置ClassPathBeanDefinitionScannerClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);// 使用scanner在执行的basePackages包中执行扫描,返回已注册的bean定义Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);// 组件注册(包括注册一些内部的注解后置处理器,触发注册事件)registerComponents(parserContext.getReaderContext(), beanDefinitions, element);return null;}
}

doScan
获取base-package属性所对应的包名, 并加载所有能够被识别的Bean,封装到BeanDefinition中并注册。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();// 遍历basePackagesfor (String basePackage : basePackages) {// 扫描basePackage,将符合要求的bean定义全部找出来Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 遍历所有候选的bean定义for (BeanDefinition candidate : candidates) {// 解析@Scope注解,包括scopeName和proxyModeScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());// 使用beanName生成器来生成beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {// 处理beanDefinition对象,例如,此bean是否可以自动装配到其他bean中postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 处理定义在目标类上的通用注解,包括@Lazy,@Primary,@DependsOn,@Role,@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查beanName是否已经注册过,如果注册过,检查是否兼容if (checkCandidate(beanName, candidate)) {// 将当前遍历bean的bean定义和beanName封装成BeanDefinitionHolderBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);// 根据proxyMode的值,选择是否创建作用域代理definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册beanDefinitionregisterBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}

registerComponents
这个方法一共做两件事:

  1. 将上一步获取到的所有BeanDefinition添加到compositeDef的nestedComponents属性中。
  2. 判断属性annotation-config值(默认为true),如果为true,则调用AnnotationConfigUtils.registerAnnotationConfigProcessors方法。
protected void registerComponents(XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {Object source = readerContext.extractSource(element);// 使用注解的tagName和source构建CompositeComponentDefinitionCompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);// 将扫描到的所有beanDefinition添加到compositeDef的nestedComponents属性中for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));}// Register annotation config processors, if necessary.boolean annotationConfig = true;if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {// 获取component-scan标签的annotation-config属性值,默认为trueannotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));}if (annotationConfig) {// 如果annotation-config属性值为true,在给定的注册表中注册所有用于注解的bean后置处理器Set<BeanDefinitionHolder> processorDefinitions =AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);for (BeanDefinitionHolder processorDefinition : processorDefinitions) {// 将注册的注解后置处理器的BeanDefinition添加到compositeDef的nestedComponents属性中compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));}}// 触发组件注册事件,默认实现为EmptyReaderEventListenerreaderContext.fireComponentRegistered(compositeDef);}

核心方法 AnnotationConfigUtils.registerAnnotationConfigProcessors

经过了前面一系列的加载、铺垫,此时终于来到了核心方法,来看看ConfigurationClassPostProcessor是如何进行创建的。

AnnotationConfigUtils类中有许多的常量值,而代码中会进行判断,如果没有该BeanDefinition,则会进行创建,而创建的正是ConfigurationClassPostProcessor.class

源码片段

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {//省略部分源码....
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalConfigurationAnnotationProcessor";// 创建BeanDefinitionHolder集合Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// 注册内部管理的用于处理@configuration注解的后置处理器的beanif (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);// 注册BeanDefinition到注册表中beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}return beanDefs;}

完整方法
会在类型进行多个常量判断,如果BeanDefinition中不包含该类,则创建并封装到BeanDefinition中。

public abstract class AnnotationConfigUtils {/*** The bean name of the internally managed Configuration annotation processor.*/public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalConfigurationAnnotationProcessor";/*** The bean name of the internally managed BeanNameGenerator for use when processing* {@link Configuration} classes. Set by {@link AnnotationConfigApplicationContext}* and {@code AnnotationConfigWebApplicationContext} during bootstrap in order to make* any custom name generation strategy available to the underlying* {@link ConfigurationClassPostProcessor}.* @since 3.1.1*/public static final String CONFIGURATION_BEAN_NAME_GENERATOR ="org.springframework.context.annotation.internalConfigurationBeanNameGenerator";/*** The bean name of the internally managed Autowired annotation processor.*/public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalAutowiredAnnotationProcessor";/*** The bean name of the internally managed Required annotation processor.* @deprecated as of 5.1, since no Required processor is registered by default anymore*/@Deprecatedpublic static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalRequiredAnnotationProcessor";/*** The bean name of the internally managed JSR-250 annotation processor.*/public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalCommonAnnotationProcessor";/*** The bean name of the internally managed JPA annotation processor.*/public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalPersistenceAnnotationProcessor";private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME ="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";/*** The bean name of the internally managed @EventListener annotation processor.*/public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME ="org.springframework.context.event.internalEventListenerProcessor";/*** The bean name of the internally managed EventListenerFactory.*/public static final String EVENT_LISTENER_FACTORY_BEAN_NAME ="org.springframework.context.event.internalEventListenerFactory";/*** Register all relevant annotation post processors in the given registry.* @param registry the registry to operate on* @param source the configuration source element (already extracted)* that this registration was triggered from. May be {@code null}.* @return a Set of BeanDefinitionHolders, containing all bean definitions* that have actually been registered by this call*/public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {// 获取beanFactoryDefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {// //设置依赖比较器beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {// //设置自动装配解析器beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}// 创建BeanDefinitionHolder集合Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// 注册内部管理的用于处理@configuration注解的后置处理器的beanif (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);// 注册BeanDefinition到注册表中beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册内部管理的用于处理@Autowired,@Value,@Inject以及@Lookup注解的后置处理器beanif (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.// 注册内部管理的用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器beanif (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.// 注册内部管理的用于处理JPA注解的后置处理器beanif (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册内部管理的用于处理@EventListener注解的后置处理器的beanif (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}// 注册内部管理用于生产ApplicationListener对象的EventListenerFactory对象if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;}
}

截止到这,从xml文件的加载到context 标签 component-scan属性的解析的整体流程已经介绍完成,
接下来看下费尽周折创建的ConfigurationClassPostProcessor中到底有什么?

ConfigurationClassPostProcessor

可以看到ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor和PriorityOrdered。

正好呼应上了上一篇所讲的内容,所以当调用beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class)时。
一定可以获取到Spring已经创建了的ConfigurationClassPostProcessor,并且也一定会调用对应的postProcessBeanDefinitionRegistry();方法。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {//省略部分源码。。。。/*** 定位、加载、解析、注册相关注解** Derive further bean definitions from the configuration classes in the registry.*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {// 根据对应的registry对象生成hashcode值,此对象只会操作一次,如果之前处理过则抛出异常int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}// 将马上要进行处理的registry对象的id值放到已经处理的集合对象中this.registriesPostProcessed.add(registryId);// 处理配置类的bean定义信息processConfigBeanDefinitions(registry);}
}

下一篇帖子介绍ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry()方法都干了些什么。

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

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

相关文章

【数学建模】最优旅游城市的选择问题:层次分析模型(含MATLAB代码)

层次分析法&#xff08;The analytic hierarachy process&#xff0c;简称AHP&#xff09;是一种常用的决策分析方法&#xff0c;其基本思路是将复杂问题分解为多个组成部分&#xff0c;然后对这些部分进行逐一评估和比较&#xff0c;最后得出最优解决方案。&#xff08;例如&a…

JVM知识点总结二

参考文章&#xff1a;【Java面试题汇总】JVM篇&#xff08;2023版&#xff09;_jvm面试题2023-CSDN博客 1、说说你了解的JVM内存模型&#xff1a; JVM由三部分组成&#xff1a;类加载子系统、运行时数据区、执行引擎 JVM内存模型&#xff1a; 内存模型里的运行时数据区&#…

ruby 配置代理 ip(核心逻辑)

在 Ruby 中配置代理 IP&#xff0c;可以通过设置 Net::HTTP 类的 Proxy 属性来实现。以下是一个示例&#xff1a; require net/http// 获取代理Ip&#xff1a;https://www.kuaidaili.com/?refrg3jlsko0ymg proxy_address 代理IP:端口 uri URI(http://www.example.com)Net:…

机器学习 | 使用Scikit-Learn实现分层抽样

在本文中&#xff0c;我们将学习如何使用Scikit-Learn实现分层抽样。 什么是分层抽样&#xff1f; 分层抽样是一种抽样方法&#xff0c;首先将总体的单位按某种特征分为若干次级总体&#xff08;层&#xff09;&#xff0c;然后再从每一层内进行单纯随机抽样&#xff0c;组成…

Django项目使用uwsgi+nginx部署上线

Django项目使用uwsginginx部署上线 前言settings 配置安装uwsgi 和配置uwsgi推荐配置文件启用wsgi不使用nginx的配置&#xff08;不推荐&#xff09;使用nginx的配置 安装 nginx和配置niginx 配置 运行参考资料 前言 代码已经开发完成&#xff0c;正式部署上线 settings 配置…

Redmi Turbo 3新品发布,天星金融(原小米金融)优惠加持护航新机体验

Redmi新十年使命不变&#xff0c;挑战不断升级。Redmi Turbo 3&#xff0c;作为Turbo系列的开篇之作&#xff0c;将自身定位为新生代性能旗舰&#xff0c;决心重塑中端性能新格局。据悉&#xff0c;Redmi Turbo 3于4月10日已正式发布。预售期间更是连续数日&#xff0c;蝉联小米…

SSL证书在HTTP与HTTPS中的角色差异是什么?

在互联网的广泛应用背景下&#xff0c;随着网络攻击和数据泄露事件频发&#xff0c;保障用户的数据安全已成为至关重要的议题。传统的HTTP协议在传输数据时不进行加密处理&#xff0c;导致数据在传输过程中暴露于潜在的窃听和篡改风险中&#xff0c;安全性薄弱。而通过引入SSL/…

解决Keil V5.38 和 ST-Link V3 Debug不能运行问题

目录 概述 1 问题描述 1.1 情况一 1.2 情况二 1.3 情况三 2 解决方法 2.1 认识Keil Mico Lib 2.2 使能Keil Mico Lib 3 验证 3.1 进入C程序Main验证 3.2 断点验证 3.3 上电重启验证 4 结论 笔者使用的验证代码下载地址&#xff1a; stm32-freeRTOS-queue资源-CSD…

微信小程序日期增加时间完成订单失效倒计时(有效果图)

效果图 .wxml <view class"TimeSeond">{{second}}</view>.js Page({data: {tiem_one:,second:,//倒计时deadline:,},onLoad(){this.countdown();},countdown(){let timestamp Date.parse(new Date()) / 1000;//当前时间戳let time this.addtime(2024…

k8s 部署 kube-prometheus监控

一、Prometheus监控部署 1、下载部署文件 # 使用此链接下载后解压即可 wget https://github.com/prometheus-operator/kube-prometheus/archive/refs/heads/release-0.13.zip2、根据k8s集群版本获取不同的kube-prometheus版本部署 https://github.com/prometheus-operator/k…

VSCode断点调试(ROS)

0、安装ros插件 在扩展商店中安装ROS插件&#xff08;Microsoft&#xff09; 1、修改CMakeList.txt # set(CMAKE_BUILD_TYPE "Release") // 注释Release模式 set(CMAKE_BUILD_TYPE "Debug") // 设置为Debug模式 # set(CMAKE_CXX_FLAGS_RELEASE &…

递归、搜索与回溯算法:回溯,决策树

回溯算法是⼀种经典的递归算法&#xff0c;通常⽤于解决组合问题、排列问题和搜索问题等。 回溯算法的基本思想&#xff1a;从⼀个初始状态开始&#xff0c;按照⼀定的规则向前搜索&#xff0c;当搜索到某个状态⽆法前进时&#xff0c;回退到前⼀个状态&#xff0c;再按照其他…

Hadoop3:大数据的基本介绍

一、什么是大数据 1、大数据的4v特点 Volume&#xff08;大量&#xff09; Velocity&#xff08;高速&#xff09; Variety&#xff08;多样&#xff09; Value&#xff08;低价值密度&#xff09; 2、大数据部门间的工作岗位 第三部分&#xff0c;其实就是JavaWeb 二、…

用 element ui 实现季度选择器

由于在数据项目中经常以各种时间条件查询数据&#xff0c;所以时间选择器&#xff08;DatePicker&#xff09;组件是很常用的组件。但是在我使用的 Element UI 中&#xff0c;缺少了季度选择器的功能。 简易实现 一开始我根据时间范围使用 select 去遍历,如 2024-Q1、2023-Q4…

cdp集群Hbase组件HRegionServer服务停止原因以及排查

前言&#xff1a;重启集群后某一节点HRegionServer服务停止&#xff0c;重启前所有服务均正常 去查看日志&#xff1a; 日志报错 ERROR HRegionServer Master rejected startup because clock is out of sync org.apache.hadoop.hbase.ClockOutOfSyncException: org.apache.h…

Spark-Scala语言实战(17)

我带着大家一起来到Linux集群环境下&#xff0c;学习我们的spark。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 Spark-Scala语言实战&#xff08;16&#x…

linux 基础命令docker及防火墙iptables详解

应用场景&#xff1a; web应用自动打包和发布 自动化测试&#xff0c;持续集成、发布 在服务环境中部署后台应用 搭建paaS平台 安装应用 apt install docker.io#kali中 配置docker源&#xff0c;文件位置/etc/docker/daemon.json { "registry-mirrors": [ "h…

机器学习和深度学习-- 李宏毅(笔记于个人理解)Day 21

Day 21 Self- Attention 选修部分 ​ 学完自适应 再回来看看 Sequence Labling 假如我们现在有一个需要读完全部句子才能解的问题&#xff0c; 那么red window 就需要变得是最大的&#xff08;最长的句子&#xff09;&#xff1b; 其实这里大家有没有想过&#xff0c;这个玩意…

死磕GMSSL通信-java/Netty系列(二)

死磕GMSSL通信-java/Netty系列(二) 在上一篇文章中,我们探讨了如何利用C/C++实现国密通信。而本文将聚焦于Java环境下,特别是基于Netty框架,如何实现与国密系统的安全通信。为了确保新项目遵循最新的国密标准,我们将优先推荐使用GB/T 38636-2020(TLCP)协议。对于Java开…

45、二叉树-二叉树的右视图

思路 层序遍历 从左向右遍历每一层取最后一个数&#xff0c;代码如下&#xff1a; public List<Integer> rightSideView(TreeNode root) {if (rootnull){return new ArrayList<>();}Queue<TreeNode> queue new LinkedList<>();List<Integer> …