聚焦IOC容器刷新环节postProcessBeanFactory(BeanFactory后置处理)专项

目录

一、IOC容器的刷新环节快速回顾

二、postProcessBeanFactory源码展示分析

(一)模版方法postProcessBeanFactory

(二)AnnotationConfigServletWebServerApplicationContext

调用父类的 postProcessBeanFactory

包扫描

注解类注册

(三)postProcessBeanFactory 主要功能

三、调用父类方法以继承基础设置和逻辑

(一)重要任务回顾

(二)注册 WebApplicationContextServletContextAwareProcessor

(三)忽略 ServletContextAware 接口的依赖

(四)注册 Web 应用程序范围

ExistingWebApplicationScopes 的角色

注册 Web 应用程序作用域

四、执行包扫描

五、注解类注册

(一)扫描和注册注解类的过程步骤

扫描注解类

创建 BeanDefinition

注册 BeanDefinition

(二)对注解类注册的理解新思路

新的思路

六、总结


干货分享,感谢您的阅读!

在很早之前我们单独写过一篇文章《分析SpringBoot启动配置原理》,具体可见:

分析SpringBoot启动配置原理_spring启动加载顺序及原理-CSDN博客文章浏览阅读1.6w次,点赞15次,收藏43次。分析SpringBoot启动配置原理:给出整体初步分析和对应流程图,并从三方面进行展开分析(SpringApplication构造过程分析+SpringApplication启动过程分析+SpringBoot自动配置分析)_spring启动加载顺序及原理icon-default.png?t=O83Ahttps://blog.csdn.net/xiaofeng10330111/article/details/130903779?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171829487016800213028572%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171829487016800213028572&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-130903779-null-null.nonecase&utm_term=%E5%88%86%E6%9E%90SpringBoot%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86&spm=1018.2226.3001.4450其中IOC容器的刷新环节可当重点分析,值得在读源码时进行深入分析,我们会从多个方向上再次进行分析回顾和学习。历史其他专项展示:

具体内容具体链接
探究Spring BeanFactory重看Spring聚焦BeanFactory分析_java beanfactory 实现类-CSDN博客
探究Spring ApplicationContext重看Spring聚焦ApplicationContext分析_applicationcontext消息资源处理-CSDN博客
ApplicationContext vs BeanFactory解锁ApplicationContext vs BeanFactory: 谁更具选择性?-CSDN博客
探究Spring Environment重看Spring聚焦Environment分析-CSDN博客
探究Spring BeanDefintion重看Spring聚焦BeanDefinition分析和构造-CSDN博客
对焦后置处理器聚焦Spring后置处理器分析对比_spring的后置处理器分析-CSDN博客
BeanFactory - obtainFreshBeanFactory专项聚焦IOC容器刷新环节obtainFreshBeanFactory初始化BeanFactory专项_refreshbeanfactory-CSDN博客
prepareBeanFactory专项聚焦IOC容器刷新环节prepareBeanFactory专项-CSDN博客

一、IOC容器的刷新环节快速回顾

我们将AbstractApplicationContext的refresh方法源码提取并进行重点代码标注说明如下:

public abstract class AbstractApplicationContext implements ApplicationContext {@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 准备上下文环境,包括初始化工厂、后置处理器等prepareRefresh();// 创建并初始化 BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 设置 BeanFactory 的类加载器、资源加载器等prepareBeanFactory(beanFactory);try {// 允许子类对 BeanFactory 进行进一步的自定义处理postProcessBeanFactory(beanFactory);// 调用 BeanFactoryPostProcessors 进行后置处理invokeBeanFactoryPostProcessors(beanFactory);// 注册 BeanPostProcessors,用于对 Bean 实例进行后置处理registerBeanPostProcessors(beanFactory);// 初始化消息源initMessageSource();// 初始化事件广播器initApplicationEventMulticaster();// 初始化其他特殊 BeanonRefresh();// 注册关闭钩子registerListeners();// 初始化所有剩余的单例 BeanfinishBeanFactoryInitialization(beanFactory);// 完成上下文刷新finishRefresh();} catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// 销毁已创建的 Bean,关闭容器destroyBeans();// 重置容器刷新标志,允许再次刷新cancelRefresh(ex);// 把异常重新抛出,允许调用者处理throw ex;} finally {// 重置已注册的 JVM 关闭钩子resetCommonCaches();}}}
}

以上内容请多次翻看并理解(如果忘记了最好在次读一下之前的原文博客进行基本的回顾),我们本次讲聚焦其中的postProcessBeanFactory专项展开分析。

二、postProcessBeanFactory源码展示分析

postProcessBeanFactory 是一个允许子类在 BeanFactory 完成初始化之后但在 Bean 实例化之前对其进行进一步自定义的钩子方法。虽然在 AbstractApplicationContext 中该方法是一个空实现(该方法就是一个模版方法),但子类可以覆盖此方法以添加特定的逻辑。

(一)模版方法postProcessBeanFactory

AbstractApplicationContext 类中,postProcessBeanFactory 方法定义如下:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 默认实现为空,子类可以覆盖此方法进行自定义处理
}

直观的看下有哪些子类进行了具体的实现:

以上是几个常见子类对 postProcessBeanFactory 方法的具体实现,我们一般探究其中一个即可理解体会,其他可当作扩展去学习。

(二)AnnotationConfigServletWebServerApplicationContext

我们以AnnotationConfigServletWebServerApplicationContext为基本去体会一下

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}
}

调用父类的 postProcessBeanFactory

super.postProcessBeanFactory(beanFactory);

确保父类 postProcessBeanFactory 方法中的所有逻辑都会被执行。通过调用父类的方法,继承了父类的初始化和处理逻辑,常包括一些基本的设置和注册操作,为后续的自定义逻辑打下基础。

包扫描

if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);
}

this.scanner 是一个 ClassPathBeanDefinitionScanner 实例,它负责扫描指定的包路径 (basePackages),从而找到并注册符合条件的 Bean,它会扫描指定的包路径,寻找符合条件的组件类(如带有 @Component@Service@Repository@Controller 注解的类),并将它们注册为 Bean 定义。

注解类注册

if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}

this.reader 是一个 AnnotatedBeanDefinitionReader 实例,它负责将指定的注解类 (annotatedClasses,如带有 @Configuration@Component 注解的类) 注册到 BeanFactory 中,从而使这些类能够参与到 Spring 的依赖注入和生命周期管理中。ClassUtils.toClassArray将一个 Set<Class<?>> 转换为一个 Class<?>[] 数组,这个转换在将注解类注册到 AnnotatedBeanDefinitionReader 中时非常有用。 

(三)postProcessBeanFactory 主要功能

从上述分析可以看出,在 Spring IOC 容器中,postProcessBeanFactory 方法的主要功能可归纳为:

  1. 调用父类方法以继承基础设置和逻辑: 确保基本的设置和注册操作在子类中得到执行。

  2. 进行包扫描: 扫描指定的包路径,自动发现并注册符合条件的组件类,可以通过注解配置的方式管理 Bean,减少手动注册的工作量。

  3. 注册注解类: 将特定的注解类注册到 BeanFactory 中,使其参与到 Spring 的依赖注入和生命周期管理中。

三、调用父类方法以继承基础设置和逻辑

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(ServletContextAware.class);this.registerWebApplicationScopes();
}

(一)重要任务回顾

postProcessBeanFactory 方法主要完成了以下几个重要任务:

  1. 注册 WebApplicationContextServletContextAwareProcessor: 添加一个 BeanPostProcessor,处理实现了 ServletContextAware 接口的 bean,注入 ServletContext 对象。

  2. 忽略 ServletContextAware 接口的依赖: 告诉 BeanFactory 忽略对 ServletContextAware 接口的自动依赖注入。

  3. 注册 Web 应用程序范围: 注册与 Web 应用程序相关的作用域,使得 bean 可以在 requestsessionapplication 范围内被管理。

这些步骤使得 Spring 容器能够更好地支持 Web 应用程序的特定需求,为处理 HTTP 请求、会话管理和应用程序范围内的 bean 提供了必要的基础设施。

(二)注册 WebApplicationContextServletContextAwareProcessor

WebApplicationContextServletContextAwareProcessor 类实现了 BeanPostProcessor 接口,用于在 bean 初始化之前和之后进行自定义的处理。

public class WebApplicationContextServletContextAwareProcessor implements BeanPostProcessor {private final WebApplicationContext webApplicationContext;public WebApplicationContextServletContextAwareProcessor(WebApplicationContext webApplicationContext) {this.webApplicationContext = webApplicationContext;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof ServletContextAware) {((ServletContextAware) bean).setServletContext(this.webApplicationContext.getServletContext());}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

这个类主要的作用是处理实现了 ServletContextAware 接口的 bean,并将 ServletContext 注入到这些 bean 中。

(三)忽略 ServletContextAware 接口的依赖

ignoreDependencyInterface 方法的作用是告诉 BeanFactory 在处理自动装配时忽略特定接口的依赖注入。也就是说,当 BeanFactory 遇到实现了该接口的 bean 时,不会自动尝试注入该接口的依赖。

public interface ServletContextAware {void setServletContext(ServletContext servletContext);
}

ServletContextAware 是一个标记接口,用于获取 ServletContext 对象。实现了该接口的 bean 需要 ServletContext,这在 Web 应用程序中非常常见。

如果不忽略 ServletContextAware 接口的依赖,Spring 容器在创建 bean 时会尝试自动注入 ServletContext 对象。然而,在 Spring 的设计中,ServletContext 的注入通常是通过 BeanPostProcessor 来处理的,而不是通过自动装配。因此,需要忽略该接口的自动依赖注入,防止 Spring 容器在自动装配时出错。

(四)注册 Web 应用程序范围

private void registerWebApplicationScopes() {ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(this.getBeanFactory());WebApplicationContextUtils.registerWebApplicationScopes(this.getBeanFactory());existingScopes.restore();}

Spring 提供了几种标准的 Web 应用程序作用域:

  • Request Scope(请求作用域):每个 HTTP 请求都会创建一个新的 bean 实例,该 bean 在请求结束时被销毁。适合存储与单个请求相关的数据,如表单数据或请求参数处理器。

  • Session Scope(会话作用域):每个 HTTP 会话期间创建一个 bean 实例,该 bean 在会话结束时被销毁。适合存储需要在用户会话期间保持状态的数据,如用户登录信息或购物车内容。

  • Application Scope(应用程序作用域):整个 Web 应用程序中仅创建一个 bean 实例,该 bean 与 ServletContext 绑定。适合存储全局配置信息或共享的资源,如全局缓存或系统配置。

ExistingWebApplicationScopes 的角色

public static class ExistingWebApplicationScopes {private static final Set<String> SCOPES;private final ConfigurableListableBeanFactory beanFactory;private final Map<String, Scope> scopes = new HashMap();public ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {this.beanFactory = beanFactory;Iterator var2 = SCOPES.iterator();while(var2.hasNext()) {String scopeName = (String)var2.next();Scope scope = beanFactory.getRegisteredScope(scopeName);if (scope != null) {this.scopes.put(scopeName, scope);}}}public void restore() {this.scopes.forEach((key, value) -> {if (ServletWebServerApplicationContext.logger.isInfoEnabled()) {ServletWebServerApplicationContext.logger.info("Restoring user defined scope " + key);}this.beanFactory.registerScope(key, value);});}static {Set<String> scopes = new LinkedHashSet();scopes.add("request");scopes.add("session");SCOPES = Collections.unmodifiableSet(scopes);}}

ExistingWebApplicationScopes 类的主要作用在于管理和保护已有的自定义作用域配置。它通过以下方式实现:

  • 保存当前状态: 在初始化时,ExistingWebApplicationScopes 会获取当前注册的作用域信息并保存到内部的 scopes 映射中。这包括了所有已定义的作用域,如 "request""session"

  • 恢复状态: 在需要时,比如在注册标准 Web 应用程序作用域之后,ExistingWebApplicationScopes 可以恢复之前保存的作用域配置。这样可以确保注册标准作用域不会覆盖或修改已有的自定义作用域定义。

在技术实现上,ExistingWebApplicationScopes 利用 Spring 框架提供的 ConfigurableListableBeanFactory 接口来管理作用域信息。它通过迭代已定义的标准作用域集合(如 "request""session")并与实际注册的作用域进行匹配,来确保作用域配置的一致性和正确性。

注册 Web 应用程序作用域

WebApplicationContextUtils.registerWebApplicationScopes() 方法在 Spring 框架中用于注册与 Web 应用程序相关的标准作用域,如 "request""session""application"

public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {registerWebApplicationScopes(beanFactory, (ServletContext)null);}public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) {beanFactory.registerScope("request", new RequestScope());beanFactory.registerScope("session", new SessionScope());if (sc != null) {ServletContextScope appScope = new ServletContextScope(sc);beanFactory.registerScope("application", appScope);sc.setAttribute(ServletContextScope.class.getName(), appScope);}beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());if (jsfPresent) {WebApplicationContextUtils.FacesDependencyRegistrar.registerFacesDependencies(beanFactory);}}

registerWebApplicationScopes() 方法的主要任务是确保 BeanFactory 支持这些标准的 Web 应用程序作用域:

  • 注册作用域实例: 方法会向 BeanFactory 中注册相应的作用域实例,如 RequestScopeSessionScopeServletContextScope

  • 配置作用域支持: 如果 BeanFactory 尚未配置支持这些作用域,方法可能会进行配置以确保它们能够正确地管理和维护这些作用域。

  • 确保作用域生命周期管理: 对于每种作用域,Spring 确保在适当的时机创建、销毁和管理 bean 实例。例如,在请求结束后销毁请求作用域的 bean 实例,以避免内存泄漏和资源浪费。

 registerWebApplicationScopes() 方法的实现会调整 BeanFactory,以便能够正确地管理和控制这些作用域,确保了在多用户、多请求的环境中,每个 bean 实例都能按预期的方式进行创建和销毁,从而保证了应用程序的稳定性和性能。

四、执行包扫描

    // 执行包扫描,自动注册符合条件的组件类if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}

 通过包扫描,Spring 可以自动发现项目中符合特定条件的类,这些类通常被标注了诸如 @Component@Service@Controller 等注解,或者是配置类,其避免了手动在配置文件中一一列出每个需要注册的 Bean,减少了配置的工作量。

根据配置的条件(如 this.basePackages),扫描器可以只扫描特定的包路径,而非整个类路径,从而精确地控制哪些类需要被注册为 Bean。

scanner 是一个专门用于扫描指定包路径下类的工具或组件。它能够递归地搜索指定包及其子包中的类文件。一旦扫描器发现符合条件的类,Spring 将调用相应的注册方法将这些类注册为 Bean。

对于每个扫描到的类,Spring 将创建一个对应的 BeanDefinition,用于后续的 Bean 实例化和依赖注入。 

 应用场景和实际意义

  • 模块化开发:通过自动注册,不同模块的组件可以自动装配,降低了模块间耦合度。
  • 动态可扩展性:允许开发者通过简单地添加新的组件类(如新的 @Component 类)来扩展应用的功能,而不需要修改现有的配置文件。 

执行包扫描并自动注册符合条件的组件类是 Spring 框架中支持依赖注入和面向组件的核心功能之一,通过简化配置提高开发效率。

五、注解类注册

    // 注册额外的注解配置类if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}

注册注解类的主要目的是让 Spring 容器能够识别和管理这些类,将其纳入到整个应用程序的 Bean 管理体系中。通过这种方式,注解类可以享受 Spring 提供的各种功能,如依赖注入(DI)、面向方面编程(AOP)、生命周期回调等。

(一)扫描和注册注解类的过程步骤

postProcessBeanFactory 方法中,通过扫描和注册注解类的过程可以分为以下几个步骤:

扫描注解类

首先,Spring 会扫描指定包路径下的类,找到所有带有特定注解的类。Spring 中的扫描器通常是 ClassPathBeanDefinitionScanner,它能够递归地扫描指定包路径下的类文件,并根据配置的过滤条件(如注解)决定是否将其注册为 Bean。

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
scanner.scan(basePackages);

常见的注解包括:

  • @Component
  • @Service
  • @Repository
  • @Controller
  • 其他自定义注解

这些注解用于标识该类是一个 Spring 管理的组件。这部分其实是上一节中讲解的。

创建 BeanDefinition

对于每一个扫描到的注解类,Spring 会创建一个 BeanDefinition 对象。BeanDefinition 描述了 Bean 的各种属性和元数据,如 Bean 的类名、作用域、初始化和销毁方法等。

扫描器在找到符合条件的类后,会调用 AnnotatedBeanDefinitionReader 或类似的类来创建 BeanDefinition

AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);
reader.register(annotatedClasses.toArray(new Class[0]));

注册 BeanDefinition

创建好 BeanDefinition 之后,Spring 会将其注册到 BeanFactory 中。这一步骤通常由 BeanDefinitionRegistry 接口的 registerBeanDefinition 方法来完成。

BeanDefinitionRegistry 接口提供了 registerBeanDefinition 方法,用于将创建好的 BeanDefinition 注册到 BeanFactory 中:

beanFactory.registerBeanDefinition(beanName, beanDefinition);

postProcessBeanFactory 方法通过注册注解类,使这些类能够参与到 Spring 的依赖注入和生命周期管理中。这一过程包括扫描指定包路径、创建并注册 BeanDefinition 等步骤,通过自动化的组件发现和注册机制,Spring 极大地简化了应用程序的配置和管理工作。

(二)对注解类注册的理解新思路

注解类的注册不仅仅是简单的扫描和注册,其实可以通过扩展和优化,比如可以在这里增加:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);// 执行包扫描,自动注册符合条件的组件类if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}// 动态注册额外的注解配置类if (!this.annotatedClasses.isEmpty()) {for (Class<?> annotatedClass : this.annotatedClasses) {if (shouldRegister(annotatedClass)) {this.reader.register(annotatedClass);}}}
}// 判断是否注册某个注解类的逻辑
private boolean shouldRegister(Class<?> annotatedClass) {// 根据某些条件决定是否注册// 例如,检查注解类上是否有特定注解,或者根据配置文件中的设置return true;
}

新的思路

  • 支持更多注解类型:除了常见的 Spring 注解,还可以支持更多的自定义注解或第三方注解。这可以通过扩展 AnnotatedBeanDefinitionReader 来实现,增加对其他注解类型的解析和处理。
  • 动态注解类注册:在应用运行过程中,根据某些条件动态决定是否注册某些注解类。比如,可以通过配置文件或者数据库表来决定需要注册哪些类,从而实现更加灵活的 Bean 管理。
  • 注解类的优先级管理:对于不同的注解类,可以设置不同的优先级。在注册时,根据优先级决定注册顺序,从而控制 Bean 的初始化顺序。这在一些复杂应用中非常有用,可以避免由于 Bean 初始化顺序引起的问题。
  • 条件性注解注册:可以根据当前的环境或者配置条件决定是否注册某些注解类。例如,只有在特定的 Profile(如开发环境或生产环境)下才注册某些类,从而实现环境隔离和配置灵活性。

六、总结

在 Spring IOC 容器中,postProcessBeanFactory 方法作为一个关键的扩展点,允许子类在 BeanFactory 初始化后、Bean 实例化前进行进一步自定义处理。通过对 AnnotationConfigServletWebServerApplicationContext 类的分析,我们理解了该方法的主要功能和实现,包括调用父类方法以继承基础设置和逻辑、执行包扫描、自动注册符合条件的组件类以及注解类注册等关键步骤。

包扫描和注解类注册是 postProcessBeanFactory 的核心功能,能够自动发现并注册带有特定注解的类,这不仅简化了配置,还增强了应用的模块化和动态可扩展性。通过扩展和优化,如支持更多注解类型、动态注解类注册、注解类优先级管理和条件性注解注册,可以进一步提升 Spring 框架的灵活性和功能性,适应复杂应用的需求。

这些机制确保了 Spring 容器能够更好地支持 Web 应用程序的特定需求,提供必要的基础设施,从而保证了应用程序的稳定性和性能。在实际开发中,通过合理运用这些功能,可以大大简化配置、提高开发效率,并增强应用的可维护性和扩展性。

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

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

相关文章

React综合指南(二)

https://activity.csdn.net/creatActivity?id10787 #1024程序员节&#xff5c;征文# 21、 React中的状态是什么&#xff1f;它是如何使用的&#xff1f;&#xff1f; 状态是 React 组件的核心&#xff0c;是数据的来源&#xff0c;必须尽可能简单。基本上状态是确定组件呈现…

rk3568 android11 单独烧写内核。

问题: 我现在 遇到一个问题,如果我单独 烧写boot.img 的话,就会进入 recovery 的模式。 如下图: 问题说明: 如果我烧写的 Update.img 是可以启动的。那么我再烧写一个 编译 update.img 顺带编译出来的 boot.img 是可以正常启动的。 问题出在 , 如果我 重新编译一遍 ,使…

在Oxygen编辑器中支持数学公式

在编写文档时&#xff0c;经常需要插入公式。虽然将公式作为图片插入到文档中是可以的&#xff0c;但这会使后续的修改变得非常不便。目前&#xff0c;MathML (Mathematical Markup Language) 和 LaTeX 是两种常用的数学公式描述语言&#xff0c;它们各自具有不同的特点和适用场…

第二十九篇:图解TCP三次握手,一次说透,TCP系列四

⼀开始&#xff0c;客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端⼝&#xff0c;处于 LISTEN 状态。 接下来这部分内容的介绍将影响你能不能彻底理解了TCP的三次握手。 一、划重点&#xff1a;只有服务端启动了端口监听&#xff0c;客户端TCP握手才能建立连接&…

关于jmeter设置为中文问题之后无法保存设置的若干问题

1、jemeter如何设置中文模式 Options--->Choose Language--->Chinese(Simplifies), 如此设置后就可显示中文模式(缺点&#xff1a;下次打开还是英文)&#xff1b;如下图所示&#xff1a; 操作完成之后&#xff1a; 但是下次重启之后依旧是英文&#xff1b; 2、在jmeter.…

TRIZ理论在医疗电子研发中的应用

TRIZ&#xff0c;全称“Theory of Inventive Problem Solving”&#xff08;发明问题解决理论&#xff09;&#xff0c;是一种系统化、逻辑严谨的创新方法论。它通过对大量发明案例的深入分析和总结&#xff0c;提炼出一套行之有效的创新原理和解决方案&#xff0c;旨在帮助人们…

【Word原件测试资料合集】软件系统功能测试方案,软件测试方案(整体方案),软件测试文档-测试计划模版(功能与性能),软件测试流程

一、 前言 &#xff08;一&#xff09; 背景 &#xff08;二&#xff09; 目的 &#xff08;三&#xff09; 测试目标 &#xff08;四&#xff09; 适用范围与读者对象 &#xff08;五&#xff09; 术语与缩写 二、 软件测试实施流程 &#xff08;一&#xff09; 测试工作总体流…

【java】thymeleaf模板怎么给JS赋值

【java】thymeleaf模板怎么给JS赋值 我们知道如果被标签绑定值是: <h3 th:text="${name}"></h3

MoH:融合混合专家机制的高效多头注意力模型及其在视觉语言任务中的应用

在深度学习领域,多头注意力机制一直是Transformer模型的核心组成部分,在自然语言处理和计算机视觉任务中取得了巨大成功。然而,研究表明并非所有的注意力头都具有同等重要性,许多注意力头可以在不影响模型精度的情况下被剪枝。基于这一洞察,这篇论文提出了一种名为混合头注意力…

DS快速排序和归并排序的非递归实现(16)

文章目录 前言一、快排的非递归实现二、归排的非递归实现总结 前言 打破递归桎梏&#xff0c;迎接迭代解放&#xff01; 一、快排的非递归实现 我们要替代递归&#xff0c;就要用到迭代或者循环&#xff0c;也就是说&#xff0c;其核心思想是不变的&#xff0c;只是换一种方式来…

使用 CDN 后 Apache 的日志记录客户真实 IP

经常搭建网站服务器的都知道&#xff0c;在给站点使用了 CDN 后 Web 应用的日志记录里就会只记录 CDN 节点 IP 了&#xff0c;这就没法看到真实客户请求 IP&#xff0c;对于日志分析、运维日常维护来说就有点儿麻烦了&#xff0c;今天明月结合在五洛云服务器上搭建的Apache环境…

探索C嘎嘎:模版初阶

前言&#xff1a; 小编在前文讲述了C的内存管理&#xff0c;下面我们来开始继续探索C&#xff0c;开启C又一个重要的内容&#xff0c;模版初阶的详解&#xff0c;代码时间到&#xff01; 目录 1.泛型编程 1.1.引子 1.2.泛型编程 2.函数模版 2.1.函数模版的概念 2.2.函数模版的格…

基于知识图谱的电子元器件问答系统

你还在为寻找电子元器件的相关信息头疼吗&#xff1f;作为一名程序员或电子工程师&#xff0c;在项目中经常需要快速查询电子元件的属性或关联关系。今天给大家介绍一个可以大大提升工作效率的神器——基于知识图谱的电子元器件问答系统。这不仅是你学习和工作的好帮手&#xf…

解读华为云Kuasar多沙箱容器技术,带来更强隔离性和安全性

摘要&#xff1a;沙箱技术的引入&#xff0c;为容器提供了更强的隔离性和安全性&#xff0c;成为云原生技术的重要组成部分。 本文来源 《华为云DTSE》第五期开源专刊&#xff0c;作者&#xff1a;华为云云原生开源团队研发工程师。 近年来&#xff0c;云原生容器技术飞速发展&…

详解Java之异常

目录 防御式编程 捕获异常 基础语法 示例1 【不处理异常】 示例2 【使用try catch捕获异常】 示例3 【catch只能处理对应的异常】 示例4 【catch可以有多个】 示例5 【可以用一个catch捕获所有异常】 示例6 【finally一定会执行】 示例7 【使用try回收资源】 示例8 …

鸿蒙网络编程系列24-Web组件与应用互操作示例

1. APP内嵌网页与应用互操作概述 在通常的APP开发中&#xff0c;经常会采用内嵌网页的形式&#xff0c;通过网页来展现丰富的动态内容&#xff0c;虽少了很多原生开发的功能&#xff0c;但是这么做无可厚非&#xff0c;毕竟APP需要适配的系统平台很多&#xff0c;比如安卓、苹…

【HarmonyOS NEXT】权限申请及应用设置页跳转

关键词&#xff1a;鸿蒙、程序访问控制、定位、应用详情页、startability、want 在app开发过程中&#xff0c;常进行系统权限的申请以提供设备访问或个性化功能&#xff08;如扫一扫、城市定位、剪贴板等&#xff09;&#xff0c;从而保障应用功能的完整性&#xff0c;那么本期…

Jupyter notebook和Conda使用

Jupyter notebook和Conda使用 文章目录 Jupyter notebook和Conda使用AnacondaJupyter notebook简介页面使用技巧编写格式自动补全查看函数文档魔术命令远程访问交互式 Anaconda Anaconda是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项…

stm32实现esp8266连接到TCP服务器(二)未完

1.2 连接到TCP Server 1.2.1 使用网络助手&#xff0c;设立TCP服务器 ​ 编辑 1.2.2 连接服务器 ATCIPSTART"TCP","192.168.1.18",8080 //指令&#xff0c;注意双引号逗号都要半角(英文)输入 CONNECT //结果&#xff1a;成功 OK //结果&#xff1a;成功 …

jmeter中用csv data set config做参数化2

在jmeter中&#xff0c;使用csv data set config进行参数化是很重要的一个功能&#xff0c;但是这个功能的使用需要十分仔细和小心&#xff0c;因为细节之处往往决定着结果的正确与否。 举例&#xff1a; 一个登录接口用加密密码登录&#xff0c;一个登录接口用原始密码登录。…