Spring上下文模块设计

经过此前我们设计的如:IoC、Web、数据访问、AOP等模块的设计,我们从设计上已经搭建好了Spring的基础骨架了,但聪明的码友会思考想到:作为一个基础框架而言,目前应该是已经够用了的,但是上进的码友怎么会就此止步;从模块划分上每个模块均有自己要关注和实现的内容,那么是否会存在一些共有的内容,比如:环境配置、事件机制、国际化等。

一、背景与设计理念

在Spring框架早期版本中,BeanFactory作为最基础的IoC容器实现,仅提供了基础的依赖注入功能和Bean生命周期管理。开发者需要通过显式编码来创建和管理对象,每个Bean的依赖关系都需要手动配置和解析,导致大量重复代码。随着企业应用复杂度增加,这种基础容器的局限性日益凸显:缺乏事件机制国际化支持薄弱资源抽象不足(资源配置分散在各模块,难以满足现代应用的需求。

Spring上下文的诞生正是为了解决这些痛点。ApplicationContext作为BeanFactory的扩展,在保留核心依赖注入功能的同时,引入了多项企业级服务支持,形成了完整的应用执行环境。与基础BeanFactory相比,ApplicationContext提供了以下关键增强:

  • 资源管理统一化:通过ResourceLoaderResource接口抽象不同来源的资源(类路径、文件系统、URL等),使资源获取与具体环境解耦;
  • 国际化便捷支持:基于MessageSource接口提供消息解析机制,支持层次化消息源和地区化处理
  • 事件发布订阅模型:通过ApplicationEventPublisherApplicationListener实现观察者模式,增强组件间解耦
  • 上下文层次化管理:支持父子容器结构,允许在不同层次共享或隔离配置

1、有无Spring上下文的对比分析

能力维度无上下文(BeanFactory)有上下文(ApplicationContext)
依赖注入基础Bean管理支持完整Bean生命周期管理
资源配置需手动处理资源路径统一资源抽象(ResourceLoader)
国际化无内置支持多语言消息源(MessageSource)
事件机制需自定义实现内置发布-订阅模型
容器结构单一容器支持父子容器层次
AOP集成手动代理创建声明式切面支持
与框架集成困难Spring MVC/Spring Boot无缝集成

在Spring Boot和Spring Cloud等现代框架中,上下文设计进一步演进出层次化容器结构。当使用SpringApplicationBuilder构建应用时,会自动创建父子上下文层次:Bootstrap上下文作为父容器,主应用上下文作为子容器。这种设计使得:

  1. 配置继承:子容器可以访问父容器的属性源,实现配置共享
  2. 隔离与覆盖:子容器可定义同名属性覆盖父容器配置
  3. 多级扩展:通过parent(), child(), sibling()方法构建复杂容器关系
  4. 模块化部署:不同模块可使用独立上下文,通过父子关系共享基础服务

这种层次化设计在微服务架构中尤为重要。例如在Spring Cloud应用中,Bootstrap上下文负责加载外部配置中心参数,主应用上下文则处理业务Bean初始化,二者分离既保证配置优先加载,又避免环境污染。

2、解耦悖论

Spring模块化设计的初衷是解耦,但上下文模块的出现,似乎让上下文模块成了核心依赖,那么岂不是违背了解耦的初衷。

确实,Spring各模块(如AOP、事务、数据访问)都需要访问ApplicationContext获取Bean或环境信息,形成了事实上的中心依赖点。但这并不违背解耦原则,原因在于:

  1. 依赖抽象而非实现
    所有模块依赖的是ApplicationContext接口(定义在spring-context模块),而非具体实现类。这种接口隔离确保了模块间通过契约交互:

  1. 上下文本质是“集成中枢”
    上下文不是业务组件,而是基础设施层。就像操作系统为应用提供统一API,Spring上下文为模块提供:
    • 环境配置(Environment)
    • 依赖查找(getBean())
    • 资源抽象(ResourceLoader)
    • 事件机制(ApplicationEventPublisher)

这种中心化服务提供是框架的必然设计。

二、核心组件与职能划分

通过以上了解,所以在Spring上下文模块的设计上,要注重设计接口分层和类继承体系,且要实现功能的高内聚和低耦合。以下从核心接口、实现类和支撑技术三个维度进行分析设计

组件类型关键类/接口主要职责实现技术
核心接口ApplicationContext容器基本功能定义接口聚合
ConfigurableApplicationContext生命周期和配置扩展生命周期方法
WebApplicationContextWeb环境扩展ServletContext集成
实现类AbstractApplicationContext容器刷新模板实现模板方法模式
GenericApplicationContext轻量级通用容器组合BeanFactory
AnnotationConfigApplicationContext注解配置支持注解扫描解析
EmbeddedWebApplicationContext内嵌Web容器支持Servlet3.0+API
支撑组件Environment环境配置抽象PropertySource体系
BeanDefinitionRegistryBean定义动态注册Bean元数据操作
ApplicationEventMulticaster事件广播机制观察者模式
ResourcePatternResolver资源加载策略路径匹配解析

1. 核心接口体系

  • ApplicationContext (核心容器接口):设计一个上下文模块的根基接口,集成多个基础接口能力,定义容器的基本行为。它继承BeanFactory提供Bean管理能力,ResourcePatternResolver支持资源加载,ApplicationEventPublisher实现事件推送,MessageSource处理国际化消息。这种接口聚合设计避免了继承爆炸问题。
  • ConfigurableApplicationContext (可配置上下文):扩展ApplicationContext,增加生命周期控制start(), stop(), close())和配置能力(设置父容器、注册关闭钩子等)。它是所有可写上下文的契约接口,为子类提供可定制入口点。
  • WebApplicationContext (Web环境扩展):专为Web应用设计,增加getServletContext()方法获取Servlet上下文,提供Web作用域Bean支持(request/session/application)。

2. 关键实现类

  • AbstractApplicationContext (抽象模板实现):可作为所有具体上下文的骨架实现,采用模板方法模式定义上下文初始化的标准流程,尤其是refresh()方法的实现是整个Spring容器启动的核心。其关键方法包括:
// 模板方法定义容器刷新流程
@Override
public void refresh() throws BeansException, IllegalStateException {this.startupShutdownLock.lock();try {this.startupShutdownThread = Thread.currentThread();StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.// 准备此上下文以刷新。prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 告诉子类刷新内部bean工厂ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// 准备好bean工厂以便在上下文中使用prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子类可以对bean工厂进行后处理,比如注册一些bean处理器、注册一些监听器、注册一些事件处理器等。postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.// 调用工厂处理器,这些处理器是作为bean在context中注册的。invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 注册Bean后置处理器registerBeanPostProcessors(beanFactory);beanPostProcess.end();// Initialize message source for this context.// 初始化消息源initMessageSource();// Initialize event multicaster for this context.// 初始化事件多播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 子类扩展点onRefresh();// Check for listener beans and register them.// 注册事件监听器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 实例化所有剩余的(非懒加载)单例。finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 最后一步:发布对应的事件finishRefresh();}catch (RuntimeException | Error 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 {contextRefresh.end();}}finally {this.startupShutdownThread = null;this.startupShutdownLock.unlock();}
}
  • GenericApplicationContext (通用配置上下文):基于组合优于继承原则设计的轻量级实现,内部持有DefaultListableBeanFactory实例,避免了复杂的继承层次。适合基于Java配置的应用场景,是AnnotationConfigApplicationContext的基类。

  • AnnotationConfigWebApplicationContext (注解驱动Web上下文):专为Servlet环境设计的注解配置上下文,支持通过@Configuration类定义Bean,自动扫描@Component组件。内部使用AnnotatedBeanDefinitionReader解析注解配置。

3. 支撑性技术组件

  • Environment抽象 (环境配置):通过Environment接口和PropertySource抽象,统一管理配置属性源(系统变量、环境变量、配置文件等),支持Profile条件装配。在上下文层次结构中,子容器通过Environment.merge()合并父容器环境。
  • BeanDefinitionRegistry (Bean定义注册):提供动态注册Bean定义的能力,允许在运行时修改容器元数据。GenericApplicationContext直接实现此接口,支持编程式Bean注册。
  • ApplicationEventMulticaster (事件广播器):作为观察者模式的核心实现,管理事件监听器列表,支持同步/异步事件分发。默认使用SimpleApplicationEventMulticaster实现,可通过TaskExecutor扩展为异步模式。

三、核心设计模式应用

1. 代理模式:功能委托与扩展

代理模式在上下文设计中应用广泛,主要体现在功能解耦职责分离两方面。AbstractApplicationContext内部通过多个代理组件实现功能委托。

这种设计带来两大优势:

  1. 灵活性:可动态替换代理实现(如将SimpleApplicationEventMulticaster替换为异步广播器)
  2. 可扩展性:子类只需覆盖initApplicationEventMulticaster()等初始化方法即可定制组件
public abstract class AbstractApplicationContext {// 消息代理@Nullableprivate MessageSource messageSource;// 事件广播器代理@Nullableprivate ApplicationEventMulticaster applicationEventMulticaster;// 资源解析器代理private ResourcePatternResolver resourcePatternResolver;@Overridepublic String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {// 委托给messageSource处理return getMessageSource().getMessage(code, args, defaultMessage, locale);}@Overridepublic void publishEvent(ApplicationEvent event) {// 委托给applicationEventMulticaster广播事件getApplicationEventMulticaster().multicastEvent(event);}
}

2. 模板方法模式:容器生命周期标准化

AbstractApplicationContext.refresh()方法是模板方法模式的典范,定义了容器初始化的12步标准流程,但将关键步骤设计为可扩展点

  1. 可覆盖方法:如postProcessBeanFactory()onRefresh()等protected方法允许子类扩展
  2. 抽象方法:如obtainFreshBeanFactory()强制子类提供具体实现
  3. 钩子方法:如registerBeanPostProcessors()提供默认实现,子类可选择覆盖

这种设计使Spring能够支持多样化的配置方式(XML、注解、Groovy等),同时保持核心初始化流程的统一性。例如ClassPathXmlApplicationContext通过覆盖loadBeanDefinitions()方法实现XML解析:

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {// 创建XML解析器XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);// 加载XML配置reader.loadBeanDefinitions(getConfigLocations());}
}

3. 组合模式:容器层次结构构建

Spring通过组合模式实现容器层次结构,ApplicationContext接口提供getParent()方法获取父容器引用。这种设计在Web应用中尤为重要:

public class CustomWebApplicationInitializer implements WebApplicationInitializer {public void onStartup(ServletContext servletContext) {// 创建父容器(服务层Bean)AnnotationConfigApplicationContext rootContext = new AnnotationConfigApplicationContext();rootContext.register(ServiceConfig.class);rootContext.refresh();// 创建子容器(Web层Bean)AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();webContext.setParent(rootContext); // 设置父子关系webContext.register(WebConfig.class);// 将子容器关联到DispatcherServletDispatcherServlet servlet = new DispatcherServlet(webContext);ServletRegistration.Dynamic reg = servletContext.addServlet("app", servlet);}
}

在此结构中:

  1. Web层容器可访问父容器的Bean(如Service组件)
  2. 父容器无法访问子容器Bean,实现关注点分离
  3. 配置隔离:各层容器可独立配置自己的Bean作用域

4. 观察者模式:事件驱动机制

Spring的事件模型是观察者模式的典型应用,由三个核心组件构成:

  1. ApplicationEvent:事件对象(如ContextRefreshedEvent, RequestHandledEvent
  2. ApplicationListener:事件监听器接口
  3. ApplicationEventMulticaster:事件广播中心

具体应用示例:

// 1. 定义自定义事件
public class UserModifyEvent extends ApplicationEvent {public UserModifyEvent(Object source) {super(source);}
}// 2. 创建事件监听器
@Component
public class UserModifyListener implements ApplicationListener<UserModifyEvent> {@Overridepublic void onApplicationEvent(UserModifyEvent event) {// 处理更新事件逻辑}
}// 3. 发布事件
@Service
public class UserService {@Autowiredprivate ApplicationEventPublisher publisher;public void updateUser(User user) {// 业务逻辑...publisher.publishEvent(new UserModifyEvent(this));}
}

这种松耦合通信机制使业务组件无需直接引用即可交互,增强系统可维护性。

5. 策略模式:可插拔组件实现

上下文模块中多处应用策略模式实现算法可替换:

  • 资源加载ResourcePatternResolver作为策略接口,PathMatchingResourcePatternResolver是其默认实现
  • 环境管理Environment接口抽象环境策略,StandardEnvironmentStandardServletEnvironment提供不同实现
  • 属性解析PropertyResolver定义属性解析策略,PropertySourcesPropertyResolver基于PropertySources实现

策略模式使Spring能够适应不同运行环境。例如在测试环境中可替换为模拟策略:

public class TestApplicationContext extends GenericApplicationContext {@Overrideprotected ConfigurableEnvironment createEnvironment() {// 返回测试专用的环境策略return new MockEnvironment();}
}

四、高级特性与应用实践

1. 层次化容器设计

Spring的容器层次结构不仅仅是父子关系,而是支持多级嵌套交叉引用的复杂拓扑。在Spring Cloud环境中,这种设计发挥到极致:

Bootstrap Context (最高级)||--- Application Context (主应用)||--- Web MVC Context (Web模块)||--- Batch Context (批处理模块)

属性解析规则在这种层次结构中遵循:

  1. 优先子级:子容器属性覆盖父容器同名属性
  2. 源独立性:每个容器维护独立的属性源(bootstrap, application等)
  3. 名称空间隔离:相同属性源名称在不同层级互不影响

通过SpringApplicationBuilder可编程式构建此结构:

new SpringApplicationBuilder().parent(ParentConfig.class).web(WebApplicationType.NONE) // 父容器.child(WebConfig.class).web(WebApplicationType.SERVLET)  // 子容器.sibling(BatchConfig.class).web(WebApplicationType.NONE) // 兄弟容器.run(args);

2. 环境抽象与配置管理

Environment抽象是Spring上下文的核心创新,通过PropertySource体系统一管理配置源:

  1. 层次化覆盖:子容器环境自动合并父容器环境,子级PropertySource优先
  2. 动态配置:通过@PropertySource注解动态添加配置源
  3. Profile激活:条件化加载Bean定义,实现环境适配

在Spring Boot中,属性加载顺序的精心设计体现了环境抽象的威力:

  1. 默认属性(通过SpringApplication.setDefaultProperties设置)
  2. @Configuration类上的@PropertySource
  3. 配置数据(application.properties/YAML)
  4. 操作系统环境变量
  5. JVM系统属性

3. 条件化装配机制

Spring 4.0引入的@Conditional注解将条件判断提升到元编程级别,成为Spring Boot自动配置的基石。其扩展应用包括:

  • Profile条件@Profile底层基于@Conditional实现
  • 属性条件@ConditionalOnProperty根据属性存在性/值决定装配
  • 资源条件@ConditionalOnResource检测资源存在性
  • Bean条件@ConditionalOnBean/@ConditionalOnMissingBean根据容器中Bean存在性决策

自定义条件示例:

public class ClusterModeCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 从环境获取运行模式String mode = context.getEnvironment().getProperty("cluster.mode");// 仅当模式为"high-availability"时匹配return "high-availability".equalsIgnoreCase(mode);}
}// 使用自定义条件装配
@Configuration
@Conditional(ClusterModeCondition.class)
public class ClusterConfig {@Beanpublic ClusterService clusterService() {return new HighClusterService();}
}

4. 上下文生命周期管理

上下文的生命周期由ConfigurableApplicationContext接口严格定义,核心阶段包括:

  1. 初始化:构造上下文实例,设置配置源
  2. 准备刷新prepareRefresh()初始化环境属性
  3. Bean工厂创建obtainFreshBeanFactory()加载Bean定义
  4. 后处理:执行BeanFactoryPostProcessor
  5. Bean实例化:注册BeanPostProcessor,初始化单例
  6. 完成刷新:发布ContextRefreshedEvent
  7. 运行中:处理请求/调用
  8. 关闭:发布ContextClosedEvent,销毁Bean

生命周期事件为应用提供关键扩展点:

  • ContextStartedEvent:上下文启动后
  • ContextStoppedEvent:上下文停止后
  • ContextRefreshedEvent:上下文完全刷新
  • ContextClosedEvent:上下文关闭

五、设计总结与启示

Spring上下文模块经过多年演进形成的架构,体现了以下核心设计哲学:

  1. 可扩展性设计:通过模板方法模式定义骨架流程,预留扩展点(如postProcessBeanFactory())允许子类定制特定步骤。这种设计使Spring能无缝支持XML、注解、Groovy等多种配置方式,同时保持核心流程稳定。
  2. 关注点分离:采用代理模式将消息、事件、资源等功能委托给专门组件,确保核心容器职责单一。例如ApplicationEventMulticaster专注事件广播,MessageSource处理国际化,各组件通过接口契约协作。
  3. 层次化抽象:通过组合模式构建容器父子关系,实现配置继承与覆盖。在微服务架构中,这种设计衍生出Bootstrap上下文、主应用上下文、Web上下文的层级结构,为Spring Cloud的配置管理、服务发现等提供基础设施。

在现代云原生应用开发中,上下文设计启示我们:

  • 环境适配:通过Environment抽象统一管理配置源,使应用可无缝迁移到不同环境(本地、测试、生产)
  • 条件化装配:基于@Conditional的自动配置机制大幅减少样板代码
  • 事件驱动:内置事件模型支持响应式编程,增强组件解耦
  • 生命周期管理:标准化的生命周期使框架扩展更可控

Spring上下文模块的成功证明:强大的抽象能力合理的分层设计是框架灵活性的基石。其设计思想不仅适用于Java生态系统,对任何复杂框架的开发都具有参考价值。随着Spring 6和Spring Boot 3的演进,响应式上下文、原生镜像支持等新特性将继续拓展上下文设计的边界,为开发者提供更强大的企业级支持。

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

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

相关文章

keil5怎么关闭工程

在project里面有一个close project&#xff0c;点击后就关掉了&#xff0c;之前还按照其他软件的操作习惯&#xff0c;右键工程选项&#xff0c;但是始终没有发现关闭选项。

腾讯云:6月30日起,自动禁用,及时排查

大家好&#xff0c;我是小悟。 腾讯云发布公告&#xff0c;宣布从2025年6月30日开始&#xff0c;对长期未使用的AccessKey&#xff08;API访问密钥&#xff09;进行自动禁用。 简单来说&#xff0c;如果你的密钥在90天内没动静&#xff0c;系统就会把它关掉&#xff0c;不管是…

【C++】多重继承与虚继承

多重继承与虚继承 1.单继承和多重继承的区别2.语法规则示例代码&#xff1a;多重继承子类指定父类的构造示例代码&#xff1a;多重继承子类隐藏父类的同名方法 3.虚继承解决多重继承遇到的bug示例代码&#xff1a;环状继承引发的问题 3.1 虚基类&#xff1a;3.2 语法规则&#…

GCC编译/连接/优化等选项

1. GCC编译/连接/优化等选项 1. GCC编译/连接/优化等选项 1.1. 简介1.2. 常用选项 1.2.1. -c -E -S -o1.2.2. -L<path> -l<library>1.2.3. -D<macro>1.2.4. -I<path> 1.3. 代码生成和优化 1.3.1. -std<standard>1.3.2. -shared1.3.3. -fPIC1.3.…

FFmpeg 压缩视频文件

文章目录 FFmpeg 压缩视频文件基本压缩命令&#xff08;保持 MP4 格式&#xff09;转换为其他格式示例&#xff1a;关键参数说明&#xff1a;额外优化选项&#xff1a; 在FFmpeg中使用多线程加速1. 帧级多线程 (frame-level multithreading)2. 切片级多线程 (slice-level multi…

Ubuntu 系统通过防火墙管控 Docker 容器

Ubuntu 系统通过防火墙管控 Docker 容器指南 一、基础防火墙配置 # 启用防火墙 sudo ufw enable# 允许 SSH 连接&#xff08;防止配置过程中断联&#xff09; sudo ufw allow 22/tcp二、Docker 配置调整 # 编辑 Docker 配置文件 sudo vim /etc/docker/daemon.json配置文件内…

虚拟机新增硬盘,与数据挂载

我有个虚拟机&#xff0c;当时选择了独立文件&#xff0c;现在遇到个问题&#xff0c;硬盘不够了&#xff0c;索性加了一个新硬盘&#xff0c;现在想把数据库的数据映射到这个新的硬盘处理。 罗列硬盘 lsblk我得是sdb是新硬盘 2. 分区 sudo fdisk /dev/sdb交互操作&#xff…

go语言学习 第10章:面向对象编程

第10章&#xff1a;面向对象编程 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来表示数据和方法&#xff0c;并通过类来定义对象的结构和行为。Go语言虽然不是传统的面向对象语言&#xff0c;但它通过结构体&#xff08;struct&#xff…

android计算器代码

本次作业要求实现一个计算器应用的基础框架。以下是布局文件的核心代码&#xff1a; <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"andr…

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…

我们来学mysql -- 8.4版本记录慢查询

记录慢查询 开启慢查询的配置查看慢查询状态动态开启慢查询日志永久开启配置log_throttle_queries_not_using_indexes 记录慢查询对性能的影响实际案例说明第一条记录第二条记录第三条记录第四条记录 开启慢查询的配置 查看慢查询状态 - 执行 show variables like slow_quer…

2025 年中国大学生程序设计竞赛全国邀请赛(郑州)暨第七届CCPC河南省大学生程序设计竞赛(补题)

文章目录 前言F、幻形之路G、直径与最大独立集H&#xff0c;树论函数M&#xff0c; 川陀航空学院总结 前言 本次比赛&#xff0c;只能说太多没接触的知识了&#xff0c;还有太容易被题面吓住。 F、幻形之路 题目链接&#xff1a;幻形之路 解题思路&#xff1a; 对于这一题只…

如何使用k8s安装redis呢

在Kubernetes (k8s) 上安装Redis 在Kubernetes上安装Redis有几种方法&#xff0c;下面我将介绍两种常见的方式&#xff1a;使用StatefulSet直接部署和使用Helm chart部署。 一、安装redis 1.1 拉去ARM镜像&#xff08;7.4.2&#xff09; docker pull registry.cn-hangzhou.ali…

SpringBoot的5种日志输出规范策略

在企业级应用开发中&#xff0c;合理规范的日志记录是系统稳定运行、问题排查和性能优化的关键保障。 SpringBoot作为流行的Java开发框架&#xff0c;提供了强大而灵活的日志支持&#xff0c;但如何建立统一、高效的日志输出规范却是许多团队面临的挑战。 本文将介绍SpringBo…

Python Cookbook-7.11 在 PostgreSQL 中储存 BLOB

任务 需要将 BLOB 存入一个 PostgreSQL 数据库。 解决方案 PostgreSQL7.2 以及更新的版本支持大对象,而psycopg 模块提供了二进制转义函数: import psycopg,cPickle #连接到数据库,用你的本机来测试数据库,并获得游标 connection = psycopg.connect("dbname = test…

Android端口转发

如上图所示&#xff0c;有一个Android设备&#xff0c;Android设备里面有主板&#xff0c;主板上有网络接口和Wi-Fi&#xff0c;网络接口通过网线连接了一个网络摄像头&#xff0c;这就跟电脑一样&#xff0c;电脑即可以通过网线接入一个网络&#xff0c;也可以同时用Wi-Fi接入…

Unity基础-协程

Unity基础-协程 四、协程 概述 协程&#xff08;Coroutine&#xff09;&#xff0c;本质上并不是多线程&#xff0c;而是在当前线程中将代码分时执行&#xff0c;不卡主线程。可以理解为&#xff0c;协程会把可能使主线程卡顿的程序分时分布进行。 协程通常用来&#xff1a;…

UniApp组件封装,2025年最新HarmonyOS鸿蒙模块化开发项目式教程

一、环境配置与前置条件 ‌开发工具要求‌ HBuilderX 4.64&#xff08;鸿蒙插件已预装&#xff09;DevEco Studio 5.0.3.400&#xff08;真机调试必备&#xff09;鸿蒙离线SDK&#xff08;通过HBuilderX导入&#xff0c;每个项目独立配置&#xff09; ‌项目初始化 # 创建Vu…

C++ 精简知识点

目录 一、核心语法 1.指针VS引用 2. 类与对象&#xff08;必写代码&#xff09; 3. 继承与多态&#xff08;必写代码&#xff09; 4. 模板&#xff08;必写代码&#xff09; 5.智能指针 6. 异常处理&#xff08;必写结构&#xff09; 二、简答题速记 三、考试应急策略 一…

7.Vue的compute计算属性

3.8. 【computed】 作用&#xff1a;根据已有数据计算出新数据&#xff08;和Vue2中的computed作用一致&#xff09;。 <template><div class"person">姓&#xff1a;<input type"text" v-model"firstName"> <br>名&am…