【Spring】深入解析 Spring 原理:Bean 的多方面剖析(源码阅读)

 🔥个人主页: 中草药

🔥专栏:【Java】登神长阶 史诗般的Java成神之路


一、Bean的作用域

        在 Java Spring 框架中,Bean 的作用域是一个关键概念,它决定了 Bean 的生命周期和实例化方式,对应用的性能、资源利用以及数据一致性等方面有着深远影响。本文将详细探讨 Spring Bean 的各种作用域。

举例 设置Bean的作用域

package com.bite.principle.config;import com.bite.principle.model.Dog;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.web.context.annotation.ApplicationScope;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.annotation.SessionScope;@Configuration
public class DogConfig {@Beanpublic Dog dog(){Dog dog = new Dog();dog.setName("旺旺");return dog;}@Bean
//    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)@Scope("singleton")public Dog singleDog(){return new Dog();}@Bean@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//    @Scope("prototype")public Dog prototypeDog(){return new Dog();}@Bean@RequestScopepublic Dog requestDog(){return new Dog();}@Bean@SessionScopepublic Dog sessionDog(){return new Dog();}@Bean@ApplicationScopepublic Dog applicationDog(){return new Dog();}}

 1、singleton 单例作用域

        Singleton 是 Spring 默认的作用域。当一个 Bean 被定义为 Singleton 时,在整个 Spring 容器的生命周期内,只会创建一个该 Bean 的实例

        例如,在一个处理数据库操作的应用中,数据库连接池通常被设置为 Singleton 作用域。因为创建数据库连接是一个资源密集型操作,多个组件共享同一个连接池实例可以避免重复创建连接带来的开销,提高资源利用率。

        Spring 实现 Singleton 作用域的原理是通过容器级别的缓存。容器在启动时创建 Bean 实例并将其存储在缓存中,后续对该 Bean 的请求直接从缓存中获取,从而保证始终返回同一个实例。

可用以下代码测试

package org.example.principle;import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/scope")
@RestController
public class ScopeController {@Resource(name = "singleDog")private Dog singleDog;@RequestMapping("/single")public String single(){//从context中获取对象Dog dog = (Dog)context.getBean("singleDog");return "注入对象:"+ singleDog.toString() + ",context Dog:"+ dog.toString();}}

测试结果:

即使进行多次刷新,显示的结果还是同一个,这就是 单例模式

 2、prototype 原型作用域

        与 Singleton 不同,Prototype 作用域的 Bean 在每次被使用时都会创建一个新的实例。

        考虑一个用户订单处理服务,每个订单可能具有不同的处理逻辑和状态,将订单处理服务设置为 Prototype 作用域,就能确保每个订单处理过程都使用独立的服务实例,避免不同订单之间的状态干扰。

        然而,由于每次请求都会创建新实例,开发人员需要谨慎使用 Prototype 作用域,避免因频繁创建复杂对象而导致性能问题。

可用以下代码测试:

package org.example.principle;import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/scope")
@RestController
public class ScopeController {@Resource(name = "prototypeDog")private Dog prototypeDog;@RequestMapping("/prototype")public String prototype(){//从context中获取对象Dog dog = (Dog)context.getBean("prototypeDog");return "注入对象:"+ prototypeDog.toString() + ",context Dog:"+ dog.toString();}}

测试结果:

如测试结果,注入的对象不发生变化,但是提取出来的Bean会变化,每一次的刷新即使用都会变化,创建新的实例

3、Request 请求作用域

        Request 作用域适用于 Web 应用场景。在一次 HTTP 请求的生命周期内,同一个 Request 作用域的 Bean 是共享的,不同请求会创建不同的实例。

        比如在一个基于 Spring MVC 的应用中,用于存储请求参数的 Bean 可以设置为 Request 作用域。从请求开始,到各个控制器和服务层方法处理请求参数,都使用同一个参数 Bean 实例,保证了请求数据在处理过程中的一致性,当请求结束时,该 Bean 实例被销毁。

        Spring 借助与 Web 容器的集成,在请求开始时创建 Bean 实例并绑定到请求上下文,请求结束时自动销毁实例来实现 Request 作用域。

package org.example.principle;import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/scope")
@RestController
public class ScopeController {@Resource(name = "requestDog")private Dog requestDog;@RequestMapping("/request")public String request(){//从context中获取对象Dog dog = (Dog)context.getBean("requestDog");return "注入对象:"+ requestDog.toString() + ",context Dog:"+ dog.toString();}}

结果:

 

 如上测试结果,每一次刷新都会创建新的实例,但是注入对象,和使用Bean保持统一,并不会随着Bean的使用而创建新的实例

4、Session 会话作用域

        Session 作用域的 Bean 在一个用户会话期间是同一个实例。从用户首次访问应用建立会话,到会话结束(如用户注销或会话超时),对该 Bean 的引用都指向同一个对象。

        在电子商务应用中,购物车 Bean 常被设置为 Session 作用域。用户在一次购物会话中,无论浏览多少商品页面,添加或修改购物车内容,操作的都是同一个购物车实例,方便用户购物体验的同时,也保证了购物车数据在会话内的一致性。

        Spring 通过利用 Web 容器的会话管理机制,在会话创建时实例化 Bean 并绑定到会话上下文,会话结束时销毁实例来实现 Session 作用域。

测试代码:

package org.example.principle;import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/scope")
@RestController
public class ScopeController {@Resource(name = "sessionDog")private Dog sessionDog;@RequestMapping("/session")public String session(){//从context中获取对象Dog dog = (Dog)context.getBean("sessionDog");return "注入对象:"+ sessionDog.toString() + ",context Dog:"+ dog.toString();}}

测试结果:

在 浏览器1 反复刷新下

 在 浏览器2 反复刷新下

这就相当于在不同的session下,才会去创建新的实例 

5、Application 全局作用域

        Application 作用域的 Bean 在整个 Web 应用范围内只有一个实例,类似于 Singleton,但更侧重于 Web 应用级别。

        例如,应用的全局配置信息 Bean,如应用名称、版本号等配置信息,整个 Web 应用只需一个实例即可,各个组件都可以共享这个配置信息,方便统一管理和维护。

        总之,正确理解和运用 Spring Bean 的作用域对于构建高效、稳定且可维护的 Java 应用至关重要。开发人员需要根据不同的业务需求和场景,合理选择 Bean 的作用域,以优化应用的性能和功能。

6、websocket  HTTP WebSocket 作用域

        WebSocket 的 “作用域” 更倾向于长期的、持续的连接场景。一旦建立连接,这个连接就可以在整个通信过程中持续存在,直到连接被关闭。

        在一个 WebSocket 连接的范围内,服务器和客户端可以进行多次数据交互,这些交互都基于同一个连接,并且可以根据业务需求灵活地处理消息,如在一个在线游戏中,玩家的操作和游戏状态的更新都可以通过这个连接来完成。

 二、Bean的生命周期

Bean 的生命周期是一个核心概念,它涵盖了从 Bean 的创建到销毁的整个过程。

我们可以大致将他划分为5个阶段,分别是实例化阶段,属性赋值阶段,初始化阶段,使用阶段,销毁阶段

我们可以用此代码去形象理解这个生命周期的五个过程,代码如下


package org.example.principle;import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class BeanLifeComponent implements BeanNameAware {private Dog dog;//相当于实例化阶段public BeanLifeComponent() {System.out.println("执行构造函数...");}//属性装配@Autowiredpublic void setDog(Dog dog) {this.dog = dog;System.out.println("使用setter方法, 完成属性装配...");}//初始化@PostConstructpublic void init(){System.out.println("执行init方法...");}@Overridepublic void setBeanName(String name) {System.out.println("执行setBeanName, name:"+name);}//使用public void use(){System.out.println("执行use方法....");}//利用此注解去表示销毁阶段@PreDestroypublic void destroy(){System.out.println("执行destroy方法...");}
}

测试代码:

package org.example.principle;import org.example.autoconfig.TestConfig1;
import org.example.autoconfig.TestConfig2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;@SpringBootApplication
public class SpringPrincipleApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringPrincipleApplication.class, args);BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);beanLifeComponent.use();}}

 执行结果:

由此日志信息我们 可以大致来观察Bean的生命周期

1、实例化阶段

        当 Spring 容器启动时,首先会根据配置信息(如 XML 配置、Java 配置或基于注解的配置)确定需要创建的 Bean。容器会使用反射机制调用 Bean 的构造函数来创建一个实例。例如,如果有一个简单的 UserService Bean,Spring 会在这个阶段创建 UserService 的对象实例,就像执行 new UserService() 操作一样。

2、属性赋值阶段

        在实例创建之后,Spring 会根据配置将相应的值赋给 Bean 的属性。这可能包括从配置文件中读取属性值、注入其他依赖 Bean 等。比如,若 UserService 依赖于一个  UserRepository Bean,Spring 会在此时将对应的 UserRepository 实例注入到 UserService 中,使得 UserService 能够使用 UserRepository 的功能。

3、初始化阶段

        Bean 的初始化是一个关键步骤。在这个阶段,Bean 可以执行一些自定义的初始化逻辑。Spring 提供了两种主要的方式来定义初始化方法:一是在 XML 配置中使用 init-method 属性指定一个方法,二是在 Bean 类中使用 @PostConstruct 注解标注一个方法

实例化和初始化的区别

        实例化是指创建一个类的对象的过程。在 Java 中,通过使用new关键字或者通过反射等机制,为对象分配内存空间,使得这个对象从类的定义变成一个可以使用的实体。这就好比是盖房子,实例化是按照蓝图(类的定义)搭建出房子的框架(对象),但此时房子还没有进行内部装修等后续工作。

        初始化是在对象已经实例化之后,对这个对象进行的一些准备工作,使得它能够正常使用。这包括给对象的属性赋值(如果还没有赋值)、建立必要的资源连接(如数据库连接、网络连接等)、加载配置信息等操作。继续用盖房子的比喻,初始化就像是对房子进行内部装修,安装水电、家具等,让房子具备居住的条件。

4、使用阶段

        经过前面的步骤,Bedan 已经完全准备好,可以被应用程序使用了。在整个应用运行期间,Spring 容器会管理这些 Bean 实例,根据需要将它们注入到其他组件中,以提供各种服务。例如,在一个 Web 应用中,UserService 可能会被控制器调用,以处理用户相关的业务逻辑,如用户注册、登录、信息查询等操作。

5、销毁阶段

        当应用程序关闭或 Spring 容器被销毁时,Bean 也会被销毁。与初始化类似,Spring 提供了两种定义销毁方法的方式:在 XML 配置中使用 destroy-method 属性,或者在 Bean 类中使用 @PreDestroy 注解。在销毁方法中,可以进行资源的释放操作,如关闭数据库连接、释放文件句柄等。

三、Spring Boot的自动装配

        Spring Boot的自动配置就是当Spring容器启动后,一些配置类,bean对象就自动存入到了IoC容器之中,不需要我们手动声明。从而简化了开发,省去了繁琐的配置操作

1、Spring 加载 Bean

我们可以模拟去理解第三方jar包的使用

autoconfig 下创建 TestConfig 作为第三方资源

如上,启动类与第三方资源不在同一包下,因此,通过启动类

package org.example.principle;import org.example.autoconfig.TestConfig1;
import org.example.autoconfig.TestConfig2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;@SpringBootApplication
public class SpringPrincipleApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringPrincipleApplication.class, args);TestConfig1 bean = context.getBean(TestConfig1.class);bean.use();TestConfig2 bean2 = context.getBean(TestConfig2.class);bean2.use();//        BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);
//        beanLifeComponent.use();}}

会发生报错

No qualifying bean of type 'org.example.autoconfig.TestConfig1' available

没有类型为“org.example.autoconfig”的合格bean

原因分析

        Spring 通过五大注解和 @Bean 注解可以帮助我们把Bean加载到SpringIoC容器中,但前提是,这些注解类与SpringBoot启动类在同一个目录之下。

        而此时,启动类即@SpringBootApplication在principle的包之下,他只会扫描此路径下的所有包,并不包括autoconfig之下的第三方资源

解决方案:

1、@ComponentScan

通过该注解去指定Spring的扫描路径

@ComponentScan({"org.example.autoconfig","org.example.principle"})//当表现多个路径时,要用集合{}

Spring 并没有采取这种方式 (当我们引入第三方框架时,并没有额外添加扫描路径,比如mybatis)

如果采取这种方式,当我们引入大量第三方依赖,比如Mybatis,jackson等时,就需要在启动类上配置不同的依赖需要扫描的包,这种方式会非常繁琐

2、@Import

使用该注解导入该类

@Import({TestConfig1.class,TestConfig2.class})

Spring 同样没有采取这种方式,理由同上,过于繁琐

3、导入ImportSelector接口实现类

先写一个接口实现类

package org.example.autoconfig;import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;public class MyImport implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"org.example.autoconfig.TestConfig1","org.example.autoconfig.TestConfig2"};}
}

再通过@Import去引入这个接口实现类

@Import(MyImport.class)

这些都存在一个明显问题,需要使用者需要知道第三方依赖中需要那些配置和Bean对象,如果我们漏掉了一个类,会使项目出现巨大问题

4、给第三方依赖提供一个注解

package org.example.autoconfig;import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImport.class)
public @interface EnableTestConfig {
}

注解中封装@Import这个注解,并且导入MyImport.class这个类

再启动类上加入这个注解

@EnableTestConfig

Spring采取的方式便是这种

以上所有方式最后都能顺利使用TestConfig

2、自动装配的源码阅读

        pring Boot 应用通常以一个带有 @SpringBootApplication(实现自动装配的核心) 注解的主类作为入口。这个注解实际上是一个组合注解,它包含了 @Configuration@EnableAutoConfiguration 和 @ComponentScan。其中,@EnableAutoConfiguration 是实现自动装配的关键。

        当 Spring Boot 应用启动时,@EnableAutoConfiguration 注解会触发自动装配机制。它会在类路径下查找 META-INF/spring.factories 文件,并加载其中配置的自动装配类。

阅读源码:

 1、元注解

JDK中提供了4个标准的用来来对注解类型进⾏注解的注解类, 我们称之为 meta-annotation(元注

解), 他们分别是:
@Target 描述注解的使用范围(即被修饰的注解可以用在什么地方)
@Retention 描述注解保留的时间范围
@Documented 描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息
@Inherited 使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则
其子类将自动具有该注解)
2、 @SpringBootConfiguration

点开该注解,只是对@Configuration进行了一层封装

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Indexed;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;
}

3、@EnableAutoConfiguration (开启自动配置)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

该注解首先使用@Import注解,导入了实现 ImportSelector 接口的实现类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {//省略代码public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {//获取自动配置的配置类信息AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}
selectImports() 方 法底层调用  getAutoConfigurationEntry() 方 法, 获取可自动配置的配置类信息集合。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);//获取在配置⽂件中配置的所有⾃动配置类的集合List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}}
getAutoConfigurationEntry() 方 法通过调用 getCandidateConfigurations(annotationMetadata, attributes) 方法获取在配置文件中配置的所有自动配置类的集合
//获取所有基于
//METAINF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports⽂件
//META-INF/spring.factories⽂件中配置类的集合
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation, this.getBeanClassLoader());List<String> configurations = importCandidates.getCandidates();Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/" + this.autoConfigurationAnnotation.getName() + ".imports. If you are using a custom packaging, make sure that file is correct.");return configurations;}
getCandidateConfigurations 方 法的功能: 获取所有基于 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件, META-INF/spring.factories 文 件中配置类的集合.
在引入的起步依赖中, 通常都有包含以上两个文件
在加载自动配置类的时候,并不是将所有的配置全部加载进来,而是通过@Conditional等注解的判断进行动态加载
@Conditional是Spring 的底层注解,意思就是根据不同的条件,进行自己不同的条件判断 ,如果满足指定的条件,那么配置类里面的配置才会生效
此外还有 @AutoConfigurationPackage
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.springframework.boot.autoconfigure;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({AutoConfigurationPackages.Registrar.class})
public @interface AutoConfigurationPackage {String[] basePackages() default {};Class<?>[] basePackageClasses() default {};
}
这个注解主要是导入⼀个配置文件 AutoConfigurationPackages.Registrar.class
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {Registrar() {}public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));}public Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImports(metadata));}}
@AutoConfigurationPackage 就是将启动类所在的包下面所有的组件都扫描注册到 spring 容器中
因此,SpringBoot 自动配置原理大致如下

 SpringBoot的自动配置原理源码口是 @SpringBootApplication 注解,这个注解封装了3个注解@SpringBootConfiguration 标志当前类为配置类
@ComponentScan 进行包扫描(默认扫描的是启动类所在的当前包及其子包)
@EnableAutoConfiguration

  • @Import 注解:读取当前项目下所有依赖jar包中 META-INF/spring.factories,META-INF/spring/org.springframework.boot.autoconfigure.Autoconfiguration.imports 两个文件里面定义的配置类(配置类中定义了 @Bean 注解标识的方法)
  • @AutoconfigurationPackage:把启动类所在的包下面所有的组件都注入到Spring容器中 

“读书不是为了雄辩和驳斥,也不是为了轻信和盲从,而是为了思考和权衡。”—— 培根

🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀

以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐

  制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸

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

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

相关文章

Excel 列名称转换问题 Swift 解答

文章目录 摘要描述题解答案Swift 实现代码&#xff1a;题解代码分析示例测试及结果 时间复杂度空间复杂度总结未来展望参考资料 摘要 本篇文章将通过 Swift 编程语言解答一个常见的算法问题&#xff1a;给定一个整数 columnNumber&#xff0c;将其转换为 Excel 表中的列名称。…

基于艾伦方差的频率稳定性分析

某个授时系统通过串口或网口采集时间间隔计数器、频率计数器、相位噪声分析仪设备的重要信息,用于评估和分析频率源的频率稳定度,确保测量的准确性和可靠性。 数据处理: 读取保存在文件中的时间间隔计数器测量的时差数据,计算时间稳定度(用TDEV表示)并保存。TDEV包括秒稳…

秒鲨后端之MyBatis【1】环境的搭建和核心配置文件详解

​ 别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! Mybatis简介 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff…

虚幻引擎结构之ULevel

在虚幻引擎中&#xff0c;场景的组织和管理是通过子关卡&#xff08;Sublevel&#xff09;来实现的。这种设计不仅提高了资源管理的灵活性&#xff0c;还优化了游戏性能&#xff0c;特别是在处理大型复杂场景时。 1. 场景划分模式 虚幻引擎采用基于子关卡的场景划分模式。每个…

Linux文件目录 --- 移动和改名命令MV、强制移动、试探性移动过、按时间移动

二、MV移动改名命令 重命名文件&#xff1a;mv [选项] 旧文件名 新文件名 移动文件/文件夹&#xff1a;mv [选项] 源文件 目标目录 选项作用-b当覆盖文件时会对被覆盖文件进行先行备份。-i交互式操作&#xff0c;当目标文件已经存在时&#xff0c;会询问是否覆盖。-n试探性覆盖…

Linux服务器端自动挂载存储设备(U盘、移动硬盘)

前言 Linux服务器挂载存储设备需要使用mount&#xff0c;因为服务器的存储通常是固定的&#xff0c;很少存在频繁的插拔USB存储设备的现象 &#xff0c;使用Linux系统本身是没有较为简单的自动挂载存储设备的方法的。 涉及知识点 udev udev可以监测USB设备的插入、拔出事件&…

CentOS7下的vsftpd服务器和客户端

目录 1、安装vsftpd服务器和ftp客户端&#xff1b; 2、配置vsftpd服务器&#xff0c;允许普通用户登录、下载、上传文件&#xff1b; 3、配置vsftpd服务器&#xff0c;允许anonymous用户登录、下载、上传文件&#xff1b; 4、配置vsftpd服务器&#xff0c;允许root用户登录…

系统思考—全局思维

昨天接到一个企业需求&#xff0c;某互联网公司VP希望N-1的核心团队一起学习系统思考&#xff0c;特别是在新业务快速发展的阶段。公司增长势头不错&#xff0c;但如何解决跨部门的协作问题&#xff0c;成为了瓶颈。全局思维就是关键。产品、技术、市场、运营、客服……如何打破…

information_schema是什么?

前言 在现代数据驱动的应用开发中&#xff0c;理解和管理数据库结构变得尤为重要。几乎所有的SQL数据库管理系统&#xff08;DBMS&#xff09;都提供了一个名为 information_schema 的虚拟数据库。它不仅是一个了解数据库内部结构的强大工具&#xff0c;也是一个实现跨平台兼容…

MySQL中Seconds_Behind_Master是怎么计算的

目录 1.Seconds_Behind_Master计算方式2.Seconds_Behind_Master 计算方式会存在什么问题3.更好的方式3.1 实现方法3.2 优点在MySQL中,Seconds_Behind_Master是一个用于表示从库(Slave)落后于主库(Master)的时间(以秒为单位)的指标。 1.Seconds_Behind_Master计算方式 其…

Linux 中检查 Apache Web Server (httpd) 正常运行时间的 4 种方法

注&#xff1a;机翻&#xff0c;未校。 4 Ways To Check Uptime of Apache Web Server (httpd) on Linux November 28, 2019 by Magesh Maruthamuthu We all know about the purpose of uptime command in Linux. 我们都知道 Linux 中 uptime 命令的目的。 It is used to c…

活着就好20241225

亲爱的朋友们&#xff0c;大家早上好&#xff01;&#x1f31e; 今天是25号&#xff0c;星期三&#xff0c;2024年12月的第二十五天&#xff0c;同时也是第51周的第三天&#xff0c;农历甲辰[龙]年十一月初二十一日。在这晨光熹微的美好时刻&#xff0c;愿那和煦而明媚的阳光照…

《Swift 字面量》

《Swift 字面量》 介绍 在 Swift 编程语言中&#xff0c;字面量是一种表示源代码中固定值的表达方式。字面量可以直接表示数字、字符串、布尔值等基本数据类型&#xff0c;为编程提供了简洁和直观的方式。Swift 支持多种类型的字面量&#xff0c;包括整数字面量、浮点数字面量…

oracle使用imp命令导入dmp文件

需求&#xff1a; 增量导入 tbl_servicelegalclause 表数据&#xff08;dmp格式&#xff09;。 导入思路&#xff1a;使用 dba 创建一个 临时库&#xff0c;先将 tbl_servicelegalclause.dmp&#xff08;增量的数据&#xff09; 文件导入到 临时库&#xff0c;然后确认临时库数…

美国加州房价数据分析01

1.项目简介 本数据分析项目目的是分析美国加州房价数据&#xff0c;预测房价中值。 环境要求&#xff1a; ancondajupyter notebookpython3.10.10 虚拟环境&#xff1a; pandas 2.1.1 numpy 1.26.1 matplotlib 3.8.0 scikit-learn1.3.1 2. 导入并探索数据集 通用的数据分析…

LabVIEW软件开发的未来趋势

LabVIEW软件开发的未来趋势可以从以下几个方面来分析&#xff1a; ​ 1. 与AI和机器学习的深度结合 趋势&#xff1a;LabVIEW正在向集成AI和机器学习方向发展&#xff0c;尤其是在数据处理、预测性维护和自动化控制领域。 原因&#xff1a;AI技术的普及使得实验和工业场景中的…

使用Amazon Bedrock的无服务器的智能工作流

使用Amazon Bedrock的无服务器的智能工作流 智能工作流基于用户输入处理不可预见的任务&#xff0c;比如发起API调用。无服务器架构可以高效地管理这些任务和不同的工作负载&#xff0c;而无需维护服务器&#xff0c;从而加快部署速度。 你将学习如何通过使用带有保护措施的智能…

近实时”(NRT)搜索、倒排索引

近实时&#xff08;Near Real-Time, NRT&#xff09;搜索 近实时&#xff08;NRT&#xff09;搜索是 Elasticsearch 的核心特性之一&#xff0c;指的是数据在被写入到系统后&#xff0c;可以几乎立即被搜索和查询到。虽然它不像传统数据库那样完全实时&#xff0c;但它的延迟通…

【NACOS插件】使用官网插件更换NACOS数据库

说明 nacos 2.3.1默认支持mysql和derby数据库&#xff0c;如果想要支持其他数据库&#xff0c;可以通过使用插件方式实现。对于该插件的使用&#xff0c;官方说明文档较为粗略(不过也没问题&#xff0c;实际上整个过程就是很简单&#xff0c;只是使用者想复杂了)&#xff0c;网…

Java 深拷贝全面解析

1. 引言 在 Java 编程中&#xff0c;对象之间的复制是一个常见的需求。根据复制的深度不同&#xff0c;我们可以将复制分为浅拷贝和深拷贝。本文将深入探讨 深拷贝&#xff08;Deep Copy&#xff09; 的概念、应用场景、具体实现方法及其优缺点&#xff0c;并提供一些实用的建…