编程上下文Context及其实现原理

编程上下文Context及其实现原理

author:shengfq
date:2024-07-06
title:编程上下文Context及其实现原理
category:编程思想

思维导图

1.编程中的上下文Context是指什么?

在编程和软件工程领域,“上下文”(Context)是一个多义词,其含义可以根据不同的技术和框架有所变化,但总体上,上下文是指程序执行的环境或状态,它包含了影响程序行为的各种因素。下面是一些编程上下文的主要概念和应用场景:

  1. 线程上下文(Thread Context)
    在多线程编程中,上下文通常指一个线程的执行环境,包括CPU寄存器的值、堆栈状态、线程本地存储(TLS,Thread Local Storage)等。当操作系统或运行时环境在多个线程之间切换时,会保存当前线程的上下文,并恢复下一个线程的上下文。
  2. 函数调用上下文
    当一个函数被调用时,会创建一个调用上下文,其中包含函数的参数、局部变量和函数体。这个上下文在函数执行期间保持有效,直到函数返回,上下文被销毁。
  3. 作用域上下文
    作用域上下文定义了变量的可见性和生命周期。在不同的编程语言中,作用域规则可能有所不同,但通常包括全局作用域、局部作用域、类作用域等。
  4. 安全上下文(Security Context)
    在安全相关的编程中,上下文可能包含用户认证信息、权限和角色等。例如,在Spring Security中,SecurityContextHolder用于管理当前线程的安全上下文。
  5. 网络请求上下文
    在网络编程中,上下文可能包含请求和响应的详细信息,如HTTP头部、请求体、状态码等。
  6. 配置上下文
    应用程序运行所需的配置参数,如数据库连接字符串、API密钥、环境变量等,共同构成了配置上下文。
  7. 事务上下文
    在数据库编程中,事务上下文包含了事务的状态、隔离级别、回滚点等信息,它对于确保数据的一致性和完整性至关重要。
  8. 微服务上下文
    在微服务架构中,上下文可能包含服务间通信的追踪ID、请求的元数据等,用于调试和监控。
  9. 上下文切换(Context Switching)
    上下文切换是指操作系统在不同进程或线程之间切换执行环境的过程。这通常涉及到保存和恢复CPU寄存器、堆栈和其他状态,是影响系统性能的关键因素之一。
  10. 函数式编程上下文
    在函数式编程中,上下文可能指的是闭包(Closure)的概念,即函数可以访问并记住其定义时存在的外部变量。
  11. 框架和库提供的上下文
    许多框架和库提供了自己的上下文概念,如Spring框架的ApplicationContext,它管理着bean的生命周期和依赖注入。

总的来说,编程上下文是理解程序行为的关键,它帮助开发者追踪和控制程序执行的不同方面。掌握上下文的概念对于编写健壮、可维护的代码至关重要。

2.编程实践中常见的Context分类,主要作用?

例如spring框架的ApplicationContext,spring WEB框架的SecurityContext,用户自定义的需要获取会话环境数据的应用场景,如:HTTP请求的会话管理,数据库连接池的事务管理,用户登录访问服务授权管理,这些场景基本都是独立线程隔离级别的会话数据,每个线程都拥有独立的变量副本,不会干扰.

3.案例SecurityContext是怎么应用的?

使用SecurityContextHolder获取当前用户信息
在SecurityContextHolder中保存的是当前访问者的信息。Spring Security使用一个Authentication对象来表示这个信息。一般情况下,我们都不需要创建这个对象,在登录过程中,Spring Security已经创建了该对象并帮我们放到了SecurityContextHolder中。从SecurityContextHolder中获取这个对象也是很简单的。比如,获取当前登录用户的用户名,可以这

类结构:
    SecurityContextHolder //SecurityContext bean工厂
        SecurityContext //上下文实例
            Authentication //认证信息
                UserDetails //用户身份
                
  SecurityContextHolderStrategy  getContext() //接口 获取上下文对象            
    ThreadLocalSecurityContextHolderStrategy //实现类 提供存储在ThreadLocal中的SecurityContext
    InheritableThreadLocalSecurityContextHolderStrategy //提供子线程可继承访问的存储在ThreadLocal中的SecurityContext
    
// 获取安全上下文对象SecurityContext,就是那个保存在 ThreadLocal 里面的安全上下文对象,通过对

// 总是不为null(如果不存在,则创建一个authentication属性为null的empty安全上下文对象)
SecurityContext securityContext = SecurityContextHolder.getContext();

// 获取当前认证了的 principal(当事人),或者 request token (令牌)
// 如果没有认证,会是 null,该例子是认证之后的情况
Authentication authentication = securityContext.getAuthentication()

// 获取当事人信息对象,返回结果是 Object 类型,但实际上可以是应用程序自定义的带有更多应用相关信息的某个类型。
// 很多情况下,该对象是 Spring Security 核心接口 UserDetails 的一个实现类,你可以把 UserDetails 想像
// 成我们数据库中保存的一个用户信息到 SecurityContextHolder 中 Spring Security 需要的用户信息格式的
// 一个适配器。
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
	String username = ((UserDetails)principal).getUsername();
} else {
	String username = principal.toString();
}

每个线程都有一个独立的Security Context,作为环境变量保存到当前线程.

认证与授权

Authentication对象会被填充并放置到SecurityContextHolder中

访问和修改

Authentication =SecurityContextHolder.getContext().getAuthentication()
SecurityContextHolder.getContext().setAuthentication(Authentication)

清理上下文

SecurityContextHolder.clearContext()
    ThreadLocal<SecurityContext>.remove()

4.SecurityContext实现原理ThreadLocal详解?

ThreadLocal 是 Java 中的一个类,用于在多线程环境下为每个线程提供独立的变量副本。它可以解决多线程并发访问共享变量时的线程安全问题。

在多线程应用程序中,多个线程可能同时访问同一个变量,如果没有适当的同步机制,就会导致数据的不一致性和竞态条件。ThreadLocal 提供了一种线程级别的变量隔离机制,使得每个线程都拥有自己独立的变量副本,互不干扰。

ThreadLocal 类提供了以下常用方法

get():获取当前线程的 ThreadLocal 变量的值。如果变量尚未被当前线程设置,则返回 null。

set(T value):设置当前线程的 ThreadLocal 变量的值为指定的值。

remove():移除当前线程的 ThreadLocal 变量。清除后,下次调用 get() 方法将返回 null。

initialValue():返回 ThreadLocal 的初始值。可以通过继承 ThreadLocal 并覆盖该方法来自定义初始值。

withInitial(Supplier<? extends T> supplier):使用指定的 Supplier 函数式接口提供的初始值创建一个 ThreadLocal 实例。

ThreadLocal 的这些方法提供了对线程局部变量的管理和访问。你可以使用 get() 和 set() 方法在当前线程中存储和获取变量的值,使用 remove() 方法清除变量,使用 initialValue() 方法自定义初始值,以及使用 withInitial() 方法创建具有自定义初始值的 ThreadLocal 实例。

ThreadLocal 使用案例

//线程安全的计数器
public class ThreadSafeCounter {
    private static ThreadLocal<Integer> counter = ThreadLocal.withInitial(() -> 0);

    public static void increment() {
        counter.set(counter.get() + 1);
    }

    public static int getCount() {
        return counter.get();
    }
}

线程上下文传递

public class UserContext {
    private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();

    public static void setUser(User user) {
        userThreadLocal.set(user);
    }

    public static User getUser() {
        return userThreadLocal.get();
    }
}

数据库连接管理

public class DBConnectionManager {
    private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();

    public static void openConnection() {
        // 获取数据库连接并设置到 ThreadLocal
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", "user", "password");
        connectionThreadLocal.set(connection);
    }

    public static Connection getConnection() {
        return connectionThreadLocal.get();
    }

    public static void closeConnection() {
        // 关闭数据库连接
        Connection connection = connectionThreadLocal.get();
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                // 异常处理
            }
        }
        // 清理 ThreadLocal 变量
        connectionThreadLocal.remove();
    }
}

ThreadLocal 内存泄漏

ThreadLocal 是 Java 中的一个类,它提供了一个线程局部变量。这些变量不同于普通的变量,因为每个线程都有它自己的副本,而且它们之间互不影响。ThreadLocal 的目的是提供一个方便的方式来保存那些每个线程需要独立访问的数据。

内存泄漏通常指的是程序在释放了某个对象后,后续代码仍然可以访问这个对象。在使用 ThreadLocal 时,如果没有正确地移除对应的线程局部变量,可能会导致内存泄漏。因为一旦 ThreadLocal 的线程被回收,其关联的线程局部变量如果没有手动移除,那么下次当这个线程再次使用 ThreadLocal 时,它将持有一个过期的引用。

解决方法:
在使用完 ThreadLocal 后,手动调用 remove() 方法来清除线程局部变量。
如果使用的是 Java 8 或更高版本,可以利用 ThreadLocal 的新特性(目前是 preview 功能),即在 get 或 set 方法后自动清除线程局部变量。
如果是在 web 应用中,可以在请求处理完毕后的 Filter 中清理 ThreadLocal。
使用 ThreadLocal 的包装类,它们在每次 get 后自动清除 ThreadLocal 中的值。
如果使用了第三方库,检查是否有相关的工具类或注解来自动管理 ThreadLocal 的生命周期。

5.如何确定什么场景适合使用ThreadLocal实现的Context,并正确的使用

在生产实践中,我们要判断是否适合使用Context及ThreadLocal,主要判断依据有:

1.他是以空间换时间的方式实现,在高并发、高性能要求的场景下,频繁的同步操作会导致性能下降。使用 ThreadLocal 可以减少锁的使用,提高程序的并发性能。

2.每个线程都有一个独立的变量副本,需要快捷方便的从上下文中获取变量数据.可考虑使用.

那么,应用开发中,一些场景如:日志追踪,方法间共享信息,事务管理,会话信息,授权信息都可以采用上下文机制实现.

参考文档

ThreadLocal 线程局部变量
Spring Security 的基本组件 SecurityContextHolder

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

开始尝试从0写一个项目--后端(二)

实现学生管理 新增学生 接口设计 请求路径&#xff1a;/admin/student 请求方法&#xff1a;POST 请求参数&#xff1a;请求头&#xff1a;Headers&#xff1a;"Content-Type": "application/json" 请求体&#xff1a;Body&#xff1a; id 学生id …

VideoAgent——使用大规模语言模型作为代理来理解长视频

概述 论文地址&#xff1a;https://arxiv.org/pdf/2403.10517 本研究引入了一个新颖的基于代理的系统&#xff0c;名为 VideoAgent。该系统以大规模语言模型为核心&#xff0c;负责识别关键信息以回答问题和编辑视频。VideoAgent 在具有挑战性的 EgoSchema 和 NExT-QA 基准上进…

MySQL架构和工作流程

引言&#xff1a;MySQL执行一条sql语句期间发生了什么&#xff1f; 想要搞清楚这个问题&#xff0c;我们必须了解MySQL的体系结构和工作流程 一、MySQL体系结构 MySQL由以下几个部分组成 一、server层 1.MySQL Connnectors连接器&#xff0c;MySQL的连接池组件&#xff0c;…

【vue组件库搭建05】vitePress中使用vue/antd/demo预览组件

一、vitepress使用vue及antd组件 1.安装antd之后在docs\.vitepress\theme\index.ts引入文件 // https://vitepress.dev/guide/custom-theme import { h } from vue import type { Theme } from vitepress import DefaultTheme from vitepress/theme import ./style.css impor…

React 19 竞态问题解决

竞态问题/竞态条件 指的是&#xff0c;当我们在交互过程中&#xff0c;由于各种原因导致同一个接口短时间之内连续发送请求&#xff0c;后发送的请求有可能先得到请求结果&#xff0c;从而导致数据渲染出现预期之外的错误。 因为防止重复执行可以有效的解决竞态问题&#xff0…

试用笔记之-汇通Exe可执行文件之pe分析

首先下载汇通Exe可执行文件之pe分析 http://www.htsoft.com.cn/download/pedump.rar

苹果笔记本能玩网页游戏吗 苹果电脑玩steam游戏怎么样 苹果手机可以玩游戏吗 mac电脑安装windows

苹果笔记本有着优雅的机身、强大的性能&#xff0c;每次更新迭代都备受用户青睐。但是&#xff0c;当需要使用苹果笔记本进行游戏时&#xff0c;很多人会有疑问&#xff1a;苹果笔记本能玩网页游戏吗&#xff1f;苹果笔记本适合打游戏吗&#xff1f;本文将讨论这两个话题&#…

数据集 | 人脸公开数据集的介绍及下载地址

本文介绍了人脸相关算法的数据集。 1.人脸数据集详情 1.1.Labeled Faces in the Wild (LFW) 论文 下载地址&#xff1a;LFW Face Database : Main (umass.edu) 是目前人脸识别的常用测试集&#xff0c;其中提供的人脸图片均来源于生活中的自然场景&#xff0c;因此识别难度会…

Google Play上架:恶意软件、移动垃圾软件和行为透明度详细解析和解决办法 (一)

近期整理了许多开发者的拒审邮件和内容,也发现了许多问题,今天来说一下关于恶意软件这类拒审的问题。 目标邮件如下: 首先说一下各位小伙伴留言私信的一个方法,提供你的拒审邮件和时间,尽可能的详细,这样会帮助我们的团队了解你们的问题,去帮助小伙伴么解决问题。由于前…

【CUDA】 扫描 Scan

Scan Scan操作是许多应用程序中常见的操作。扫描操作采用一个二元运算符⊕和一个输入数组并计算输出数组如下&#xff1a; [x0,(x0⊕x1),…,( x0⊕x1⊕…..⊕xn-1)] 分层扫描和多种Scan算法介绍 Kogge-Stones Algorithm Kogge-Stones Algorithm最初是为设计快速加法电路而发…

【pytorch19】交叉熵

分类问题的loss MSECross Entropy LossHinge Loss &#xff08;SVN用的比较多&#xff09; ∑ i m a x ( 0 , 1 − y i ∗ h θ ( x i ) ) \sum_imax(0,1-y_i*h_\theta(x_i)) ∑i​max(0,1−yi​∗hθ​(xi​)) Entropy&#xff08;熵&#xff09; Uncertainty&#xff08;…

解决obsidian加粗中文字体显示不突出的问题

加粗字体显示不突出的原因&#xff1a;默认字体的加粗版本本来就不突出 解决方法&#xff1a;改成显示突出的类型Microsoft YaHei UI 【效果】 修改前&#xff1a;修改后&#xff1a; 其他方法&#xff1a; 修改css&#xff08;很麻烦&#xff0c;改半天也不一定奏效&#…

容器:stack

以下是关于stack容器的一些总结&#xff1a; stack容器比较简单&#xff0c;主要包括&#xff1a; 1、构造函数&#xff1a;stack [staName] 2、添加、删除元素: push() 、pop() 3、获取栈顶元素&#xff1a;top() 4、获取栈的大小&#xff1a;size() 5、判断栈是否为空&#x…

Codeforces Round 903 (Div. 3)A~F

A.Dont Try to Count 输入样例&#xff1a; 12 1 5 a aaaaa 5 5 eforc force 2 5 ab ababa 3 5 aba ababa 4 3 babb bbb 5 1 aaaaa a 4 2 aabb ba 2 8 bk kbkbkbkb 12 2 fjdgmujlcont tf 2 2 aa aa 3 5 abb babba 1 19 m mmmmmmmmmmmmmmmmmmm输出样例&#xff1a; 3 1 2 -1 1 0…

django之url路径

方式一&#xff1a;path 语法&#xff1a;<<转换器类型:自定义>> 作用&#xff1a;若转换器类型匹配到对应类型的数据&#xff0c;则将数据按照关键字传参的方式传递给视图函数 类型&#xff1a; str: 匹配除了”/“之外的非空字符串。 /test/zvxint: 匹配0或任何…

【IO】文件操作

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 文件1.1 认识文件1.2 分清操作的是内存还是硬盘1.3 路径1.3.1 目录结构1.3.2 相对和绝对路径 1.4 文本文件…

计算机网络——数据链路层(以太网扩展、虚拟局域网、高速以太网)

在许多情况下&#xff0c;我们希望把以太网的覆盖范围扩展。本节先讨论在物理层把以太网扩展&#xff0c;然后讨论在数据链路层把以太网扩展。这种扩展的以太网在网络层看来仍然是一个网络。 在物理层扩展以太网 现在&#xff0c;扩展主机和集线器之间的距离的一种简单方法就是…

Spring源码十四:Spring生命周期

上一篇我们在Spring源码十三&#xff1a;非懒加载单例Bean中看到了Spring会在refresh方法中去调用我们的finishBeanFactoryInitialization方法去实例化&#xff0c;所有非懒加载器单例的bean。并实例化后的实例放到单例缓存中。到此我们refresh方法已经接近尾声。 Spring的生命…

【前端实现】在父组件中调用公共子组件:注意事项逻辑示例 + 将后端数组数据格式转换为前端对象数组形式 + 增加和删除行

【前端】在父组件中调用公共子组件的实现方法 写在最前面一、调用公共子组件子组件CommonRow.vue父组件ParentComponent.vue 二、实现功能1. 将后端数组数据格式转换为前端对象数组形式2. 增加和删除row 三、小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2…

【论文解读】AGENTLESS:揭开基于LLM的软件工程代理的神秘面纱,重塑软件工程自动化新基线

&#x1f4dc; 文献卡 英文题目: Agentless: Demystifying LLM-based Software Engineering Agents;作者: Chunqiu Steven Xia; Yinlin Deng; Soren Dunn; Lingming ZhangDOI: 10.48550/arXiv.2407.01489摘要翻译: 大型语言模型&#xff08;LLM&#xff09;的最新进展显著推进…