[Spring] Spring原理(SpringBoot完结)

news2024/11/25 18:49:45

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. Bean的作用域
    • 1.1 概念
    • 1.2 Bean的作用域
  • 2. Bean的生命周期
    • 2.1 概念
    • 2.2 代码演示
  • 3. SpringBoot自动配置
    • 3.1 Spring加载Bean
      • 3.1.1 问题描述
      • 3.1.2 原因分析
      • 3.1.3 解决方案
    • 3.2 SpringBoot原理分析
      • 3.2.1 源码
      • 3.2.2 @EnableAutoConfiguratio详解
      • 3.2.3 总结

1. Bean的作用域

1.1 概念

在我们学习SpringIOC和DI阶段的时候,我们学习了Spring是如何帮助我们管理对象的.

  1. 首先我们可以通过@Controller ,@Service ,@Repository ,@Component ,@Configuration ,@Bean 来声明Bean对象.
  2. 通过AppliactionContext(Spring上下文)或者BeanFactory来获取对象.
  3. 通过@Autowired,Setter方法或者构造方法来为应用程序注入所依赖的Bean对象.
    可以通过https://blog.csdn.net/2301_80050796/article/details/140531072?spm=1001.2014.3001.5501这篇文章来复习.
    创建一个类,叫做Dog类.
@Data
@Getter
public class Dog {
    @Setter
    public Integer age;
    @Setter
    public String name;
}

之后在DogBeanConfig类中创建一个对象,之后把对象放入IoC容器中.

@Component
public class DogBeanConfig {
    @Bean
    public Dog dog(){
        Dog dog = new Dog();
        dog.setAge(2);
        dog.setName("哈士奇");
        return dog;
    }
}

之后从上下文中两次拿到dog对象.

@Test
void dogTest(){
    Dog dog1 = applicationContext.getBean(Dog.class);
    System.out.println(dog1);
    Dog dog2 = applicationContext.getBean(Dog.class);
    System.out.println(dog2);
}

在这里插入图片描述

这里我们发现,Bean对象的输出地址是一样的,说明每次从IoC容器中取出来的是同一个对象.
这也就是单例模式,在默认的情况下,Spring中的Bean都是单例的,这种共行为模式,我们就称为Bean的作用域.Bean的作用域指的是Bean在Spring框架中的某种行为模式.
比如单例模式的作用域:表示在整个Spring中,它只有一个,是全局共享的,也就是当有别人修改它的值之后,另一个人读到的就是被修改的值.

@Test
    @Test
    void dogTest(){
        Dog dog1 = applicationContext.getBean(Dog.class);
        dog1.setName("金毛");
        System.out.println(dog1);
        System.out.println(dog1.getName());
        Dog dog2 = applicationContext.getBean(Dog.class);
        System.out.println(dog2);
        System.out.println(dog2.getName());
    }

观察运行结果,我们发现修改之后的Bean对象拿到名字的时候是修改之后的名字.
在这里插入图片描述

那么能不能将Bean对象设置为非单例的呢(每次获取Bean对象都是一个新对象)?我们这时候就要提到Bean的作用域了.

1.2 Bean的作用域

在Spring中支持6种作用域,其中后4种在SpringMVC环境中才会生效.

  1. singleton:单例作用域,表示的是在每个IoC容器中,同名称的Bean只有一个
  2. prototype:原型作用域(多例作用域),每次使用该Bean的时候,都会创建一个新实例.
  3. request:请求作用域,每次http请求都会创建一个新的实例
  4. session:会话作用域,每一个http session周期之内,都会创建一个新实例.
  5. Application:全局作用域,每个ServletContext生命周期内,创建新的实例
  6. websocket:HTTPWebSocket作用域,每个WebSocket生命周期内,创建新的实例
    指定Bean对象的生命周期,我们可以通过@Scope(翻译:范围)注解来指定.我们来定义几个作用域不同的Bean.
@Component
public class DogBeanConfig {
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public Dog singleDog(){
        Dog dog = new Dog();
        dog.setAge(1);
        dog.setName("萨摩耶");
        return dog;
    }
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Dog prototypeDog(){
        Dog dog = new Dog();
        dog.setAge(3);
        dog.setName("柴犬");
        return dog;
    }
    @Bean
    @RequestScope
    public Dog requestDog(){
        Dog dog = new Dog();
        dog.setAge(2);
        dog.setName("哈士奇");
        return dog;
    }
    @Bean
    @SessionScope
    public Dog sessionDog(){
        Dog dog = new Dog();
        dog.setAge(4);
        dog.setName("柯基");
        return dog;
    }
}

测试不同的Bean获取的对象是否一样.

@RestController
public class DogController {
	@Autowired
	private Dog singleDog;
	@Autowired
	private Dog prototypeDog;
	@Autowired
	private Dog requestDog;
	@Autowired
	private Dog sessionDog;
	@Autowired
	private ApplicationContext applicationContext;
	@RequestMapping("/single")
	public String single(){
		Dog contextDog = (Dog)applicationContext.getBean("singleDog");
		return "dog:"+singleDog.toString()+",contextDog:"+contextDog;
	}
	@RequestMapping("/prototype")
	public String prototype(){
		Dog contextDog = (Dog)applicationContext.getBean("prototypeDog");
		return "dog:"+prototypeDog.toString()+",contextDog:"+contextDog;
	}
	@RequestMapping("/request")
	public String request(){
		Dog contextDog = (Dog)applicationContext.getBean("requestDog");
		return "dog:"+requestDog.toString()+",contextDog:"+contextDog.toString();
	}
	@RequestMapping("/session")
	public String session(){
		Dog contextDog = (Dog)applicationContext.getBean("sessionDog");
		return "dog:"+sessionDog.toString()+",contextDog:"+contextDog.toString();
	}
	@RequestMapping("/application")
	public String application(){
		Dog contextDog = (Dog)applicationContext.getBean("applicationDog");
		return "dog:"+applicationDog.toString()+",contextDog:"+contextDog.toString();
	}
}

我们每次请求有两个对象,一个是通过@Autowired注入的Bean对象,一个是通过上下文获取的Bean对象.
单例作用域:
每一次访问都是同一个对象,并且@Autowired 和applicationContext.getBean() 也是同⼀个对象.
在这里插入图片描述
原型作用域:
从上下文获取的Bean对象每一次请求都不一样,但是通过注解注入的Bean对象没有改变,这是由于在项目运行起来之后就已经注入完成了,所以多次请求也不会发生变化.
在这里插入图片描述
请求作用域:
每一次请求中,@AutowiredapplicationContext.getBean() 也是同⼀个对象.每次请求都会创建一个新对象.
在这里插入图片描述
会话作用域:
在一个session中,多次请求,获取到的对象都是同一个.换一个浏览器访问就会重新创建对象.
在这里插入图片描述
在这里插入图片描述
Appliaction作用域:
在⼀个应用中,多次访问都是同⼀个对象
在这里插入图片描述
这个Appliaction的效果和Singleton有些类似,但是他们有所不同,区别在于:Application scope是ServletContext的单例,singleton是⼀个ApplicationContext的单例.在⼀个web容器中ApplicationContext可以有多个,但是一个web容器中只有一个ServletContext容器.(了解)

2. Bean的生命周期

2.1 概念

生命周期指的是一个对象从诞生到销毁的过程.
Bean的生命周期分为一下5个部分:

  1. 实例化(为Bean分配内存空间) —> 构造方法
  2. 属性赋值(Bean注入和装配,比如@Autowired) —> Setter方法注入
  3. 初始化: 就是执行通知,BeanNameAware,BeanFactoryAware,ApplicationContextAware的接口方法和执行使用注解@PostConstruct 修饰的初始化方法.
  4. 使用Bean.
  5. 销毁Bean: 就是执行销毁容器DisposableBean 接口方法和执行使用注解@PreDestroy修饰的销毁容器的方法.
    在这里插入图片描述

这个就好比我们想买一套房子:

  1. 需要先买房(实例化,分配内存空间)
  2. 装修,把毛坯房变为精装房(执行属性赋值,执行@Autowired注入赋值)
  3. 购买家电.(执行初始化方法,包括接口实现和注释修饰)
  4. 拎包入住(使用Bean)
  5. 寿命到期,拆迁(销毁Bean)

2.2 代码演示

@Component
public class BeanLifeComponent implements BeanNameAware {
    private Dog dog;
    public BeanLifeComponent(){
        System.out.println("实例化Bean...");
    }
    @Autowired
    public void setDog(Dog dog1) {//set方法注入法
        this.dog = dog1;
        System.out.println("属性赋值Bean");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("执行了BeanNameAware接口的通知方法(初始化Bean)");
    }
    @PostConstruct
    public void init(){
        System.out.println("执行了PostConstruct注解修饰的方法(初始化Bean)");
    }
    public void use(){
        System.out.println("使用Bean");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("销毁Bean");
    }
}

测试代码:

@Test
void beanLifeComponent(){
    BeanLifeComponent beanLifeComponent = applicationContext.getBean(BeanLifeComponent.class);
    beanLifeComponent.use();
}

测试结果如下:
在这里插入图片描述
即使类中的这些方法变换了顺序,也不会改变这些这些内容输出的顺序.

3. SpringBoot自动配置

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

3.1 Spring加载Bean

3.1.1 问题描述

现在有一个问题,就是属于Spring本身的类自动导入还可以理解,但是如果是第三方的库想要导入Spring是如何做到的呢?
现在我们使用在项目下创建不同的目录来模拟第三方代码的引入.
数据准备:

  1. com.jrj.springprincipledemo软件包之外新创建一个软件包spring_autoconfig,之后在spring_autoconfig引入第三方代码TestConfig.
    在这里插入图片描述
@Component
public class TestConfig {
    public void print(){
        System.out.println("打印...");
    }
}
  1. com.jrj.springprincipledemo目录下的运行类中通过上下文来获取这个Bean对象,我们发现是获取不到的.
@SpringBootApplication
public class SpringPrincipleDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringPrincipleDemoApplication.class, args);
        TestConfig testConfig = context.getBean(TestConfig.class);
        System.out.println(testConfig);
    }
}

在这里插入图片描述

3.1.2 原因分析

根据前面学过的知识,我们知道,这是由于启动项只能扫描到他所在的目录以及子目录造成的,而在外面的目录却扫描不到.
当我们引入第三方的jar包的时候,第三方jar代码目录一定不再启动类的目录下,那么如何告诉Spring帮我们管理这些Bean呢?

3.1.3 解决方案

我们需要指定路径或者引入文件,告诉Spring,Spring扫描到.
常见的解决方案有两种:

  1. @ComponentScan注解添加扫描路径.
    这种方法我们之前在SpringIoC&DI注入介绍过,不再赘述
  2. @Import注解导入
    @Import导入形式主要有以下两种:
    • 导入类
@SpringBootApplication
@Import(TestConfig.class)
public class SpringPrincipleDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringPrincipleDemoApplication.class, args);
        TestConfig testConfig = context.getBean(TestConfig.class);
        System.out.println(testConfig);
    }
}

我们看到了启动类成功拿到了IoC容器中的Bean对象.
在这里插入图片描述
也可以使用大括号导入多个类:@Import({TestConfig1.class,TestConfig2.class})
- 导入ImportSelector接口实现类.

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"spring_autoconfig.TestConfig"};
    }
}

需要注意的一点是,给返回值导入类的时候,需要导入类的全限定名称.
在启动类的上面直接导入实现ImportSelector的类.

@SpringBootApplication
@Import(MyImportSelector.class)
public class SpringPrincipleDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringPrincipleDemoApplication.class, args);
        TestConfig testConfig = context.getBean(TestConfig.class);
        System.out.println(testConfig);
    }
}

依然可以获取到对象:
在这里插入图片描述
问题:但是他们都有⼀个明显的问题,就是使用者需要知道第三方依赖中有哪些Bean对象或配置类.依赖中有哪些Bean,使用的时候需要配置哪些Bean,只有第三方最清楚,能否让第三方来做这件事情呢?

  • 比较常见的方案就是第三方依赖给我们提供一个注解,这个注解一般都是以@EnableXxxx开头,其中封装的就是@Import注解.
    1. 第三方提供注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(TestConfig.class)
public @interface EnableTestConfig {
}

使用@Target标签定义注解在哪里标记,使用@Retention注解定义注解的生命周期.之后使用@Import注解导入第三方的类对象.
2. 在启动类上提供第三方注解

@SpringBootApplication
@EnableTestConfig
public class SpringPrincipleDemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringPrincipleDemoApplication.class, args);
        TestConfig testConfig = context.getBean(TestConfig.class);
        System.out.println(testConfig);
    }
}

Bea对象依然可以拿到:
在这里插入图片描述

3.2 SpringBoot原理分析

3.2.1 源码

那么Spring究竟是如何实现自动导入的呢?接下来我们就来查看Spring的源码,我们从@SpringBootApplication 开始看起.
这个直接也是Spring实现自动配置的核心

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
....
}

@SpringBootAppliaction是一个组合注解,注解中包含了:

  1. 元注解:
    JDK中提供了4个标准的用来对注解类型进行注解的注解类,我们称之为meta-annotation(元注解),他们分别是:
    • @Target描述注解的使用范围(即被修饰的注解可以用在什么地方)
    • @Retention描述注解保留的时间范围
    • @Documented描述在使用javadoc工具为类生成帮助文档时是否要保留其注解信息(了解)
    • @Inherited使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,其子类自动具有该注解)
  2. @SpringBootConfiguration:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

里面其实就是一个@Configuration,只不过就是封装了一层而已.
3. @EnableAutoConfiguratio
这是Spring自动装配的核心机制,下面详细解释.
4. @ComponentScan
excludeFilter是自定义过滤器,通常用于排除一些类,注解等.

3.2.2 @EnableAutoConfiguratio详解

我们来观察@EnableAutoConfiguration注解的实现:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

这个注解主要包含两部分:

  1. @Import(AutoConfigurationImportSelector.class)
    使用@Import注解,导入实现ImportSelector的类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered{
			@Override
			public String[] selectImports(AnnotationMetadata annotationMetadata) {
				if (!isEnabled(annotationMetadata)) {
					return NO_IMPORTS;
				}
				AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
				return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
			}
		}

selectImports方法有调用了getAutoConfigurationEntry方法,获取可以自动配置的配置类信息集合:

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

其中getCandidateConfigurations方法获取在配置文件中所有自动配置类的集合.

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
			.getCandidates();
		Assert.notEmpty(configurations,
				"No auto configuration classes found in "
						+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

获取的是所有基于META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports配置文件和META-INF/spring.factories的配置文件.里面包含了很多第三方依赖的配置文件.
在这里插入图片描述
[注意]

  • 加载的时候并不是把所有的配置全部加载进来,他是根据不同的条件来导入对应的配置的,这和@Conditional注解有关系,这个注解是Spring底层的一个注解,就是根据不同的条件来进行自己不同条件的判断,如果满足指定的条件,配置才会生效.
  • META-INF/spring.factories文件是Spring内部提供的⼀个约定俗成的加载方式,只需要在模块的META-INF/spring.factories文件中配置即可, Spring就会把相应的实现类注入到Spring容器中.
  1. @AutoConfigurationPackage
    源码如下:
@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 {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImports(metadata));
		}

	}

Registrar中实现了ImportBeanDefinitionRegistrar类,就可以被注解@Import导入到Spring容器中.其中PackageImports(metadata).getPackageNames().toArray(new String[0]))就是当前启动所在的包名.
所以:@AutoConfigurationPackage就是把启动类所在的包下面所有的组件全部都扫描注册操Spring容器中.

3.2.3 总结

SpringBoot自动装配原理大致如下:
在这里插入图片描述
当Spring项目启动的时候,就会自动把这些配置文件中的配置类通过@Import注解全部加载到SpringIoC容器中.

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

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

相关文章

【15】Java字节码

Java方法栈帧的组成&#xff1a;操作数栈局部变量表 操作数栈 Java字节码是Java虚拟机所使用的的指令集。它与JVM基于栈的计算模型是分不开的。 在解释执行过程中&#xff0c;每当为 Java 方法分配栈桢时&#xff0c;Java 虚拟机往往需要开辟一块额外的空间作为操作数栈&…

JavaEE 第16节 线程安全的集合类

目录 前言 顺序表 队列 哈希表 1、Hashtable 2、ConcurrentHashMap&#xff08;重点&#xff09; 前言 本文章主要介绍在多线程环境下&#xff0c;如何线程安全的使用一些常用的集合类&#xff08;顺序表和哈希表&#xff09;。 顺序表 1、自己使用同步锁机制&#xff…

模拟笔试:卡码网2023年快手笔试真题

1.158同余方程 思路 纯数学的思路&#xff0c;想不出来的话很难做。 欧几里得算法视频讲解 代码 #include <iostream> using namespace std;// 扩展欧几里得&#xff1a;计算 ax by gcd(a, b) 的解 long long extended_gcd(long long a, long long b, long long &a…

Java语言程序设计——篇十五(5)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

【STM32嵌入式系统设计与开发拓展】——16_FreeRTOS操作系统

参考&#xff1a;链接: 正点原子 一、认识裸机和RTOS 裸机是无操作系统支持&#xff0c;程序直接运行在硬件上&#xff0c;开发者要自行处理硬件细节。早期单片机常采用&#xff0c;优点是性能和资源利用率高&#xff0c;缺点是开发难、可移植性差。RTOS 是实时操作系统&…

vscode导入的包裹代码名称没有颜色

问题描述:代码其他染色正常,但是例如import torchtorch没有颜色,虽然能够识别(ctrl左键能够点进去看到torch代码) 解决: 下载extention pylancefile->preferences->settings, 搜索Python: Language Server, 从default改成pylance

JAVA—IO流

存储数据的方案File和文件数据的操作IO流&#xff0c;学习字节流和字符流&#xff0c;了解框架和IO框架Commons IO 目录 1.File &#xff08;1&#xff09;创建对象 &#xff08;2&#xff09;常用方法 【1】判断类型&#xff0c;获取信息 【2】创建文件&#xff0c;删除…

LNMP学习

一、LNMP—web 1. 概述 LNMP/LAMP linux/windows/unix apache/nginx mysql/pgsql php/jsp 2. nginx部署及其平滑升级 实操 3. nginx七层负载均衡及算法 算法参考文档&#xff1a;https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/ 实操 4…

flv格式转换mp4怎么转换?5个软件帮助你自己快速进行格式转换

flv格式转换mp4怎么转换&#xff1f;5个软件让你从此快速转换格式不求别人 将FLV格式的视频转换为MP4格式可以通过使用以下五款软件来轻松实现。这些工具操作简便&#xff0c;能够快速高效地完成视频格式的转换&#xff0c;让你轻松应对各种视频格式需求。 口袋视频转换器 这…

网安新声 | 网易云音乐崩了:网络安全如何守护在线体验

网安加社区【网安新声】栏目&#xff0c;汇聚网络安全领域的权威专家与资深学者&#xff0c;紧跟当下热点安全事件、剖析前沿技术动态及政策导向&#xff0c;以专业视野和前瞻洞察&#xff0c;引领行业共同探讨并应对新挑战的策略与可行路径。 8月19日&#xff0c;#网易云音乐崩…

“休闲化“趋势增强,IAA手游出海如何抓住增长机遇?

进入存量时代&#xff0c;全球手游市场正面临严峻的挑战。数据显示&#xff0c;2023年 App Store 和 Google Play 的全球双端下载量同比下降10%&#xff0c;IAP 收入也同比减少2%。而作为大盘的支柱品类&#xff0c;中重度手游首当其冲。以 RPG 和 SLG 品类为例&#xff0c;虽然…

Halo个人博客Docker部署结合内网穿透为本地站点配置公网地址远程访问

文章目录 前言1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤&#xff1a;1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 前言 本文主要介绍如何在Cen…

常见计算机网络协议汇总(非常详细)从零基础入门到精通,看完这一篇就够了

文章目录 前言计算机网络五层模型回顾应用层协议 DNS协议&#xff1a;HTTP协议HTTPS协议 传输层协议 UDP协议TCP 网络层 IP协议ICMP协议 数据链路层 ARP协议 物理层整体的网络传输流程 1️⃣网络安全零基础入门 ① 学习路线② 路线对应学习视频 2️⃣视频配套资料&国内外网…

二分+前缀和+思维,CF 1902D - Robot Queries

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1902D - Robot Queries 二、解题报告 1、思路分析 不管怎么反转: 起点终…

【新品实测】C1001毫米波人体检测传感器来了!跌倒检测、睡眠监测更准确!

我们最近推出了一款全新的60G毫米波产品&#xff1a;C1001毫米波人体检测传感器。在这篇文章中&#xff0c;我们将深入测评这款产品的性能&#xff0c;并详细解析C1001毫米波人体检测传感器的功能和特性。 产品链接&#xff1a;C1001 60GHz毫米波人体检测传感器 原文链接&…

QML ScrollView 实现自动滚动到底部

先看效果,每当有新的日志,会自动添加到Text中,主要实现了ScrollView自动滑动到底部,显示最新的日志 目录 1.思路2.position分析 1.思路 在官网中scrollview并没有关于scrollview位置的设置 但是我们可以控制右边滑动条scrollbar的位置 注意position并不是一个高度数据,你可以…

Adobe Dreamweaver(DW)网页代码编辑器win/mac软件安装下载

一、Adobe DW软件概览 1.1 DW软件简介 Adobe Dreamweaver&#xff08;简称DW&#xff09;是一款功能强大的网页代码编辑器&#xff0c;由Adobe公司开发并维护。其全称为“Adobe Dreamweaver”&#xff0c;中文译为“梦想编织者”。DW集网页制作和管理网站于一身&#xff0c;支…

Allegro PCB位号重排反标原理图步骤

第一步&#xff1a;也是最重要的一步&#xff0c;备份整个工程文件夹。 防止操作过程中误操作导致工程文件出问题&#xff0c;万一出问题&#xff0c;没有备份&#xff0c;调整代价比较大 第二步&#xff1a;确认当前PCB和原理图的网表统一。 稳妥做法&#xff1a; 2a:原理图…

Linux入门——07 动静态库软硬连接

1.动静态库 静态库&#xff08;.a&#xff09;&#xff1a;程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库动态库&#xff08;.so&#xff09;&#xff1a;程序在运行的时候才去链接动态库的代码&#xff0c;多个程序共享使用库的代码。一…

如何在VMware ESXI中创建Linux虚拟机并实现异地SSH远程访问

目录 ⛳️推荐 前言 1. 在VMware ESXI中创建Ubuntu虚拟机 2. Ubuntu开启SSH远程服务 3. 安装Cpolar工具 4. 使用SSH客户端远程访问Ubuntu 5. 固定TCP公网地址 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…