聚焦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.rhkb.cn/news/453071.html

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

相关文章

数字后端零基础入门系列 | Innovus零基础LAB学习Day2

今天开始更新数字IC后端设计实现中Innovus零基础Lab学习后续内容。 数字后端零基础入门系列 | Innovus零基础LAB学习Day1 ####LAB5-2 这个章节的目标也很明确——学习掌握工具的一些常用快捷键。 这里只需要掌握以下几个快捷键即可。其他小编我也不会&#xff0c;也用不着。…

MATLAB电车(宝马 i3)卸载电池再利用电气模型分析

&#x1f3af;要点 特性测试评估卸载电池性能以及不同温度下电池容量和电阻。使用两种电气模型评估和模拟卸载电池可利用性能。从宝马 i3模块中提取三星三元锂方形电池作为评估电池&#xff1a;容量测量、电阻测量&#xff0c;对比新电池性能。使用的等效电路模型以及用于校准…

文心一言 VS 讯飞星火 VS chatgpt (373)-- 算法导论24.4 5题

五、请稍微修改 Bellman-Ford 算法&#xff0c;使其能够在 〇(nm) 时间内解决由 n 个未知变量和 m 个约束条件所构成的差分约束系统问题。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; Bellman-Ford 算法本身就是一个用于解决差分约束系统问题的经典算法&…

【途牛旅游网-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

工作日志:vue3各种警告

1、遇见报错&#xff0c;但也没啥影响&#xff0c;不知怎么回事。 可是我没写过这东西啊。 2、一个警告。 它表示在渲染过程中尝试访问组件实例上不存在的属性linkTags。 解决办法&#xff1a;在该属性前&#xff0c;加个v-if判断。 3、 意味着在模板渲染过程中尝试访问了…

LeetCode102. 二叉树的层序遍历(2024秋季每日一题 43)

给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]] 示例 2&#xff1a; 输入…

数据结构 - 队列

队列也是一种操作受限的线性数据结构&#xff0c;与栈很相似。 01定义 栈的操作受限表现为只允许在队列的一端进行元素插入操作&#xff0c;在队列的另一端只允许删除操作。这一特性可以总结为先进先出&#xff08;First In First Out&#xff0c;简称FIFO&#xff09;。这意味…

【资料集】项目全周期过程管理资料、各类软件建设方案、源码梳理清单(全原件)

该资源库深度覆盖开发、运维、实施等核心流程&#xff0c;全面囊括项目从立项至结项的各类必需文档&#xff0c;如验收辅助材料、资质审核流程及投标策略方案等&#xff0c;确保项目生命周期的每个阶段都能找到相应的支持与依据。此外&#xff0c;资源库精心整理了研发流程细节…

Docker 容器 数据卷 使用

目录 常用 命令 什么是数据卷以及特点 如何挂载数据卷 数据卷容器 数据覆盖问题 修改已经建立的数据卷关系 博主wx&#xff1a;yuanlai45_csdn 博主qq&#xff1a;2777137742 想要 深入学习 5GC IMS 等通信知识(加入 51学通信)&#xff0c;或者想要 cpp 方向修改简历&…

Nuxt.js 应用中的 build:done 事件钩子详解

title: Nuxt.js 应用中的 build:done 事件钩子详解 date: 2024/10/21 updated: 2024/10/21 author: cmdragon excerpt: build:done 是 Nuxt.js 的一个生命周期钩子,它在 Nuxt 应用的打包构建器完成运行后被调用。这个钩子为开发者提供了一个在构建过程结束后执行特定逻辑的…

Java基于SpringBoot微信小程序的跳蚤市场系统设计与实现(lw+数据库+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

数据分析和可视化python库orange简单使用方法

Orange 是一个基于 Python 的数据挖掘和机器学习库&#xff0c;它提供了一系列可视化工具和算法&#xff0c;用于数据分析、机器学习和数据可视化等任务。 一、主要特点 可视化界面&#xff1a;Orange 提供了直观的可视化界面&#xff0c;使得用户可以通过拖放操作构建数据分…

学习文档(5)

Redis应用 目录 Redis应用 Redis 除了做缓存&#xff0c;还能做什么&#xff1f; Redis 可以做消息队列么&#xff1f; Redis 可以做搜索引擎么&#xff1f; 如何基于 Redis 实现延时任务&#xff1f; Redis 除了做缓存&#xff0c;还能做什么&#xff1f; 分布式锁&…

AI‘林黛玉发疯文学’火了!40篇笔记涨粉30万,这是怎么做到的?五步教你!

本文背景 最近老刷到林黛玉那种阴阳怪气的“发疯文学”视频呢。在 小红书 搜了搜相关话题&#xff0c;嘿&#xff0c;带“#林黛玉”的话题浏览量有 9.8 亿之多&#xff0c;像“#林黛玉发疯文学”的标签浏览量也有七千多万次&#xff0c;“林黛玉倒拔垂杨柳”都有 1332 万次浏览…

Java--集合(三)之vectorlinkedlisthashset结构

文章目录 0.架构图1.vector解析2.LinkedList分析2.1源码分析2.2迭代器遍历的三种方式 3.set接口的使用方法3.1基本使用说明3.2基本遍历方式3.3HashSet引入3.4数组链表模拟3.5hashset扩容机制3.6hashset源码解读3.7扩容*转成红黑树机制**我的理解 0.架构图 1.vector解析 和之前介…

mysql 10 单表访问方法

01.优化的过程 对于我们这些 MySQL 的使用者来说&#xff0c; MySQL 其实就是一个软件&#xff0c;平时用的最多的就是查询功能。DBA时不时丢过来一些慢查询语句让优化&#xff0c;我们如果连查询是怎么执行的都不清楚还优化个毛线&#xff0c;所以是时候掌握真正的技术了。我…

Jupyter notebook中更改字体大小

文章目录 方法一&#xff1a;局部修改方法二&#xff1a;全局修改 Jupyter notebook提供了一个非常方便的跨平台交互代码编译环境&#xff0c;但是单元格的内的代码字体往往显示较小&#xff0c;不利于观看。本人查了很多方法来调整字体&#xff0c;后来发现既不需要更改jupyte…

HCIP-HarmonyOS Application Developer 习题(十二)

&#xff08;多选&#xff09;1、声明式开发范式的转场动画包含以下哪几种类型? A、页面间转场 B、应用间转场 C、共享元素转场 D、组件内转场 答案&#xff1a;ACD 分析&#xff1a; &#xff08;多选&#xff09;2、公共事件服务为应用程序提供哪些能力。 A、取消发布公共…

vue day08(vuex)

一、vuex 概述 1. 是什么 vuex 是一个 vue 的状态管理工具&#xff0c;状态就是数据 大白话&#xff1a;vuex 是一个插件&#xff0c;可以帮我们管理 vue 通用的数据&#xff08;多组件共享的数据&#xff09; 2. 场景 一份数据在多个组件中使用&#xff0c;并且还可以进行数据…

Facebook的隐私之战:数据保护的挑战与未来

在数字化时代&#xff0c;隐私保护成为了公众关注的焦点&#xff0c;尤其是在社交媒体巨头Facebook身上。随着用户数据泄露事件的频发&#xff0c;Facebook面临着日益严峻的隐私挑战。这些挑战不仅涉及法律法规的遵循&#xff0c;还影响着用户信任、公司声誉以及未来的发展方向…