总结:Spring创建Bean循环依赖问题与@Lazy注解使用详解

news2024/9/29 11:29:02

总结:Spring创建Bean循环依赖问题与@Lazy注解使用详解

  • 一·前提知识储备:
    • 1.Spring Bean生命周期机制(IOC)
    • 2.Spring依赖注入机制(DI)
      • (1)@Autowired注解标注属性set方法注入
      • (2)@Autowired注解标注属性注入
      • (3)@Autowired注解标注构造方法注入,也可用于存在多个构造方法时,手动指明Spring框架使用哪个构造方法创建Bean
    • 3.了解一定的JVM类加载原理机制
      • (1)第一次使用new关键字调用类构造方法创建对象时,会触发类加载机制,然后再执行类实例化机制
      • (2)每创建一个对象,就会触发类实例化机制一次,注意不是类加载机制
      • (3)先产生一个对象的内存地址,再调用类的 `clinit`方法(由编译器自动生成,用于初始化静态变量和执行静态初始化块的代码),最后才执行类的构造方法。
      • (4)因此一个对象的内存地址,可以在构造方法结束之前暴露出来。但Spring中所谓的提前暴露bean对象地址,都是指构造方法结束之后暴露,而不是构造方法结束之前暴露
    • 4.@Lazy注解使用:
      • (1)使用地方:类、方法、构造方法、方法参数、属性字段。必须标注在IOC容器管理的bean上才会生效,否则无效果
      • (2)功能作用:Springboot项目启动时,懒加载Bean。即只会分配对象地址并暴露在IOC容器里面,但不会立即执行该Bean的实例化操作(构造方法)
      • (3)标注在类上示例:延迟创建
      • (4)标注在方法上示例:延迟注入
      • (5)标注在构造方法参数上示例:延迟注入。直接标注在构造方法上面没效果,加在构造方法参数上才有效果
      • (6)标注在属性字段上示例:
  • 二·什么是Spring Bean循环依赖问题:
    • 1.类A中存在类B属性,类B中存在类C属性,类C中存在类A属性,等类似情况:
    • 2.类A中存在类A属性,等类似情况:
    • 3.Spring项目启动会报异常提示:
  • 三·如何解决Spring Bean循环依赖:
    • 方案一:尽量避免双向依赖(根本上解决):设计时尽量避免双向依赖,因为双向依赖很容易导致循环依赖的发生。(推荐)
    • 方案二:使用构造函数注入 + @Lazy注解:(推荐)
    • 方案三:使用字段属性注入 + application.yml配置:
    • 方案四:使用字段属性注入 + @Lazy注解:(推荐)
  • 四·Spring解决循环依赖的底层原理:概述
    • 1.三级缓存容器:
    • 2.为什么Bean 都已经实例化了,还需要一个生产 Bean 的ObjectFactory工厂呢?
    • 3.三级缓存容器工作流程示例:假设现在需要实例化两个对象:A、B
      • (1)不存在循环依赖、或者存在循环依赖但不存在AOP操作:
      • (2)存在循环依赖、存在AOP操作:
    • 4.为什么要再包装一层ObjectFactory对象存入三级缓存呢?说是为了解决Bean对象存在AOP代理情况,那么直接生成代理对象半成品Bean放入二级缓存中,这不就可以省略三级缓存了吗?所以这使用三级缓存的意义在哪里?
    • 5.使用构造器注入,造成的循环依赖,三级缓存机制无法自动解决:
    • 6.为什么构造器注入,配合@Lazy注解就能解决循环依赖问题呢?
    • 7·参考文献链接:

一·前提知识储备:

1.Spring Bean生命周期机制(IOC)

在这里插入图片描述
注意:bean实例化就是指调用构造方法创建bean的过程

参考详情文献:

https://blog.csdn.net/riemann_/article/details/118500805

2.Spring依赖注入机制(DI)

参考详情文献:
https://juejin.cn/post/6857406008877121550#heading-17

(1)@Autowired注解标注属性set方法注入

@Component
public class Dog {

    // 私有成员变量
    private Cat cat;

    // 使用@Autowired注解标注setter方法
    @Autowired
    public void setCat(Cat cat) {
        this.cat = cat;
    }

    // 其他业务逻辑...
}

(2)@Autowired注解标注属性注入

@Component
public class Dog {
    @Autowired
    private Cat cat;
}

(3)@Autowired注解标注构造方法注入,也可用于存在多个构造方法时,手动指明Spring框架使用哪个构造方法创建Bean

@Component
public class Dog {

    private Cat cat;

    @Autowired
    public Dog(Cat cat) {
        this.cat = cat;
    }
}

3.了解一定的JVM类加载原理机制

参考详情文献:
https://blog.csdn.net/weixin_48033662/article/details/135246047

(1)第一次使用new关键字调用类构造方法创建对象时,会触发类加载机制,然后再执行类实例化机制

(2)每创建一个对象,就会触发类实例化机制一次,注意不是类加载机制

(3)先产生一个对象的内存地址,再调用类的 clinit方法(由编译器自动生成,用于初始化静态变量和执行静态初始化块的代码),最后才执行类的构造方法。

(4)因此一个对象的内存地址,可以在构造方法结束之前暴露出来。但Spring中所谓的提前暴露bean对象地址,都是指构造方法结束之后暴露,而不是构造方法结束之前暴露

示例代码如下:

public class Example {
    private String value;
    private Example next;

    public Example(String value) {
        // 开启新线程并让其尝试访问this.value
        new Thread(() -> {
            //将当前对象内存地址,赋给next属性,提前暴露当前对象地址
            System.out.println("异步线程next:" + next);
            System.out.println("新线程:" + this.value);
        }).start();

        //将当前对象内存地址,赋给next属性,提前暴露当前对象地址
        next = this;
        System.out.println("主线程next:" + next);

        // 睡眠一段时间模拟初始化耗时操作
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        this.value = value;
        System.out.println("构造方法内部:value已初始化为 " + this.value);
    }

    public static void main(String[] args) {
        Example example = new Example("Hello, World!");
        // 此时example引用已经可以获取,但value字段还未初始化
        System.out.println("example:" + example);
    }
}

4.@Lazy注解使用:

(1)使用地方:类、方法、构造方法、方法参数、属性字段。必须标注在IOC容器管理的bean上才会生效,否则无效果

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {

	/**
	 * Whether lazy initialization should occur.
	 */
	boolean value() default true;

}

(2)功能作用:Springboot项目启动时,懒加载Bean。即只会分配对象地址并暴露在IOC容器里面,但不会立即执行该Bean的实例化操作(构造方法)

注意:
(1)简述:虽然会创建该类的一个对象,但是不会执行该对象的构造方法
(2)没有标注该注解或者进行特定配置时,Springboot项目启动时,会默认将扫描范围内的所有Bean进行实例化操作(既创建该类对象,又执行该对象的构造方法)

(3)标注在类上示例:延迟创建

@Lazy
@Component
public class Cat {
    private String name;
    private int age;

    public Cat() {
        System.out.println("Cat无参构造方法执行");
    }
}

(4)标注在方法上示例:延迟注入

注意:@Lazy注解 + @Configuration注解同时标注在类上,会作用所有@Bean注册的类实例

@Configuration
public class IocConfig {
    @Lazy
    @Bean
    public Dog dog(){
        return new Dog();
    }
}

(5)标注在构造方法参数上示例:延迟注入。直接标注在构造方法上面没效果,加在构造方法参数上才有效果

@Component
public class Cat {
    private Dog dog;

    @Autowired
    public Cat(@Lazy Dog dog) {
        this.dog = dog;
    }
}

(6)标注在属性字段上示例:

@Component
public class Cat {
    @Lazy
    @Autowired
    private Dog dog;
}

二·什么是Spring Bean循环依赖问题:

1.类A中存在类B属性,类B中存在类C属性,类C中存在类A属性,等类似情况:

在这里插入图片描述
示例代码:
类A

@Component
public class A {
    @Autowired
	private B b;
}

类B:

@Component
public class B {
    @Autowired
	private C c;
}

类C:

@Component
public class C {
    @Autowired
	private A a;
}

2.类A中存在类A属性,等类似情况:

在这里插入图片描述
示例代码:

@Component
public class A {
    @Autowired
	private A a;
}

3.Spring项目启动会报异常提示:

在这里插入图片描述

三·如何解决Spring Bean循环依赖:

方案一:尽量避免双向依赖(根本上解决):设计时尽量避免双向依赖,因为双向依赖很容易导致循环依赖的发生。(推荐)

方案二:使用构造函数注入 + @Lazy注解:(推荐)

(1)当有两个类互相依赖时,只要在任意一个类的构造方法上,将另一方参数标注@Lazy注解即可打破循环引用;当然两个类构造方法互相都加也行

(2)若很多个类才构成循环依赖,则建议直接将每个类的构造方法上对方参数都标注@Lazy注解;否则你就一个个去分析循环依赖,然后再单个加@Lazy注解吧

注意:构造函数注入是解决循环依赖问题的最佳方式之一,因为它能够保证Bean在实例化时所有依赖已经注入。

示例代码:

@Component
public class Cat {
    private Dog dog;

	/**
     * 构造方法注入属性对象时,被标注@Lazy注解的参数对象,并不会直接触发Dog类的实例化操作,
     * 而是会先放入一个dog的代理对象在这里,当后面该dog的代理对象被第一次调用时,才会触发Dog的实例化操作,
     * 但是生成的实例化对象并不会替换原本的代理对象,只会将实例化对象注入代理对象里面。
     * (代理对象在其内部维护对实际实例的引用,在后续每次调用时,代理对象都会将请求转发给已经实例化的原生对象,并返回原生对象的方法执行结果)
     * @param dog
     */
    @Autowired
    public Cat(@Lazy Dog dog) {
    	//注意这里不能在构造方法里面调用dog对象,一旦调用就会立即触发Dog的实例化操作
        this.dog = dog;
    }
}
@Component
public class Dog {
    private Cat cat;
	
	//只要保证一方加了@Lazy注解就行
    @Autowired
    public Dog(@Lazy Cat cat) {
        this.cat = cat;
    }
}

方案三:使用字段属性注入 + application.yml配置:

application.yml配置如下:

#允许Spring循环引用配置,默认是关闭的
spring:
  main:
    allow-circular-references: true

(1)开启后Springboot会主动尝试利用三级缓存机制来打破循环引用。如果实在打破不了,就会抛循环引用异常让用户自己解决(可以配合@Lazy注解解决)

(2)一般使用@Autowired注入属性的循环依赖,都可以被Springboot主动打破

(3)Spring无法解决单纯由构造器注入导致的循环依赖,因为Java语言本身的特性决定了构造器调用必须在一个实例化阶段完成,无法通过延后注入的方式打破循环(可以配合@Lazy注解解决)

(4)非单例bean造成的循环引用,Spring也无法自动解决

代码示例:

@Component
public class Cat {
    @Autowired
    private Dog dog;

	//手动指明使用哪个构造方法创建bean
    @Autowired
    public Cat() {
        System.out.println("Cat无参构造方法执行");
    }
}
@Component
public class Dog {
    @Autowired
    private Cat cat;

    @Autowired
    public Dog() {
        System.out.println("Dog无参构造方法执行");
    }
}

方案四:使用字段属性注入 + @Lazy注解:(推荐)

(1)当有两个类互相依赖时,只要在任意一个类中另一方的属性字段上标注@Lazy注解,即可打破循环引用;当然两个类相都加也行

(2)若很多个类才构成循环依赖,则建议直接将每个类的另一方属性字段都标注@Lazy注解;否则你就一个个去分析循环依赖,然后再单个加@Lazy注解吧

代码示例:

@Component
public class Cat {
    @Lazy
    @Autowired
    private Dog dog;

	@Autowired
    public Cat() {
        System.out.println("Cat无参构造方法执行");
    }
}
@Component
public class Dog {
    @Lazy
    @Autowired
    private Cat cat;

    @Autowired
    public Dog() {
        System.out.println("Dog无参构造方法执行");
    }
}

四·Spring解决循环依赖的底层原理:概述

1.三级缓存容器:

public class DefaultSingletonBeanRegistry ... {
  //1、最终单例Bean容器,里面bean都已经完成了实例化、属性注入、初始化,称之为"一级缓存"
  Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
  //2、早期Bean单例池,缓存半成品对象(完成了实例化,但未完成属性注入、未执行初始化 init 方法),且当前对象已经被其他对象引用了,称之为"二级缓存"
  Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
  //3、单例Bean的工厂池,缓存半成品对象(完成了实例化,但未完成属性注入、未执行初始化 init 方法),对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
  Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}

2.为什么Bean 都已经实例化了,还需要一个生产 Bean 的ObjectFactory工厂呢?

这跟循环依赖期间存在AOP操作有关:

(1)若不存在循环依赖、或者存在循环依赖但没有AOP操作时,ObjectFactory的getObject()方法返回的是,原本bean实例对象

(2)若存在循环依赖且存在AOP操作时,ObjectFactory的getObject()方法返回的是,原本bean实例的代理对象(提前创建代理对象,原本Spring的设计模式是bean实例化、属性注入、初始化之后,再创建代理对象的,但这种特殊情况为了解决循环依赖,只能提前创建。因此Spring框架在极端情况下,可能出现bean后置处理器方法在属性注入、初始化方法前执行,但问题也能解决)

3.三级缓存容器工作流程示例:假设现在需要实例化两个对象:A、B

(1)不存在循环依赖、或者存在循环依赖但不存在AOP操作:

1.先从一级、二级、三级缓存容器找对象A,发现没有
2.执行A的构造方法进行实例化,但未执行属性注入、初始化操作(@PostConstruct),A 只是一个半成品。
3.将早期的A暴露出去,放到三级缓存容器singletonFactories中,bean对象会被ObjectFactory包装起来
4.A进行属性注入,发现没有依赖其他未创建的对象
5.A进行初始化操作(@PostConstruct),完成bean创建工作
6.然后会调用addSingleton方法,将自己丢到一级缓存中,并将自己从二级、三级缓存中移除(实际只有三级缓存容器有对象)
7.再按照上述步骤创建B对象,从步骤1开始
......

(2)存在循环依赖、存在AOP操作:

1.先从一级、二级、三级缓存容器找对象A,发现没有
2.实例化A,此时 A 还未完成属性填充和初始化方法(@PostConstruct)的执行,A 只是一个半成品。
3.提前暴露A引用,为 A 创建一个 Bean 工厂,并放入到  singletonFactories 中。
4.属性注入A,发现 A 需要注入 B 对象,但是一级、二级、三级缓存均为发现对象 B5.实例化B,此时 B 还未完成属性填充和初始化方法(@PostConstruct)的执行,B 只是一个半成品。
6.提前暴露B引用,为 B 创建一个 Bean 工厂,并放入到  singletonFactories 中。
7.属性注入B,发现 B 需要注入 A 对象,此时在一级、二级未发现对象 A,但是在三级缓存中发现了对象 A,从三级缓存中得到对象 A,
并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A。(注意,此时的 A 还是一个半成品,并没有完成属性填充和执行初始化方法),
然后将对象 A 注入到对象 B 中,对象 B 完成属性填充
8.执行B初始化方法,B对象彻底创建完成。
9.B对象放入到一级缓存中,同时删除三级缓存中的对象 B。(此时对象 B 已经是一个成品)
10.对象 A 得到对象 B,将对象 B 注入到对象 A 中,对象 A 完成属性填充。(对象 A 得到的是一个完整的对象 B11.执行A初始化方法,A对象彻底创建完成
12.A对象放入到一级缓存中,同时删除二级缓存中的对象 A。(此时对象 A 已经是一个成品)

4.为什么要再包装一层ObjectFactory对象存入三级缓存呢?说是为了解决Bean对象存在AOP代理情况,那么直接生成代理对象半成品Bean放入二级缓存中,这不就可以省略三级缓存了吗?所以这使用三级缓存的意义在哪里?

  • (1)正常情况下(没有循环依赖):

  • (1-1)Spring都是在完全创建好Bean之后,才创建对应的代理对象

  • (2)为了处理循环依赖,Spring有三种选择:

  • (2-1)不管有没有循环依赖,直接将半成品bean对象放入二级缓存,用于解决循环依赖问题。(会导致无法注入AOP代理对象,只能是原生bean实例对象

  • (2-2)不管有没有循环依赖,都提前创建好代理对象,并将代理对象放入二级缓存,出现循环依赖时,其他对象直接就可以取到代理对象并注入。(会导致无法注入原生bean实例对象,只能是AOP代理对象

  • (2-3)加一个中间层,只有出现循环依赖且存在AOP操作时,才会提前生成代理对象,其他情况下都是返回原生bean实例对象。(这样就极大可能保证Spring按照原本AOP代理设计模式进行创建bean,且又能解决循环依赖问题

注意:虽然加一个中间层,看似极大的兼顾了两种情况。但Spring框架在极端情况下,还是可能出现bean后置处理器方法在属性注入、初始化方法前执行,但该问题也能通过合理手段解决

5.使用构造器注入,造成的循环依赖,三级缓存机制无法自动解决:

因为构造器循环依赖是发生在bean实例化阶段,此时连bean的构造方法都没执行完,早期对象都无法创建出来。因此也无法放到三级缓存。三级缓存只能是在bean实例化之后,才能起到作用

6.为什么构造器注入,配合@Lazy注解就能解决循环依赖问题呢?

(1)示例代码:

@Component
public class Cat {
    private Dog dog;

	/**
     * 构造方法注入属性对象时,被标注@Lazy注解的参数对象,并不会直接触发Dog类的实例化操作,
     * 而是会先放入一个dog的代理对象在这里,当后面该dog的代理对象被第一次调用时,才会触发Dog的实例化操作,
     * 但是生成的实例化对象并不会替换原本的代理对象,只会将实例化对象注入代理对象里面。
     * (代理对象在其内部维护对实际实例的引用,在后续每次调用时,代理对象都会将请求转发给已经实例化的原生对象,并返回原生对象的方法执行结果)
     * @param dog
     */
    @Autowired
    public Cat(@Lazy Dog dog) {
    	//注意这里不能在构造方法里面调用dog对象,一旦调用就会立即触发Dog的实例化操作
        this.dog = dog;
    }
}

(2)使用构造器注入 + @Lazy注解,解决循环依赖的工作流程示例:一句话,@Lazy 注解是通过建立一个中间代理层,来破解循环依赖的

1.从一、二、三级缓存总找不到cat对象,开始实例化cat对象
2.由于Cat构造器参数dog上标注了@Lazy注解,因此Spring执行构造方法时,会创建一个代理对象赋给dog属性
3.cat对象成功创建实例对象,放入三级缓存里面
4.cat对象再执行属性注入、初始化操作,完成最终bean创建
5.cat对象最后放入单例池里面(一级缓存),删除二、三级缓存里面的cat对象
6.当cat对象的dog属性被第一次调用时(dog此时是代理对象),会触发Dog类的实例化操作,生成实例化对象dog2
7.dog2对象再执行属性注入、初始化方法,完成最终bean创建,放入单例池(一级缓存)
8.Spring最后再将dog2对象注入到cat对象的dog属性的代理对象里面
(生成的实例化对象并不会替换原本的代理对象,只会将实例化对象注入代理对象里面。代理对象在其内部维护对实际实例的引用,
在后续每次调用时,代理对象都会将请求转发给已经实例化的原生对象,并返回原生对象的方法执行结果)

7·参考文献链接:

Spring 解决循环依赖必须要三级缓存吗?
Spring循环依赖解决方案
Spring使用三级缓存解决循环依赖?
spring中怎么解决循环依赖的问题
Spring系列第28篇:Bean循环依赖详解

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

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

相关文章

面具安装LSP模块时提示 Unzip error错误的解决办法

面具(Magisk Delta)安装LSP模块时提示 Unzip error错误的解决办法 ​​ 如果前面的配置都正常的话&#xff0c;可能是LSP版本有问题重新去Github下载一个最新版的吧&#xff1b;我是这么解决的。 我安装1.91那个版本的LSP就是死活安装不上&#xff0c;下载了1.92的版本一次就…

Golang-channel合集——源码阅读、工作流程、实现原理、已关闭channel收发操作、优雅的关闭等面试常见问题。

前言 面试被问到好几次“channel是如何实现的”&#xff0c;我只会说“啊&#xff0c;就一块内存空间传递数据呗”…所以这篇文章来深入学习一下Channel相关。从源码开始学习其组成、工作流程及一些常见考点。 NO&#xff01;共享内存 Golang的并发哲学是“要通过共享内存的…

⭐每天一道leetcode:83.删除排序链表中的重复元素(简单;链表遍历、删除经典题目)

⭐今日份题目 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例1 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2] 示例2 输入&#xff1a;head [1,1,2,3,3] 输出&#xff1a;[1,2,3] …

Linux 进程程序替换

&#x1f493;博主CSDN主页:麻辣韭菜-CSDN博客&#x1f493;   ⏩专栏分类&#xff1a;http://t.csdnimg.cn/G90eI⏪   &#x1f69a;代码仓库:Linux: Linux日常代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d;&#x1f5…

考研经验|如何从考研失败中走出来?

对我来说&#xff0c;太丢人了 其实我在本科的时候在同学眼中&#xff0c;一直很优秀&#xff0c;每年奖学金必有我的&#xff0c;国家励志奖学金&#xff0c;国家奖学金&#xff0c;这种非常难拿的奖学金&#xff0c;我也拿过&#xff0c;本科期间学校有一个公费去新西兰留学的…

美化console

console简介 控制台&#xff08;Console&#xff09;是JS开发里最重要的面板&#xff0c;主要作用是显示网页加载过程中产生各类信息,我们经常使用console.log()这个函数在控制台打印一些东西 但是,console这个对象不仅仅有log这个函数,还有很多其他的函数,如下 console.de…

vue学习笔记22-组件传递多种数据类型props效验

组件传递多种数据类型 通过props传递数据&#xff0c;不仅可以传递字符串类型的数据&#xff0c;还可以是其他类型&#xff0c;例如&#xff1a;数字、对象、数组等&#xff0c;但实际上任何类型的值都可以作为props的值被传递&#xff08;即组件与组件之间的传递是没有限制的…

Text Field文本输入框

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Text Field文本输入框 一、最基本的本文输入框1、基础示例2、一些表单属性3、验证 二、多行文本 一、最基本的本文输入框 1、基础示例 import {Box, TextField} from "…

CSS拖曳盒子案例

让我为大家带来一个小案例吧&#xff01; <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>* {margin: 0;padding: 0;}.box1 {width: 100px;height: 100px;background-color: black;margin-bot…

基于springboot+layui仓库管理系统设计和实现

基于 java springbootlayui仓库管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取…

HarmonyOS(二)Ability应用模型概述

目录 1 Ability概念 2 Ability形态 3 Stage优势 4 Stage模型结构 5 总结 注&#xff1a;本章内容提前声明。 基于HarmonyOS开发者3.1/4.0版本配套的开发者文档&#xff0c;对应API能力级别为API 9 Release。 详情可参考官网API入门第一章应用模型文档中心 1 Ability概念…

机器学习(五) -- 监督学习(1) -- 线性回归

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理&#xff08;1-3&#xff09; 机器学习&#xff08;三&#xff09; -- 特征工程&#xff08;1-2&#xff09; 机器学习&#xff08;四&#xff09; -- 模型评估…

【LeetCode: 212. 单词搜索 II - dfs】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

harmonyos arkts 开发商品页面

1.结果展示 2. 实现分层组件 1.1 实现搜索栏 1.2 代码 这段代码是一个构建搜索框组件的方法&#xff0c;具体功能包括&#xff1a; - 创建一个Search组件&#xff0c;设置初始值为this.keyword&#xff0c;placeholder为请输入书名... - 添加一个搜索按钮&#xff0c;并设置…

【UVM_phase objection_2024.03.08

phase 棕色&#xff1a;function phase 不消耗仿真时间 绿色&#xff1a;task phase 消耗仿真时间 run_phase与右边的phase并行执行&#xff0c;右边的phase&#xff08;run_time phase&#xff09;依次执行&#xff1a; List itemreset_phase对DUT进行复位&#xff0c;初始…

嵌入式学习day34 网络

TCP包头: 1.序号:发送端发送数据包的编号 2.确认号:已经确认接收到的数据的编号(只有当ACK为1时,确认号才有用) TCP为什么安全可靠: 1.在通信前建立三次握手连接 SYN SYNACK ACK 2.在通信过程中通过序列号和确认号保障数据传输的完整性 本次发送序列号:上次…

LVS+Keepalived 高可用负载均衡集群

一. 高可用集群的相关知识 1.1 高可用&#xff08;HA&#xff09;集群和普通集群的比较 ① 普通集群 普通的群集的部署是通过一台度器控制调配多台节点服务器进行业务请求的处理&#xff0c;但是仅仅是一台调度器&#xff0c;就会存在极大的单点故障风险&#xff0c;当该调度…

HTML5 Web Worker之性能优化

描述 由于 JavaScript 是单线程的&#xff0c;当执行比较耗时的任务时&#xff0c;就会阻塞主线程并导致页面无法响应&#xff0c;这就是 Web Workers 发挥作用的地方。它允许在一个单独的线程&#xff08;称为工作线程&#xff09;中执行耗时的任务。这使得 JavaScript 代码可…

openssl3.2 - exp - 选择最好的内建椭圆曲线

文章目录 openssl3.2 - exp - 选择最好的内建椭圆曲线概述笔记将 openssl ecparam -list_curves 实现迁移到自己的demo工程备注END openssl3.2 - exp - 选择最好的内建椭圆曲线 概述 在openssl中使用椭圆曲线, 只允许选择椭圆曲线的名字, 无法给定椭圆曲线的位数. 估计每种椭…

硬件工程师面试题梳理-百度硬件面试题

硬件工程师基本职责 在公司里面&#xff0c;硬件工程师的主要职责包括设计、开发和测试硬件系统&#xff0c;以满足产品需求和性能要求。他们负责确保硬件系统的可靠性、稳定性和可维护性&#xff0c;并与软件工程师和其他团队成员合作&#xff0c;以确保硬件和软件的协同工作…