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

@EnableResourceServer资源服务注解源码分析

文章目录

  • 学习参考
  • @EnableResourceServer
    • 概要
    • ResourceServerConfiguration
      • 属性定义
      • configure(HttpSecurity)
        • ResourceServerSecurityConfigurer
          • init(HttpSecurit)
          • configure(HttpSecurity)

学习参考

Spring Security框架配置运行流程完整分析 - 【必看】

Security OAuth2 授权 & JWT

OAuth2授权流程和源码解析 - 自己总结 - 有道笔记~

@EnableAuthorizationServer授权服务注解源码分析

@EnableResourceServer资源服务注解源码分析

Spring Security整合Gitee第三方登录

第三方登录源码梳理 - 自己总结 - 有道笔记~

Security OAuth2 SSO单点登录(一)

Security OAuth2 SSO单点登录源码剖析 - 自己总结 - 有道笔记~

@EnableResourceServer

概要

@EnableResourceServer用于开启资源服务器,它使用@Import注解引入了ResourceServerConfiguration

  • ResourceServerConfiguration
    • 资源服务器配置类,继承自继承自WebSecurityConfigurerAdapter,order为3,大于AuthorizationServerSecurityConfiguration的order,其中WebSecurityConfigurerAdapter的order默认为100;由此可见它们的顺序:AuthorizationServerSecurityConfiguration、ResourceServerConfiguration、WebSecurityConfigurerAdapter
    • 自动注入容器中定义的TokenStore令牌存储组件、所有的tokenServices资源服务器令牌服务、AuthorizationServerEndpointsConfiguration授权服务器端点配置类、所有的ResourceServerConfigurer资源服务器配置器
    • 在配置HttpSecurity时,会创建1个ResourceServerSecurityConfigurer资源服务器安全配置器,它用于添加到HttpSecurity中继续配置HttpSecurity,会往HttpSecurity中添加OAuth2AuthenticationProcessingFilter这一重要的过滤器,该OAuth2AuthenticationProcessingFilter用于使用令牌加载OAuth2Authenticaiton认证对象,绑定到当前线程中。
    • 在配置HttpSecurity时,也会对把自动注入的TokenStore、tokenServices设置到ResourceServerSecurityConfigurer资源服务器安全配置器中,并且会使用ResourceServerConfigurer资源服务器配置器对该ResourceServerSecurityConfigurer资源服务器安全配置器进行配置
    • 可定义ResourceServerConfigurer类型的bean来配置ResourceServerSecurityConfigurer和HttpSecurity,它们的配置过程都在ResourceServerConfiguration的configure(HttpSecurity)方法中

ResourceServerConfiguration

资源服务器配置类,继承自继承自WebSecurityConfigurerAdapter,order为3

属性定义

/* 尝试注入容器中的 TokenStore 令牌存储器 */
@Autowired(required = false)
private TokenStore tokenStore;/* 尝试注入容器中的 AuthenticationEventPublisher 认证事件发布器 */
@Autowired(required = false)
private AuthenticationEventPublisher eventPublisher;/* 尝试注入容器中的 ResourceServerTokenServices 资源服务器令牌服务 */
@Autowired(required = false)
private Map<String, ResourceServerTokenServices> tokenServices;/* 注入 ApplicationContext 应用上下文 */
@Autowired
private ApplicationContext context;/* 注入容器中的所有定义的 ResourceServerConfigurer 资源服务器配置器 */
private List<ResourceServerConfigurer> configurers = Collections.emptyList();/* 尝试注入容器中的 AuthorizationServerEndpointsConfiguration 授权服务器都单点配置类因为: 授权服务器经常也会开启资源服务器的功能, 如果未开启, 这里就会是null	 */
@Autowired(required = false)
private AuthorizationServerEndpointsConfiguration endpoints;

configure(HttpSecurity)

其实就是在配置ResourceServerSecurityConfigurer 资源服务器安全配置器,而 资源服务器安全配置器 则是为了给HttpSecurity添加1个OAuth2AuthenticationProcessingFilter过滤器

@Override
protected void configure(HttpSecurity http) throws Exception {// 创建1个【ResourceServerSecurityConfigurer 资源服务器安全配置器】, 用来继续配置HttpSecurityResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer();// 解析出1个 资源服务器令牌服务, // 从自动注入的tokenServices中获取, 如果没有, 则返回null; 如果只有1个, 则选择这个; 如果有多个, 须使用@Primary来标注使用哪个ResourceServerTokenServices services = resolveTokenServices();// 如果解析出来了 ResourceServerTokenServices 资源服务器令牌服务, 则设置给 资源服务器安全配置器 的 resourceTokenServices属性if (services != null) {resources.tokenServices(services);}else {// 此时, 容器中未定义任何 ResourceServerTokenServices 资源服务器令牌服务if (tokenStore != null) {// 如果令牌存储器有定义 TokenStore令牌存储器, // 则将此TokenStore设置给 【ResourceServerSecurityConfigurer 资源服务器安全配置器】的tokenStore属性resources.tokenStore(tokenStore);}else if (endpoints != null) {// 此时容器中未定义任何  TokenStore令牌存储器, 则使用AuthorizationServerEndpointsConfiguration的endpoints的tokenStore属性// 设置给【ResourceServerSecurityConfigurer 资源服务器安全配置器】的tokenStore属性resources.tokenStore(endpoints.getEndpointsConfigurer().getTokenStore());}}// 如果容器中有定义 AuthenticationEventPublisher 认证事件发布器, 则将它设置给【ResourceServerSecurityConfigurer 资源服务器安全配置器】if (eventPublisher != null) {resources.eventPublisher(eventPublisher);}// 使用容器中所有定义的 *ResourceServerConfigurer* 资源服务器配置器 来配置【ResourceServerSecurityConfigurer 资源服务器安全配置器】// 这个扩展点非常重要, 注意它的执行时机哦~for (ResourceServerConfigurer configurer : configurers) {configurer.configure(resources);}// 给HttpSecurity添加一些配置器http// 1. 给HttpSecurity的sharedObjects属性中AuthenticationManagerBuilder类型的公共属性添加AnonymousAuthenticationProvider// 2. 这个AuthenticationManagerBuilder的公共属性, 在 WebSecurityConfigurerAdapter 的 getHttp()方法中, 在创建HttpSecurity时, //    就会把WebSecurityConfigurerAdapter的authenticationBuilder属性作为AuthenticationManagerBuilder传进去作为HttpSecurity的公共属性.authenticationProvider(new AnonymousAuthenticationProvider("default"))// 添加异常处理配置器, 将resources的accessDeniedHandler设置给异常处理配置器.exceptionHandling().accessDeniedHandler(resources.getAccessDeniedHandler()).and()// 添加会话管理配置器, 不使用HttpSession.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 移除掉csrf配置器.csrf().disable();// 将【ResourceServerSecurityConfigurer 资源服务器安全配置器】添加到HttpSecurity, // 目的是使用刚刚配置好的 资源服务器安全配置器 来配置HttpSecurityhttp.apply(resources);// 1. 如果 AuthorizationServerEndpointsConfiguration 不为空, 那说明开启了授权服务器//    那就把@FrameworkEndpoint标注的处理器方法的请求路径排除在 资源服务过滤器链 之外// 2. 其实根本就不用吧?!当同时开启授权服务和资源服务的话, 授权服务过滤器链肯定排在资源服务器链前面, 那么肯定先匹配上授权服务过滤器链阿, //    这在AuthorizationServerSecurityConfiguration的configure(HttpSecurity)方法中就设置了资源过滤器链的匹配的路径,//    难道这里只是想说 授权服务的请求不归资源服务器链管?if (endpoints != null) {http.requestMatcher(new NotOAuthRequestMatcher(endpoints.oauth2EndpointHandlerMapping()));}// 使用容器中所有定义的 *ResourceServerConfigurer* 资源服务器配置器 来配置HttpSecurity过滤器链// 这个扩展点非常重要, 注意它的执行时机哦~for (ResourceServerConfigurer configurer : configurers) {configurer.configure(http);}// 如果没有定义 ResourceServerConfigurer 资源服务器配置器, 那就对资源服务过滤器链匹配到的请求 都需要认证后,才能访问if (configurers.isEmpty()) {http.authorizeRequests().anyRequest().authenticated();}
}
ResourceServerSecurityConfigurer

资源服务器安全配置器,用于给HttpSecurity添加OAuth2AuthenticationProcessingFilter过滤器,该过滤器会通过读取令牌加载OAuth2Authentication绑定到当前线程,以确认客户端身份和用户授权信息。

// 异常处理过滤器的认证入口点
AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();// 异常处理过滤器的访问拒绝处理器
AccessDeniedHandler accessDeniedHandler = new OAuth2AccessDeniedHandler();// 【OAuth2AuthenticationProcessingFilter 资源服务器过滤器】
// 它会使用 TokenExtractor 令牌提取器 从当前请求中获取 令牌, 然后把令牌交给 OAuth2AuthenticationManager 作认证, OAuth2AuthenticationManager 又会交给 ResourceServerTokenServices 来加载 OAuth2Authentication 认证对象
OAuth2AuthenticationProcessingFilter resourcesServerFilter;// 认证管理器, 实现一般为: OAuth2AuthenticationManager, 它会持有ResourceServerTokenServices, 用于读取令牌
AuthenticationManager authenticationManager;// 认证事件发布器
AuthenticationEventPublisher eventPublisher = null;// 资源服务器令牌服务, 用于读取令牌, 以获得OAuth2Authentication认证对象
ResourceServerTokenServices resourceTokenServices;// 令牌存储器, 用户存储令牌和查询令牌
TokenStore tokenStore = new InMemoryTokenStore();// 资源服务标识, 用于标识此资源服务。同时, ClientDetails客户端必须拥有该资源服务, 才能访问该资源
String resourceId = "oauth2-resource";// 用于支持权限表达式, 可参考: Security方法注解权限控制过程及自定义权限表达式 https://blog.csdn.net/qq_16992475/article/details/130462486
SecurityExpressionHandler<FilterInvocation> expressionHandler = new OAuth2WebSecurityExpressionHandler();// 令牌提取器, 用于在 OAuth2AuthenticationProcessingFilter 过滤器中, 从请求中获取令牌
TokenExtractor tokenExtractor;// 获取认证详情信息
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;// 是否无状态。
// 如果是false, 则不仅仅是OAuth2客户端可以访问, 非OAuth2客户端也可以访问;
// 如果是true, 则如果是非OAuth2客户端已被认证了, 那么在OAuth2AuthenticationProcessingFilter中会清除掉这个认证对象
//(注意OAuth2AuthenticationProcessingFilter过滤器排在UsernamePasswordAuthenticationFilter前面, 这在FilterComparator和ResourceServerSecurityConfigurer的configure(HttpSecurity)方法中可以看到)
boolean stateless = true;
init(HttpSecurit)
@Override
public void init(HttpSecurity http) {// 1. 其实就是给HttpSecurity过滤器链上的异常过滤器设置入口点属性,// 2. 将当前ResourceServerSecurityConfigurer资源服务器安全配置器的authenticationEntryPoint属性设置到ExceptionHandlingConfigurer的defaultEntryPointMappings中, 并以MediaTypeRequestMatcher实例作为keyregisterDefaultAuthenticationEntryPoint(http);
}
configure(HttpSecurity)
@Override
public void configure(HttpSecurity http) {// 创建1个 OAuth2AuthenticationManager OAuth2认证管理器, 并完成 OAuth2认证管理器 的配置AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http);// 创建1个 【OAuth2AuthenticationProcessingFilter 过滤器】resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 OAuth2认证管理器 和 认证入口点resourcesServerFilter.setAuthenticationEntryPoint(authenticationEntryPoint);resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);// 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 认证事件发布器if (eventPublisher != null) {resourcesServerFilter.setAuthenticationEventPublisher(eventPublisher);}// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 令牌提取器if (tokenExtractor != null) {resourcesServerFilter.setTokenExtractor(tokenExtractor);}// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 认证详情源if (authenticationDetailsSource != null) {resourcesServerFilter.setAuthenticationDetailsSource(authenticationDetailsSource);}// 使用ObjectPostProcessor处理 【OAuth2AuthenticationProcessingFilter 过滤器】resourcesServerFilter = postProcess(resourcesServerFilter);// 给 【OAuth2AuthenticationProcessingFilter 过滤器】 设置 statelessresourcesServerFilter.setStateless(stateless);http// 添加FilterSecurityInterceptor过滤器, 并添加支持权限表达式处理器.authorizeRequests().expressionHandler(expressionHandler).and()// 添加【OAuth2AuthenticationProcessingFilter 过滤器】, 放置在AbstractPreAuthenticatedProcessingFilter前面// 在我们熟悉的 UsernamePasswordAuthenticationFilter, 可在FilterComparator中看到.addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.class)// 添加异常处理配置器, 并指定 访问拒绝处理器 和 认证入口点.exceptionHandling().accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(authenticationEntryPoint);
}private AuthenticationManager oauthAuthenticationManager(HttpSecurity http) {// 创建1个 OAuth2AuthenticationManager OAuth2认证管理器OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();// 如果已经设置认证管理器, 并且 如果认证管理器是 OAuth2AuthenticationManager  那么给该oauthAuthenticationManager继续设置属性, //                          如果认证管理器不是 OAuth2AuthenticationManager 类型, 那么直接返回if (authenticationManager != null) {if (authenticationManager instanceof OAuth2AuthenticationManager) {oauthAuthenticationManager = (OAuth2AuthenticationManager) authenticationManager;}else {return authenticationManager;}}// 设置 资源服务标识, 若客户端无该资源服务标识, 将不能访问该资源oauthAuthenticationManager.setResourceId(resourceId);// 获取 资源服务器令牌服务, 并设置给 OAuth2认证管理器oauthAuthenticationManager.setTokenServices(resourceTokenServices(http));// 获取 客户端服务, 并设置给 OAuth2认证管理器oauthAuthenticationManager.setClientDetailsService(clientDetails());// 返回配置好的 OAuth2认证管理器return oauthAuthenticationManager;
}// 获取资源服务器令牌服务
private ResourceServerTokenServices resourceTokenServices(HttpSecurity http) {// 获取 ResourceServerSecurityConfigurer 设置的 resourceTokenServices 或 创建1个DefaultTokenServices 作为 资源服务器令牌服务tokenServices(http);return this.resourceTokenServices;
}// 获取 资源服务器令牌服务
private ResourceServerTokenServices tokenServices(HttpSecurity http) {// 如果设置 给 ResourceServerSecurityConfigurer 设置了 resourceTokenServices, 就直接返回指定的资源服务器令牌服务if (resourceTokenServices != null) {return resourceTokenServices;}// 未给 ResourceServerSecurityConfigurer 设置 令牌服务 属性时, // 就会创建默认的令牌服务, 并使用 ResourceServerSecurityConfigurer 设置 的令牌存储器// 创建1个默认的令牌服务DefaultTokenServices tokenServices = new DefaultTokenServices();// 获取tokenStore 设置到 令牌服务 中()tokenServices.setTokenStore(tokenStore());// 设置支持刷新令牌tokenServices.setSupportRefreshToken(true);// 设置客户端详情服务tokenServices.setClientDetailsService(clientDetails());// DefaultTokenServices可作为资源服务器令牌服务this.resourceTokenServices = tokenServices;return tokenServices;
}// 获取 令牌存储器
// 直接返回 ResourceServerSecurityConfigurer 的 tokenStore 属性, 显然它一定要被设置, 否则一调用就会抛异常
private TokenStore tokenStore() {Assert.state(tokenStore != null, "TokenStore cannot be null");return this.tokenStore;
}// 获取访问拒绝处理器, 直接返回 ResourceServerSecurityConfigurer 的 accessDeniedHandler 属性
public AccessDeniedHandler getAccessDeniedHandler() {return this.accessDeniedHandler;
}

相关文章:

@EnableResourceServer资源服务注解源码分析

文章目录 学习参考EnableResourceServer概要ResourceServerConfiguration属性定义configure(HttpSecurity)ResourceServerSecurityConfigurerinit(HttpSecurit)configure(HttpSecurity) 学习参考 Spring Security框架配置运行流程完整分析 - 【必看】 Security OAuth2 授权 &…...

SpringBoot实现图片文件上传和回显的两种方式

目录 一 功能需求 二 上传本地 2.1 实现文件上传的controller层 2.2 图片访问资源映射 二 上传OSS 一 功能需求 实现图片的上传和回显功能其实在业务中是非常常见的&#xff0c;比如需要上传头像&#xff0c;或者交易平台需要上传物品的图片等等&#xff0c;都需要上传和回…...

进程和计划任务以及步骤

进程 进程和程序有关&#xff0c;把该文件放到内存里&#xff0c;进程是动态的&#xff0c;不同时刻的状态不一样 内存&#xff1a;放置正在运行的程序和所需数据的位置 程序启动 ——》将相关文件和数据放到内存里 ——》进程&#xff08;processes&#xff09; 进程相关命令 …...

使用Python实现深度学习模型:序列到序列模型(Seq2Seq)

序列到序列&#xff08;Seq2Seq&#xff09;模型是一种深度学习模型&#xff0c;广泛应用于机器翻译、文本生成和对话系统等自然语言处理任务。它的核心思想是将一个序列&#xff08;如一句话&#xff09;映射到另一个序列。本文将详细介绍 Seq2Seq 模型的原理&#xff0c;并使…...

力扣283. 移动零

给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出:[1,3,12,0,0] 示例 2: 输入: nums [0] …...

二叉树的顺序结构(堆的实现)

前言 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。 现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储&#xff0c;需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事&…...

2024大模型如何学习【附学习资料】

摘要&#xff1a; 通过深入了解本文中的这些细节&#xff0c;并在实际项目中应用相关知识&#xff0c;将能够更好地理解和利用大模型的潜力&#xff0c;不仅在学术研究中&#xff0c;也在工程实践中。通过不断探索新方法、参与项目和保持热情&#xff0c;并将其应用于各种领域&…...

计算机组成原理·考点知识点整理

根据往年考试题&#xff0c;对考点和知识点的一个整理。 校验编码 码距 一种编码的最小码距&#xff0c;其实就是指这种编码的码距。码距有两种定义&#xff1a; 码距所描述的对象含义 2 2 2 个特定的码其二进制表示中不同位的个数一种编码这种编码中任意 2 2 2 个合法编码的…...

python-datetime模块时间戳常用方法汇总

文章目录 datetime模块常用方法1、导入模块2、获取当前日期和时间3、获取当前日期4、创建特定日期或时间5、日期和时间的运算6、使用timedelta运算日期时间创建 timedelta 对象timedelta 的加减运算timedelta 的属性timedelta 的比较示例代码格式化日期和时间获取日期和时间的各…...

【Python报错】已解决ModuleNotFoundError: No module named ‘timm’

成功解决“ModuleNotFoundError: No module named ‘timm’”错误的全面指南 一、引言 在Python编程中&#xff0c;经常会遇到各种导入模块的错误&#xff0c;其中“ModuleNotFoundError: No module named ‘timm’”就是一个典型的例子。这个错误意味着你的Python环境中没有安…...

【设计模式】适配器模式(结构型)⭐⭐⭐

文章目录 1.概念1.1 什么是适配器模式1.2 优点与缺点 2.实现方式2.1 类适配器模式2.2 对象适配器模式 3 Java 哪些地方用到了适配器模式4 Spring 哪些地方用到了适配器模式 1.概念 1.1 什么是适配器模式 简单来说&#xff0c;适配器模式就是作为两个不兼容接口之间的桥梁。 1.…...

云原生周刊:Gateway API v1.1 发布 | 2024.6.3

开源项目推荐 Grafana Tanka Tanka 是 Grafana 开发的一款用于 Kubernetes 的灵活、可重用和简洁的配置工具,是使用 YAML 进行 Kubernetes 配置的一种替代方案。 pv-migrate pv-migrate 是一个 CLI 工具/kubectl 插件&#xff0c;可以轻松地将一个 Kubernetes PersistentVo…...

KotlinConf 2024:深入了解Kotlin Multiplatform (KMP)

KotlinConf 2024&#xff1a;深入了解Kotlin Multiplatform (KMP) 在近期的Google I/O大会上&#xff0c;我们推荐了Kotlin Multiplatform (KMP)用于跨移动、网页、服务器和桌面平台共享业务逻辑&#xff0c;并在Google Workspace中采用了KMP。紧接着&#xff0c;KotlinConf 2…...

探索ChatGPT-4在解决化学知识问题上的研究与应用

1. 概述 近年来&#xff0c;人工智能的发展主要集中在 GPT-4 等大型语言模型上。2023 年 3 月发布的这一先进模型展示了利用广泛知识应对从化学研究到日常问题解决等复杂挑战的能力。也开始进行研究&#xff0c;对化学的各个领域&#xff0c;从化学键到有机化学和物理化学&…...

性能狂飙:SpringBoot应用优化实战手册

在数字时代&#xff0c;速度就是生命&#xff0c;性能就是王道&#xff01;《极速启航&#xff1a;SpringBoot性能优化的秘籍》带你深入SpringBoot的内核&#xff0c;探索如何打造一个飞速响应、高效稳定的应用。从基础的代码优化到高级的数据库连接池配置&#xff0c;再到前端…...

Github上一款开源、简洁、强大的任务管理工具:Condution

Condution 是一款开源任务管理工具&#xff0c;它以简洁易用、功能强大著称。它旨在为用户提供一个简单高效的平台&#xff0c;帮助他们管理日常任务、提高工作效率。 1. Condution 的诞生背景 现如今&#xff0c;市面上存在着许多任务管理软件&#xff0c;但它们往往价格昂贵…...

LeetCode-2938. 区分黑球与白球【贪心 双指针 字符串】

LeetCode-2938. 区分黑球与白球【贪心 双指针 字符串】 题目描述&#xff1a;解题思路一&#xff1a;贪心解题思路二&#xff1a;一次遍历统计1的个数&#xff0c;找0后累加左边的1的个数解题思路三&#xff1a; 题目描述&#xff1a; 桌子上有 n 个球&#xff0c;每个球的颜色…...

深度神经网络——什么是扩散模型?

1. 概述 在人工智能的浩瀚领域中&#xff0c;扩散模型正成为技术创新的先锋&#xff0c;它们彻底改变了我们处理复杂问题的方式&#xff0c;特别是在生成式人工智能方面。这些模型基于高斯过程、方差分析、微分方程和序列生成等坚实的数学理论构建。 业界巨头如Nvidia、Google…...

有代码冗余的检查工具嘛

是的&#xff0c;有一些代码质量工具可以帮助检查冗余代码。这些工具可以分析代码库&#xff0c;并识别出重复、冗余或不必要的代码片段。一些流行的代码质量工具包括&#xff1a; PMD: PMD 是一个开源的静态代码分析工具&#xff0c;支持多种编程语言&#xff0c;包括 Java、…...

3D培训大师:快速输出标准3D课件,打造沉浸式培训体验

随着技术的日新月异和市场的迅猛扩张&#xff0c;企业对员工专业技能培训的需求日益凸显。传统的培训方式往往依赖于实地操作、现场指导&#xff0c;这不仅需要大量的人力、物力和时间成本&#xff0c;而且存在安全风险。特别是化工、机械制造等行业&#xff0c;实操培训的成本…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...