Spring高手之路8——Spring Bean模块装配的艺术:@Import详解

news2024/9/23 19:16:46

文章目录

  • 1. Spring手动装配基础
  • 2. Spring框架中的模块装配
    • 2.1 @Import注解简单使用
  • 3. @Import模块装配的四种方式
    • 3.1 @Import注解的功能介绍
    • 3.2 导入普通类与自定义注解的使用
    • 3.3 导入配置类的策略
    • 3.4 使用ImportSelector进行选择性装配
    • 3.5 使用ImportBeanDefinitionRegistrar进行动态装配

1. Spring手动装配基础

  在Spring中,手动装配通常是指通过XML配置文件明确指定Bean及其依赖,或者在代码中直接使用new关键字创建对象并设定依赖关系。

  然而,随着Spring 2.0引入注解,以及Spring 3.0全面支持注解驱动开发,这个过程变得更加自动化。例如,通过使用@Component + @ComponentScanSpring可以自动地找到并创建bean,通过@AutowiredSpring可以自动地注入依赖。这种方式被称为 “自动装配”。

  对于手动装配,最常见的场景可能是在不使用Spring的上下文的单元测试或者简单的POJO类中,通过new关键字直接创建对象和设定依赖关系。比如下面这段代码:

public class Main {
    public static void main(String[] args) {
        ServiceA serviceA = new ServiceA();
        ServiceB serviceB = new ServiceB(serviceA);
        //...
    }
}

  在这个例子中,我们显式地创建了ServiceAServiceB的对象,并将ServiceA的对象作为依赖传递给了ServiceB。这就是一个典型的手动装配的例子。

  需要注意的是,手动装配的使用通常是有限的,因为它需要开发者显式地在代码中管理对象的创建和依赖关系,这在大型应用中可能会变得非常复杂和难以管理。因此,Spring的自动装配机制(例如@Autowired注解,或者@Configuration@Bean的使用)通常是更常见和推荐的方式。


2. Spring框架中的模块装配

  模块装配就是将我们的类或者组件注册到SpringIoCInversion of Control,控制反转)容器中,以便于Spring能够管理这些类,并且在需要的时候能够为我们自动地将它们注入到其他的组件中。

Spring框架中,有多种方式可以实现模块装配,包括:

  1. 基于Java的配置:通过使用@Configuration@Bean注解在Java代码中定义的Bean。这是一种声明式的方式,我们可以明确地控制Bean的创建过程,也可以使用@Value@PropertySource等注解来处理配置属性。

  2. 基于XML的配置Spring也支持通过XML配置文件定义Bean,这种方式在早期的Spring版本中更常见,但现在基于Java的配置方式更为主流。

  3. 基于注解的组件扫描:通过使用@Component@Service@Repository@Controller等注解以及@ComponentScan来自动检测和注册Bean。这是一种隐式的方式,Spring会自动扫描指定的包来查找带有这些注解的类,并将这些类注册为Bean

  4. 使用@Import:这是一种显式的方式,可以通过它直接注册类到IOC容器中,无需这些类带有@Component或其他特殊注解。我们可以使用它来注册普通的类,或者注册实现了ImportSelectorImportBeanDefinitionRegistrar接口的类,以提供更高级的装配能力。

  每种方式都有其应用场景,根据具体的需求,我们可以选择合适的方式来实现模块装配。比如在Spring Boot中,我们日常开发可能会更多地使用基于Java的配置和基于注解的组件扫描来实现模块装配。

2.1 @Import注解简单使用

  @Import是一个强大的注解,它为我们提供了一个快速、方便的方式,使我们可以将需要的类或者配置类直接装配到Spring IOC容器中。这个注解在模块装配的上下文中特别有用。

我们先来看一下简单的应用,后面再详细介绍

全部代码如下:

Book.java

package com.example.demo.bean;

public class Book {
    private String name;

    public Book() {
        this.name = "Imported Book";
    }
    
    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                '}';
    }
}

LibraryConfig.java

package com.example.demo.configuration;

import com.example.demo.bean.Book;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(Book.class)
public class LibraryConfig {
}

  使用 @Import 注解来导入一个普通的类(即一个没有使用 @Component 或者 @Service 之类的注解标记的类),Spring 会为该类创建一个 Bean,并且这个 Bean 的名字默认就是这个类的全限定类名。

主程序:

package com.example.demo;

import com.example.demo.bean.Book;
import com.example.demo.configuration.LibraryConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LibraryConfig.class);
        Book book = context.getBean(Book.class);
        System.out.println(book);
    }
}

运行结果如下:

在这里插入图片描述


3. @Import模块装配的四种方式

3.1 @Import注解的功能介绍

  在Spring中,有时候我们需要将某个类(可能是一个普通类,可能是一个配置类等等)导入到我们的应用程序中。Spring提供了四种主要的方式来完成这个任务,后面我们会分别解释。

@Import注解可以有以下几种使用方式:

  • 导入普通类:可以将普通类(没有被@Component或者@Service等注解标注的类)导入到SpringIOC容器中,Spring会为这个类创建一个Bean,这个Bean的名字默认为类的全限定类名。

  • 导入配置类:可以将一个或多个配置类(被@Configuration注解标注的类)导入到SpringIOC容器中,这样我们就可以一次性地将这个配置类中定义的所有Bean导入到SpringIOC容器中。

  • 使用ImportSelector接口:如果想动态地导入一些BeanSpringIOC容器中,那么可以实现ImportSelector接口,然后在@Import注解中引入ImportSelector实现类,这样Spring就会将ImportSelector实现类返回的类导入到SpringIOC容器中。

  • 使用ImportBeanDefinitionRegistrar接口:如果想在运行时动态地注册一些BeanSpringIOC容器中,那么可以实现ImportBeanDefinitionRegistrar接口,然后在@Import注解中引入ImportBeanDefinitionRegistrar实现类,这样Spring就会将ImportBeanDefinitionRegistrar实现类注册的Bean导入到SpringIOC容器中。

  @Import注解主要用于手动装配,它可以让我们显式地导入特定的类或者其他配置类到SpringIOC容器中。特别是当我们需要引入第三方库中的类,或者我们想要显式地控制哪些类被装配进SpringIOC容器时,@Import注解会非常有用。它不仅可以直接导入普通的 Java 类并将其注册为 Bean,还可以导入实现了 ImportSelectorImportBeanDefinitionRegistrar 接口的类。这两个接口提供了更多的灵活性和控制力,使得我们可以在运行时动态地注册 Bean,这是通过 @Configuration + @Bean 注解组合无法做到的。

  例如,通过 ImportSelector 接口,可以在运行时决定需要导入哪些类。而通过 ImportBeanDefinitionRegistrar 接口,可以在运行时控制 Bean 的定义,包括 Bean 的名称、作用域、构造参数等等。

  虽然 @Configuration + @Bean 在许多情况下都足够使用,但 @Import 注解由于其更大的灵活性和控制力,在处理更复杂的场景时,可能会是一个更好的选择。

3.2 导入普通类与自定义注解的使用

我们第2节的例子也是导入普通类,这里加一点难度,延伸到自定义注解的使用。

背景:图书馆模块装配
在这个例子中,我们将创建一个图书馆系统,包括图书馆(Library)类、图书馆管理员(Librarian)类、图书(Book)类,还有书架(BookShelf)类。我们的目标是创建一个图书馆,并将所有组件装配到一起。

首先,我们创建一个自定义@ImportLibrary注解,通过此注解我们将把所有相关的类装配到图书馆里面:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({Librarian.class, Book.class, BookShelf.class})
public @interface ImportLibrary {
}

  这个@ImportLibrary注解内部实际上使用了@Import注解。当Spring处理@Import注解时,会将其参数指定的类添加到Spring应用上下文中。当我们在Library类上使用@ImportLibrary注解时,Spring会将Librarian.classBook.classBookShelf.class这三个类添加到应用上下文中。

  然后,我们创建图书馆管理员(Librarian)、图书(Book)、书架(BookShelf)这三个类:

Librarian.java

package com.example.demo.bean;

public class Librarian {
    public void manage() {
        System.out.println("The librarian is managing the library.");
    }
}

Book.java

package com.example.demo.bean;

public class Book {
    private String name;

    // @ImportLibrary里面有@Import会自动装配,会调用无参构造,不写会报错
    public Book() {
    }

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

BookShelf.java

package com.example.demo.bean;

import java.util.List;

public class BookShelf {
    private List<Book> books;

    // @ImportLibrary里面有@Import会自动装配,会调用无参构造,不写会报错
    public BookShelf() {
    }

    public BookShelf(List<Book> books) {
        this.books = books;
    }

    public List<Book> getBooks() {
        return books;
    }
}

最后,我们创建一个图书馆(Library)类,并在这个类上使用我们刚刚创建的@ImportLibrary注解:

package com.example.demo.configuration;

import com.example.demo.annotations.ImportLibrary;
import com.example.demo.bean.Book;
import com.example.demo.bean.BookShelf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

@ImportLibrary
@Configuration
public class Library {

    @Bean
    public Book book1() {
        return new Book("The Catcher in the Rye");
    }

    @Bean
    public Book book2() {
        return new Book("To Kill a Mockingbird");
    }

    @Bean
    public BookShelf bookShelf(Book book1, Book book2) {
        return new BookShelf(Arrays.asList(book1, book2));
    }
}

然后我们可以创建一个启动类并初始化IOC容器,看看是否可以成功获取到Librarian类、BookShelf类和Book类的实例:

package com.example.demo;

import com.example.demo.bean.Book;
import com.example.demo.bean.BookShelf;
import com.example.demo.bean.Librarian;
import com.example.demo.configuration.Library;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Library.class);

        // 这行代码供调试查看使用
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        
        Librarian librarian = context.getBean(Librarian.class);
        BookShelf bookShelf = context.getBean("bookShelf", BookShelf.class);
        Book book1 = (Book) context.getBean("book1");
        Book book2 = (Book) context.getBean("book2");

        librarian.manage();
        bookShelf.getBooks().forEach(book -> System.out.println("Book: " + book.getName()));
    }
}

这个例子中,我们通过@Import注解一次性把LibrarianBookBookShelf这三个类导入到了SpringIOC容器中,这就是模块装配的强大之处。

调试结果
在这里插入图片描述

当我们使用 @Import 注解来导入一个普通的类(即一个没有使用 @Component 或者 @Service 之类的注解标记的类),Spring 会为该类创建一个 Bean,并且这个 Bean 的名字默认就是这个类的全限定类名。

运行结果:

在这里插入图片描述

3.3 导入配置类的策略

这里使用Spring@Import注解导入配置类,我们将创建一个BookConfig类和LibraryConfig类,然后在主应用类中获取Book实例。

全部代码如下:

创建一个配置类BookConfig,用于创建和配置Book实例:

package com.example.demo.configuration;

import com.example.demo.bean.Book;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BookConfig {
    @Bean
    public Book book() {
        Book book = new Book();
        book.setName("Imported Book");
        return book;
    }
}

在这里,我们定义了一个Book类:

package com.example.demo.bean;

public class Book {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

创建一个配置类LibraryConfig,使用@Import注解来导入BookConfig类:

package com.example.demo.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(BookConfig.class)
public class LibraryConfig {
}

主程序:

package com.example.demo;

import com.example.demo.bean.Book;
import com.example.demo.configuration.LibraryConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LibraryConfig.class);
        Book book = context.getBean(Book.class);
        System.out.println(book.getName());
    }
}

运行结果:

在这里插入图片描述

在这个例子中,当Spring容器启动时,它会通过@Import注解将BookConfig类导入到Spring 上下文中,并创建一个Bean。然后我们可以在主程序中通过context.getBean(Book.class)获取到Book的实例,并打印出书名。

3.4 使用ImportSelector进行选择性装配

如果我们想动态地选择要导入的类,我们可以使用一个ImportSelector实现。

全部代码如下:

定义一个 Book 类:

package com.example.demo.bean;

public class Book {
    private String name = "java从入门到精通";

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

创建图书馆管理员Librarian

package com.example.demo.bean;

public class Librarian {
    public void manage() {
        System.out.println("The librarian is managing the library.");
    }
}

定义一个 BookImportSelector,实现 ImportSelector 接口:

package com.example.demo.configuration;

import com.example.demo.bean.Librarian;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class BookImportSelector implements ImportSelector {

    /**
     * 这里示范2种方式,一种是拿到class文件后getName,一种是直接写全限定类名
     * @param importingClassMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] { "com.example.demo.bean.Book", Librarian.class.getName() };
    }
}

  ImportSelector接口可以在运行时动态地选择需要导入的类。实现该接口的类需要实现selectImports方法,这个方法返回一个字符串数组,数组中的每个字符串代表需要导入的类的全类名,我们可以直接在这里将 Book 类和 Librarian 类加入到了 Spring 容器中。

使用Class.getName()方法获取全限定类名的方式,比直接硬编码类的全名为字符串更推荐,原因如下:

  1. 避免错误:如果类名或包名有所改动,硬编码的字符串可能不会跟随变动,这可能导致错误。而使用Class.getName()方法,则会随类的改动自动更新,避免此类错误。
  2. 代码清晰:使用Class.getName()能让读代码的人更清楚地知道你是要引用哪一个类。
  3. 增强代码的可读性和可维护性:使用类的字节码获取全限定类名,使得代码阅读者可以清晰地知道这是什么类,增加了代码的可读性。同时,也方便了代码的维护,因为在修改类名或者包名时,不需要手动去修改硬编码的类名。

定义一个配置类 LibraryConfig,使用 @Import 注解导入 BookImportSelector

package com.example.demo.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(BookImportSelector.class)
public class LibraryConfig {
}

创建一个主应用类,从 SpringAnnotationConfigApplicationContext 中获取 Book 的实例:

package com.example.demo;

import com.example.demo.bean.Book;
import com.example.demo.bean.Librarian;
import com.example.demo.configuration.LibraryConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LibraryConfig.class);
        Book book = context.getBean(Book.class);
        Librarian librarian = context.getBean(Librarian.class);
        System.out.println(book.getName());
        librarian.manage();
    }
}

运行结果:

在这里插入图片描述

  在 Spring Boot 中,ImportSelector 被大量使用,尤其在自动配置(auto-configuration)机制中起着关键作用。例如,AutoConfigurationImportSelector 类就是间接实现了 ImportSelector,用于自动导入所有 Spring Boot 的自动配置类。

  我们通常会在Spring Boot启动类上使用 @SpringBootApplication 注解,实际上,@SpringBootApplication 注解中也包含了 @EnableAutoConfiguration@EnableAutoConfiguration 是一个复合注解,它的实现中导入了普通类 @Import(AutoConfigurationImportSelector.class)AutoConfigurationImportSelector 类间接实现了 ImportSelector接口,用于自动导入所有 Spring Boot 的自动配置类。

如下图:

在这里插入图片描述

3.5 使用ImportBeanDefinitionRegistrar进行动态装配

  ImportBeanDefinitionRegistrar接口的主要功能是在运行时动态的往Spring容器中注册Bean,实现该接口的类需要重写registerBeanDefinitions方法,这个方法可以通过参数中的BeanDefinitionRegistry接口向Spring容器注册新的类,给应用提供了更大的灵活性。

全部代码如下:

首先,定义一个 Book 类:

package com.example.demo.bean;

public class Book {
    private String name = "java从入门到精通";

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

定义一个 BookRegistrar 类,实现 ImportBeanDefinitionRegistrar 接口:

package com.example.demo.configuration;

import com.example.demo.bean.Book;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class BookRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Book.class);
        // 通过反射技术调用setter方法给name赋值,也可以在构造器赋值name,name需要调用beanDefinitionBuilder.addConstructorArgValue("战争与和平");
        beanDefinitionBuilder.addPropertyValue("name", "战争与和平");
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        registry.registerBeanDefinition("myBook", beanDefinition);
    }
}

下面来详细解释一下BookRegistrar类里面的registerBeanDefinitions方法和参数。

  • AnnotationMetadata importingClassMetadata: 这个参数表示当前被@Import注解导入的类的所有注解信息,它包含了该类上所有注解的详细信息,比如注解的名称,注解的参数等等。

  • BeanDefinitionRegistry registry: 这个参数是SpringBean定义注册类,我们可以通过它往Spring容器中注册Bean。在这里,我们使用它来注册我们的Book Bean

  在方法registerBeanDefinitions中,我们创建了一个BeanDefinition,并将其注册到SpringBeanDefinitionRegistry中。

  代码首先通过BeanDefinitionBuilder.genericBeanDefinition(Book.class)创建一个BeanDefinitionBuilder实例,这个实例用于构建一个BeanDefinition。我们使用addPropertyValue("name", "战争与和平")为该BeanDefinition添加一个name属性值。

  接着我们通过beanDefinitionBuilder.getBeanDefinition()方法得到BeanDefinition实例,并设置其作用域为原型作用域,这表示每次从Spring容器中获取该Bean时,都会创建一个新的实例。

  最后,我们将这个BeanDefinition以名字 "myBook" 注册到BeanDefinitionRegistry中。这样,我们就可以在Spring容器中通过名字 "myBook" 来获取我们的Book类的实例了。

接着定义一个配置类 LibraryConfig,使用 @Import 注解导入 BookRegistrar

package com.example.demo.configuration;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(BookRegistrar.class)
public class LibraryConfig {
}

创建一个主应用类,从 Spring ApplicationContext 中获取 Book 的实例:

package com.example.demo;

import com.example.demo.bean.Book;
import com.example.demo.configuration.LibraryConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class DemoApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LibraryConfig.class);
        Book book = context.getBean("myBook", Book.class);
        System.out.println(book.getName());
    }
}

运行结果:

在这里插入图片描述

  在这个例子中,我们使用 AnnotationConfigApplicationContext 初始化 Spring 容器并提供配置类。然后通过 context.getBean("book", Book.class)Spring 容器中获取名为 book 的实例。

  ImportBeanDefinitionRegistrar接口提供了非常大的灵活性,我们可以根据自己的需求编写任何需要的注册逻辑。这对于构建复杂的、高度定制的Spring应用是非常有用的。

  Spring Boot就广泛地使用了ImportBeanDefinitionRegistrar。例如,它的@EnableConfigurationProperties注解就是通过使用一个ImportBeanDefinitionRegistrar来将配置属性绑定到Beans上的,这就是ImportBeanDefinitionRegistrar在实践中的一个实际应用的例子。



欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------

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

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

相关文章

指针进阶详解

目录 指针基本概念 1.字符指针 2.指针数组 3.数组指针 对数组名的理解 小结 指针基本概念 在初阶指针中我们了解到一些指针的基本概念: 1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存 2.指针的大小是固定的4/8个字节&#xff08;32位/64位平台&…

详解c++---哈希封装

目录标题 哈希桶的代码哈希桶的修改迭代器的实现const迭代器 哈希桶的代码 通过前面的学习大家应该能够很容易的写出下面的代码&#xff1a; #pragma once #include<iostream> #include<vector> using namespace std; template<class K,class V> struct Ha…

2023年互联网行业研究报告

第一章 行业概况 互联网行业是一个广泛的领域&#xff0c;包括所有利用互联网技术进行商业活动的企业和组织。这个行业的核心是互联网&#xff0c;一个全球性的网络&#xff0c;连接着数以亿计的计算设备和用户&#xff0c;使他们可以共享信息、资源和服务。 互联网行业包括网…

apache 安装配置 基础篇(-)

download 地址 apache下载 ApacheHaus是免安装的&#xff0c; 然后解压上面的文件&#xff0c;把里面 因apache 默认端口是80&#xff0c;如果这个端口被占用&#xff0c;apache服务是启动不起来的 netstat -ano|findstr 80 apache 修改端口号 创建apache服务 在apa…

ESP32-H2 固件烧录需满足的硬件环境整理

ESP32-H2 默认通过 UART0 &#xff08;即 TXD&#xff08;GPIO24&#xff09;和 RXD&#xff08;GPIO23&#xff09;&#xff09;下载固件。 Windows 下可使用 Flash download tool 工具来下载编译后的 bin 文件&#xff1b; 运行 flash_download_tool.exe 的文件 选择开发…

SkyEye处理器仿真系列:龙芯2K1000处理器

​SkyEye简介&#xff1a; 天目全数字实时仿真软件SkyEye作为基于可视化建模的硬件行为级仿真平台&#xff0c;能够为嵌入式软件提供虚拟化运行环境&#xff0c;开发、测试人员可在该虚拟运行环境上进行软件开发、软件测试和软件验证活动。小到芯片&#xff0c;大到系统&#…

win10 DBeaver (升级)下载、安装、彻底卸载

DBeaver &#xff08;升级&#xff09;下载及安装 一、DBeaver 下载二、安装三、DBeaver 的基本使用 - mysql连接四、DBeaver 彻底卸载 DBeaver是一种通用数据库管理工具&#xff0c;适用于需要以专业方式使用数据的每个人&#xff1b;适用于开发人员&#xff0c;数据库管理员&…

苹果笔买原装的还是随便买?便宜好用的手写笔推荐

自从ipad和其他的平板电脑都搭配上了电容笔以后&#xff0c;电容笔很好地取代了我们的手指&#xff0c;书写的效率就大大提升了&#xff0c;但由于苹果原装电容笔的价格不够人性化&#xff0c;一直高居不下给普通人带来了很大的负担&#xff0c;特别是对于学生们来说&#xff0…

QT DAY1

做一个窗口界面 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow) {ui->setupUi(this);//设置窗口标题、图标this->setWindowTitle("Fly_Chat")…

6、Flume安装部署

按照采集通道规划&#xff0c;需在hadoop102&#xff0c;hadoop103&#xff0c;hadoop104三台节点分别部署一个Flume。可参照以下步骤先在hadoop102安装&#xff0c;然后再进行分发。 1、Flume入门 1.1、 Flume安装部署 1.1.1、 安装地址 &#xff08;1&#xff09; Flume官…

全网最牛,Web自动化测试Selenium八大元素定位实战(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 安装Selenium和下…

BFT 最前线|OpenAI暂时下线ChatGPT”浏览“功能;Stability AI CEO:5年内,人类程序员将不复存在

原创 | 文 BFT机器人 AI视界 TECHNOLOGY NEWS 01 Open AI暂时下线ChatGPT“浏览”功能 日前OpenAI方面宣布&#xff0c;面向ChatGPT Plus用户的"浏览"功能会在某些情况下出现故障&#xff0c;因此已于7月3日暂时禁用了这一功能。该功能是为了提高ChatGPT的搜索体验…

威胁检测和取证日志分析

在网络中&#xff0c;威胁是指可能影响其平稳运行的恶意元素。因此&#xff0c;对于任何希望搁置任何财政损失或生产力下降机会的组织来说&#xff0c;威胁检测都是必要的。为了先发制人地阻止来自各种来源的任何此类攻击&#xff0c;需要有效的威胁检测情报。 威胁检测可以是…

mmap函数

参考 https://blog.csdn.net/bhniunan/article/details/104105153void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);参数 addr&#xff1a;出参&#xff0c; 指定映射的起始地址&#xff0c;通常设为NULL&#xff0c;由内核来分配 len&#x…

网络编程3——TCP Socket实现的客户端服务器通信完整代码(详细注释帮你快速理解)

文章目录 前言一、理论准备Socket套接字是什么TCP协议的特点 二、TCP 流套接字提供的APIServerSocket APISocket API 三、代码实现请求响应式 客户端服务器服务器客户端疑惑解答为什么服务器进程需要手动指定端口号而客户端进程不需要为什么客户端中的服务器IP与端口号是"…

Mysql架构篇--Mysql 主从同步方案

文章目录 前言一、传统的主从复制&#xff1a;1 原理&#xff1a;2 缺点&#xff1a; 二、半同步复制&#xff08;Semi-Synchronous Replication&#xff09;&#xff1a;三、组复制&#xff1a;1 原理&#xff1a;2 实现&#xff1a;2.1 myql 实例安装&#xff1a;2.1 myql 实…

量子近似优化算法(QAOA)入门(1):从量子绝热算法(QAA)角度的直观理解

文章目录 前言&#xff1a;量子计算的本质是测量一、基于量子逻辑电路的常用算法1.NISQ&#xff1a;Noisy Intermediate-Scale Quantum&#xff08;含噪声中等规模量子&#xff09; 二、量子绝热算法&#xff08;QAA&#xff1a;Quantum Adiabatic Algorithm&#xff09;1.QAA的…

【KingFusion】用KingFusion3.6创建一个客户端工程的步骤

哈喽&#xff0c;大家好&#xff0c;我是雷工&#xff01; 今天学习用KingFusion3.6创建一个客户端工程&#xff0c;以下记录创建过程。 客户端组件作为KingFusion3.6的数据展示功能模块&#xff0c;其主要功能是通过组态组态式配置以及丰富的图表元素、动画连接等多样的展示形…

ROS:TF坐标变换

目录 一、TF坐标变换背景二、概念三、静态坐标变换3.1概念3.2实际用例3.2.1分析3.2.2流程3.2.3C实现 一、TF坐标变换背景 机器人系统上&#xff0c;有多个传感器&#xff0c;如激光雷达、摄像头等&#xff0c;有的传感器是可以感知机器人周边的物体方位(或者称之为:坐标&#…

《LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS》论文笔记

引言 全量参数微调在LLM背景下由“不方便”演变为“不可行|高昂成本”&#xff0c;基于“收敛的模型参数可以压缩到低维空间”的假设&#xff1a; the learned over-parametrized models in fact reside on a low intrinsic dimension. 作者提出LORA&#xff08;Low Rank Adap…