Spring高手之路——深入理解注解驱动配置与XML配置的融合与区别

news2024/11/29 2:44:51

文章目录

  • 1. 配置类的编写与Bean的注册
  • 2. 注解驱动IOC的依赖注入与XML依赖注入对比
  • 3. 组件注册
  • 4. 组件扫描
    • 4.1 使用@ComponentScan的组件扫描
    • 4.2 xml中启用component-scan组件扫描
    • 4.3 不使用@ComponentScan的组件扫描
  • 5. 组件注册的其他注解
  • 6. 将注解驱动的配置与XML驱动的配置结合使用
  • 7. 思考总结
    • 7.1 为什么我们需要注册组件,这与Bean注册有什么区别?
    • 7.2 什么是组件扫描,为什么我们需要它,它是如何工作的?

1. 配置类的编写与Bean的注册

  XML配置中,我们通常采用ClassPathXmlApplicationContext,它能够加载类路径下的XML配置文件来初始化Spring应用上下文。然而,在注解驱动的配置中,我们则使用以Annotation开头和ApplicationContext结尾的类,如AnnotationConfigApplicationContext

  对比于 XML 文件作为驱动,注解驱动需要的是配置类。一个配置类就可以类似的理解为一个 XML 。配置类没有特殊的限制,只需要在类上标注一个 @Configuration 注解即可。

我们创建一个 Book 类:

public class Book {
    private String title;

    private String author;


    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

xml 中声明 Bean 是通过 <bean> 标签

<bean id="book" class="com.example.Book">
    <property name="title" value="Java Programming"/>
    <property name="author" value="Unknown"/>
</bean>

那么在配置类中替换掉 <bean> 标签,使用 @Bean 注解

我们创建一个配置类来注册这个 Book bean

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

@Configuration
public class LibraryConfiguration {
    @Bean
    public Book book() {
        Book book = new Book();
        book.setTitle("Java Programming");
        book.setAuthor("Unknown");
        return book;
    }
}

  在这个配置中,我们使用了 @Configuration 注解来表示这是一个配置类,类似于一个 XML 文件。我们在 book() 方法上使用了 @Bean 注解,这意味着这个方法将返回一个由 Spring 容器管理的对象。这个对象的类型就是 Bookbean 的名称id就是方法的名称,也就是 “book”。

  类似于 XML 配置的 <bean> 标签,@Bean 注解负责注册一个 bean。你可以把 @Bean 注解看作是 <bean> 标签的替代品。

  如果你想要更改这个 bean 的名称,你可以在 @Bean 注解中使用 name 属性:

   @Bean(name="mybook")
    public Book book() {
        Book book = new Book();
        book.setTitle("Java Programming");
        book.setAuthor("Unknown");
        return book;
    }

  这样,这个 Book bean 的名称就变成了 “mybook”。

启动并初始化注解驱动的IOC容器

@SpringBootApplication
public class DemoApplication {

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

        // 从容器中获取 Book bean
        LibraryConfiguration libraryConfiguration = context.getBean(LibraryConfiguration.class);
        System.out.println(libraryConfiguration.book().getTitle());
        System.out.println(libraryConfiguration.book().getAuthor());
    }
}

打印结果:

IOC

Java ProgrammingUnknown被打印,执行成功。

注意:@SpringBootApplication是一个复合注解,它等效于同时使用了@Configuration@EnableAutoConfiguration@ComponentScan。这三个注解的作用是:

  • @Configuration:指明该类是一个配置类,它可能会有零个或多个@Bean注解,方法产生的实例由Spring容器管理。

  • @EnableAutoConfiguration:告诉Spring Boot根据添加的jar依赖自动配置你的Spring应用。

  • @ComponentScanSpring Boot会自动扫描该类所在的包以及子包,查找所有的Spring组件,包括@Configuration类。

  在非Spring Boot的传统Spring应用中,我们通常使用AnnotationConfigApplicationContext或者ClassPathXmlApplicationContext等来手动创建和初始化SpringIOC容器。

  "非Spring Boot的传统Spring应用"是指在Spring Boot项目出现之前的Spring项目,这些项目通常需要手动配置很多东西,例如数据库连接、事务管理、MVC控制器等。这种类型的Spring应用通常需要开发者对Spring框架有深入的了解,才能做出正确的配置。

  Spring BootSpring项目的一个子项目,它旨在简化Spring应用的创建和配置过程。Spring Boot提供了一系列的"起步依赖",使得开发者只需要添加少量的依赖就可以快速开始项目的开发。此外,Spring Boot还提供了自动配置的特性,这使得开发者无需手动配置数据库连接、事务管理、MVC控制器等,Spring Boot会根据项目的依赖自动进行配置。

  因此,"非Spring Boot的传统Spring应用"通常需要手动创建和初始化SpringIOC容器,比如使用AnnotationConfigApplicationContextClassPathXmlApplicationContext等。在Spring Boot应用中,这个过程被自动化了,开发者只需要在main方法中调用SpringApplication.run方法,Spring Boot就会自动创建和初始化SpringIOC容器。SpringApplication.run(Application.class, args);语句就是启动Spring Boot应用的关键。它会启动一个应用上下文,这个上下文会加载所有的Spring组件,并且也会启动SpringIOC容器。在这个过程中,所有通过@Bean注解定义的bean都会被创建,并注册到IOC容器中。


2. 注解驱动IOC的依赖注入与XML依赖注入对比

我们就以上面的例子来说,假设配置类注册了两个bean,并设置相关的属性:

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

@Configuration
public class LibraryConfiguration {
    @Bean
    public Book book() {
        Book book = new Book();
        book.setTitle("Java Programming");
        book.setAuthor("Unknown");
        return book;
    }

    @Bean
    public Library library() {
        Library library = new Library();
        library.setBook(book());
        return library;
    }
}

  这里的方法有@Bean注解,这个注解告诉Spring,这个方法返回的对象需要被注册到SpringIOC容器中。

对应的XML配置如下:

<bean id="book" class="com.example.Book">
    <property name="title" value="Java Programming"/>
    <property name="author" value="Unknown"/>
</bean>

<bean id="library" class="com.example.Library">
    <property name="book" ref="book"/>
</bean>

  在这个XML配置中,我们定义了两个<bean>元素,分别用来创建Book对象和Library对象。在创建Book对象时,我们使用了<property>元素来设置titleauthor属性。在创建Library对象时,我们也使用了<property>元素,但是这次我们使用了ref属性来引用已经创建的Book对象,这就相当于将Book对象注入到Library对象中。


3. 组件注册

这里LibraryConfiguration 标注 @Configuration 注解,即代表该类会被注册到 IOC 容器中作为一个 Bean

@Configuration
public class LibraryConfiguration {
}

相当于 xml 中的:

<bean id="library" class="com.example.demo.configuration.LibraryConfiguration">

如果想指定 Bean 的名称,可以直接在 @Configuration 中声明 value 属性即可

@Configuration("libConfig")
public class LibraryConfiguration {
}

如果不指定 Bean 的名称,它的默认规则是 “类名的首字母小写”(例如LibraryConfiguration默认名称是 libraryConfiguration )


4. 组件扫描

如果只是@Component声明了组件,在写配置类时只写 @Configuration 注解,那么IOC容器是找不到这些组件的。

4.1 使用@ComponentScan的组件扫描

我们需要运行的代码如下:

@Component
public class Book {
    
    private String title = "Java Programming";
    private String author = "Unknown";

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}
@Component
public class Library {
    private Book book;

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }
}

如果不写@ComponentScan,而且@Component注解标识的类不在当前包或者子包,那么就会报错。

IOC

  难道@Component注解标识的类在当前包或者当前包的子包就可以不写@ComponentScan了吗?

  是的!前面说了,@SpringBootApplication 包含了 @ComponentScan,其实已经帮我们写了!只有组件和主程序不在一个共同的根包下,才需要显式地使用 @ComponentScan 注解。由于 Spring Boot 的设计原则是“约定优于配置”,所以推荐将主应用类放在根包下。

  在应用中,我们的组件(带有 @Component@Service@Repository@Controller 等注解的类)和主配置类位于不同的包中,并且主配置类或者启动类没有使用 @ComponentScan 指定扫描这些包,那么在运行时就会报错,因为Spring找不到这些组件。

主程序:

@ComponentScan(basePackages = "com.example")
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Library library = context.getBean(Library.class);
        System.out.println(library.getBook().getTitle());
        System.out.println(library.getBook().getAuthor());
    }

}
IOC

  @ComponentScan 不一定非要写在主程序(通常是指 Spring Boot 的启动类)上,它可以写在任何配置类(标记有 @Configuration 注解的类)上。@ComponentScan 注解会告诉 Spring 从哪些包开始进行组件扫描。

  为了简化配置,我们通常会将 @ComponentScan 放在主程序上,因为主程序一般会位于根包下,这样可以扫描到所有的子包。

4.2 xml中启用component-scan组件扫描

对应于 @ComponentScanXML 配置是 <context:component-scan> 标签

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.example" />

</beans>

  在这段 XML 配置中,<context:component-scan> 标签指定了 Spring 需要扫描 com.example 包及其子包下的所有类,这与 @ComponentScan 注解的功能是一样的。

  注意:在使用 <context:component-scan> 标签时,需要在 XML 配置文件的顶部包含 context 命名空间和相应的 schema 位置(xsi:schemaLocation)。

4.3 不使用@ComponentScan的组件扫描

如果我们不写刚刚提到的LibraryConfiguration配置类,那么这里可以把主程序改为如下:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext("com.example");
        Library library = context.getBean(Library.class);
        System.out.println(library.getBook().getTitle());
        System.out.println(library.getBook().getAuthor());
    }
}

  AnnotationConfigApplicationContext 的构造方法中有一个是填写basePackages路径的,可以接受一个或多个包的名字作为参数,然后扫描这些包及其子包。

IOC

运行结果如下:

IOC

  在这个例子中,Spring 将会扫描 com.example 包及其所有子包,查找并注册所有的 Bean

  我们也可以手动创建一个配置类来注册bean,那么想要运行得到一样的效果,需要改动的代码如下:

@Configuration
public class LibraryConfiguration {
    @Bean
    public Book book() {
        Book book = new Book();
        book.setTitle("Java Programming");
        book.setAuthor("Unknown");
        return book;
    }

    @Bean
    public Library library() {
        Library library = new Library();
        library.setBook(book());
        return library;
    }
}

主程序:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(LibraryConfiguration.class);
        Library library = context.getBean(Library.class);
        System.out.println(library.getBook().getTitle());
        System.out.println(library.getBook().getAuthor());
    }
}

运行结果如下:

IOC

  我们创建了一个配置类LibraryConfiguration,用于定义BookLibrary这两个bean。然后我们使用了AnnotationConfigApplicationContext来创建SpringIOC容器,并加载这个配置类。因为我们没有使用@ComponentScan注解,所以Spring不会自动扫描和注册bean,我们需要手动创建配置类来注册bean

为什么要有配置类出现?直接用@ComponentScan注解不就能解决了吗?

  我们在使用一些第三方库时,需要对这些库进行一些特定的配置。这些配置信息,我们可能无法直接通过注解或者XML来完成,或者通过这些方式完成起来非常麻烦。而配置类可以很好地解决这个问题。通过配置类,我们可以在Java代码中完成任何复杂的配置逻辑。

  假设你正在使用 MyBatis,在这种情况下可能需要配置一个SqlSessionFactory,在大多数情况下,我们无法(也不应该)直接修改第三方库的代码,所以无法直接在SqlSessionFactory类或其他类上添加@Configuration@Component等注解。为了能够在Spring中使用和配置这些第三方库,我们需要创建自己的配置类,并在其中定义@Bean方法来初始化和配置这些类的实例。这样就可以灵活地控制这些类的实例化过程,并且可以利用Spring的依赖注入功能。

下面是一个使用@Configuration@Bean来配置MyBatis的例子:

@Configuration
@MapperScan("com.example.demp.mapper")
public class MyBatisConfig {

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath*:com/example/demo/mapper/*Mapper.xml")
        );
        return factoryBean.getObject();
    }
}

  sqlSessionFactory方法创建一个SqlSessionFactoryBean对象,并使用DataSourceSpring Boot默认为你配置的一个Bean)进行初始化。然后,它指定MyBatis mapper XML文件的位置,最后返回SqlSessionFactory对象。

  通过这种方式,你可以灵活地配置MyBatis,并将其整合到Spring应用中。这是一种比使用XML配置文件或仅仅依赖于自动配置更为灵活和强大的方式。


5. 组件注册的其他注解

  @Controller, @Service, @Repository@Component 一样的效果,它们都会被 Spring IoC 容器识别,并将类实例化为 Bean。让我们来看这些注解:

  • @Controller:这个注解通常标注在表示表现层(比如 Web 层)的类上,如Spring MVC 中的控制器。它们处理用户的 HTTP 请求并返回响应。虽然 @Controller@Component 在功能上是类似的,但 @Controller 注解的使用表示了一种语义化的分层结构,使得控制层代码更加清晰。
IOC
  • @Service:这个注解通常用于标注业务层的类,这些类负责处理业务逻辑。使用 @Service 注解表明该类是业务处理的核心类,使得代码更具有语义化。
IOC
  • @Repository:这个注解用于标记数据访问层,也就是数据访问对象或DAO层的组件。在数据库操作的实现类上使用 @Repository 注解,这样Spring将自动处理与数据库相关的异常并将它们转化为SpringDataAccessExceptions
IOC

  在实际开发中,几乎很少看到@Repository,而是利用 MyBatis@Mapper@MapperScan 实现数据访问,通常做法是,@MapperScan 注解用于扫描特定包及其子包下的接口,这些接口被称为 Mapper 接口。Mapper 接口方法定义了 SQL 查询语句的签名,而具体的 SQL 查询语句则通常在与接口同名的 XML 文件中定义。

  @MapperScan("com.example.**.mapper") 会扫描 com.example 包及其所有子包下的名为 mapper 的包,以及 mapper 包的子包。 ** 是一个通配符,代表任意深度的子包。

举个例子,以下是一个 Mapper 接口的定义:

package com.example.demo.mapper;

public interface UserMapper {
    User selectUserById(int id);
}

对应的 XML 文件(通常位于 resources 目录下,并且与接口在相同的包路径中)

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="selectUserById" resultType="com.example.demo.entity.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
</mapper>

  注意:在 XML 文件中的 namespace 属性值必须与 Mapper 接口的全限定类名相同,<select> 标签的 id 属性值必须与接口方法名相同。

然后,在 Spring Boot 的主类上,我们使用 @MapperScan 注解指定要扫描的包:

@SpringBootApplication
@MapperScan("com.example.**.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

  这样,MyBatis 就会自动为 UserMapper 接口创建一个实现类(实际上是一个代理对象),并将其注册到 Spring IOC 容器中,你就可以在你的服务类中直接注入 UserMapper 并使用它。

可能有小伙伴注意到了,这几个注解中都有这么一段代码

    @AliasFor(
        annotation = Component.class
    )
    String value() default "";

  @AliasForSpring 框架的注解,它允许你在一个注解属性上声明别名。在 Spring 的许多核心注解中,@AliasFor 用于声明一个或多个别名属性。

  举个例子,在 @Controller, @Service, @Repository注解中,value() 方法上的 @AliasFor 声明了一个别名属性,它的目标注解是 @Component,具体的别名属性是 value。也就是说,当我们在 @Controller, @Service, @Repository 注解上使用 value() 方法设置值时,实际上也就相当于在 @Component 注解上设置了 name 属性的值。同时,这也表明了 @Controller, @Service, @Repository注解本身就是一个特殊的 @Component


6. 将注解驱动的配置与XML驱动的配置结合使用

  有没有这么一种可能,一个旧的Spring项目,里面有很多旧的XML配置,现在你接手了,想要全部用注解驱动,不想再写XML配置了,那应该怎么兼容呢?

假设我们有一个旧的Spring XML配置文件 old-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="oldBean" class="com.example.OldBean" />

</beans>

这个文件定义了一个名为 “oldBean” 的bean

然后,我们编写一个新的注解驱动的配置类:

package com.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ImportResource("classpath:old-config.xml")
public class NewConfig {

    @Bean
    public NewBean newBean() {
        return new NewBean();
    }
}

  在这个新的配置类中,我们使用 @ImportResource 注解来引入旧的XML配置文件,并定义了一个新的beannewBean”。@ImportResource("classpath:old-config.xml")告诉Spring在初始化AppConfig配置类时,去类路径下寻找old-config.xml文件,并加载其中的配置。

  当我们启动应用程序时,Spring会创建一个 ApplicationContext,这个 ApplicationContext 会包含 old-config.xml 文件中定义的所有beans(例如 “oldBean”),以及 NewConfig 类中定义的所有beans(例如 “newBean”)。

package com.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(NewConfig.class);
        
        OldBean oldBean = context.getBean("oldBean", OldBean.class);
        NewBean newBean = context.getBean("newBean", NewBean.class);
        
        System.out.println(oldBean);
        System.out.println(newBean);
    }
}

  在以上的main方法中,我们通过使用AnnotationConfigApplicationContext并传入NewConfig.class作为参数,初始化了一个Spring上下文。在这个上下文中,既包含了从old-config.xml导入的bean,也包含了在NewConfig配置类中使用@Bean注解定义的bean

  所以,通过使用 @ImportResource,可以在新的注解配置中引入旧的XML配置,这样就可以在不打断旧的XML配置的基础上逐步迁移至新的注解配置。

上面我们说到类路径,什么是类路径?

  resources目录就是类路径(classpath)的一部分。所以当我们说"类路径下"的时候,实际上也包含了"resources"目录。JVM在运行时,会把"src/main/resources"目录下的所有文件和文件夹都添加到类路径中。

  例如有一个XML文件位于"src/main/resources/config/some-context.xml",那么可以用以下方式来引用它:

@Configuration
@ImportResource("classpath:config/some-context.xml")
public class AppConfig {
    //...
}

这里可以描述为在类路径下的’config’目录中查找’some-context.xml’文件。

为什么说JVM在运行时,会把"src/main/resources"目录下的所有文件和文件夹都添加到类路径中?

  当你编译并运行一个Java项目时,JVM需要知道去哪里查找.class文件以及其他资源文件。这个查找的位置就是所谓的类路径(Classpath)。类路径可以包含文件系统上的目录,也可以包含jar文件。简单的说,类路径就是JVM查找类和资源的地方。

  在一个标准的Maven项目结构中,Java源代码通常在src/main/java目录下,而像是配置文件、图片、静态网页等资源文件则放在src/main/resources目录下。

  当你构建项目时,Maven(或者其他的构建工具,如Gradle)会把src/main/java目录下的.java文件编译成.class文件,并把它们和src/main/resources目录下的资源文件一起复制到项目的输出目录(通常是target/classes目录)。

IOC IOC

  然后当你运行程序时,JVM会把target/classes目录(即编译后的src/main/javasrc/main/resources)添加到类路径中,这样JVM就可以找到程序运行所需的类和资源了。

  如果有一个名为application.properties的文件在src/main/resources目录下,就可以使用类路径来访问它,就像这样:classpath:application.properties。在这里classpath:前缀告诉JVM这个路径是相对于类路径的,所以它会在类路径中查找application.properties文件。因为src/main/resources在运行时被添加到了类路径,所以JVM能找到这个文件。


7. 思考总结

7.1 为什么我们需要注册组件,这与Bean注册有什么区别?

  在Spring框架中,Bean对象是由Spring IoC容器创建和管理的。通常Bean对象是应用程序中的业务逻辑组件,如数据访问对象(DAO)或其他服务类。

  组件注册,或者说在Spring中通过@Component或者其派生注解(@Service, @Controller, @Repository等)标记的类,是告诉Spring框架这个类是一个组件,Spring需要创建它的实例并管理它的生命周期。这样当使用到这个类的时候,Spring就可以自动地创建这个类的实例并注入到需要的地方。

  Bean注册和组件注册其实是非常类似的,都是为了让Spring知道它需要管理哪些类的实例。区别在于Bean注册通常发生在配置类中,使用@Bean注解来明确地定义每一个Bean,而组件注册则是通过在类上使用@Component或者其派生注解来告诉Spring,这个类是一个组件,Spring应该自动地为其创建实例。

7.2 什么是组件扫描,为什么我们需要它,它是如何工作的?

  组件扫描是Spring的一种机制,用于自动发现应用程序中的Spring组件,并自动地为这些组件创建Bean定义,然后将它们注册到Spring的应用上下文中,我们可以通过使用@ComponentScan注解来启动组件扫描。

  我们需要组件扫描是因为它可以大大简化配置过程,我们不再需要为应用程序中的每个类都显式地创建Bean。而是通过简单地在类上添加@Component或者其派生注解,并启动组件扫描,就可以让Spring自动地为我们的类创建Bean并管理它们。

  组件扫描的工作过程如下:使用@ComponentScan注解并指定一个或多个包路径时,Spring会扫描这些包路径及其子包中的所有类。对于标记了@Component或者其派生注解的类,Spring会在应用上下文启动时为它们创建Bean,并将这些Bean定义注册到Spring的应用上下文中。当需要使用这些类的实例时,Spring就可以自动注入这些实例。



欢迎一键三连~

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

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

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

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

相关文章

Windows下搭建paddlenlp 语义检索系统

windos下搭建paddlenlp 语义检索系统 之前搭建paddleocr的时候&#xff0c;创建了paddle的虚拟环境&#xff0c;顺便也装了paddlenlp的库&#xff0c;就想着直接用这个&#xff0c;然后语义检索模型本身没有问题了&#xff0c;可以正常推理了。但在搭建pipline的时候出现问题&…

工程测量--学习笔记

1、测量学的概念 测量学是研究地球的形状、大小以及地表&#xff08;包括地面上各种物体&#xff09;的几何形状及其空间位置的科学。 2、工程测量的概念 工程测量是运用测量学的基本原理和方法为各类工程服务。 3、测量工作分类 测量工作包括测定和测设两部分。 测定是指使用…

算法|2.异或运算

算法|2.异或运算 1.不用额外变量交换两个数的值 题意&#xff1a;不用额外变量交换&#xff08;数组中&#xff09;两个数的值 解题思路&#xff1a; 使用异或运算的性质 代码及运行结果&#xff1a; 2.找到唯一出现奇数次的数字 题意&#xff1a;一个数组中有一种数出现了…

这才是网络安全最系统的学习路线(建议收藏)

01 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

一些小的问题

是否是质数&#xff1f; #include <stdio.h> #include <stdbool.h>bool is_prime(int num);int main() {int num;printf("请输入一个整数&#xff1a;");scanf("%d", &num);if (is_prime(num)) {printf("%d是质数。\n", num);} …

【萌新指南】如何获得铁粉?快收下我为你精心定制的涨粉秘籍吧

文章目录 前言"铁粉"介绍"铁粉"规则"铁粉"获取高质量博客坚持写博客参与活动 尾声 前言 目前博主的"铁粉"数量 "铁粉"介绍 "铁粉"是为了帮助博主解决上面提到的问题和困惑&#xff0c; CSDN 设计的一个功能&…

STM8、STM8S003F3P6 通过ZM470SX-MP模组实现lora通信

背景 现在物联网就是很火&#xff0c;lora是避免不开的&#xff0c;也有个项目采用STM8S003F3P6 使用周立功的lora模组ZM470SX-MP实现lora通信。 原理图 废话少说&#xff0c;上原理图 这个原理图我找了很久都没有找到&#xff0c;指示找到了管脚图&#xff0c;这个原理图非…

Linux——线程的同步与互斥

目录 模拟抢火车票的过程 代码示例 thread.cc Thread.hpp 运行结果 分析原因 tickets减到-2的本质 解决抢票出错的方案 临界资源的概念 原子性的概念 加锁 定义 初始化 销毁 代码形式如下 代码示例1&#xff1a; 代码示例2&#xff1a; 总结 如何看待锁 申…

2.自然语言处理NLP:词映射为向量——词嵌入(word embedding)

1. 什么是词嵌入&#xff08;word2vec&#xff09; &#xff1a; 把词映射为向量&#xff08;实数域&#xff09;的技术 2. 为什么不采用one-hot向量&#xff1a; one-hot词向量无法准确表达不同词之间的相似度&#xff0c;eg&#xff1a;余弦相似度&#xff0c;表示夹角之间的…

创新案例|Amazon如何打造增长飞轮保持每年20%以上的营收增速

作为世界五百强中的头部企业&#xff0c;亚马逊的价值定位经历了三次转变&#xff0c;从成为“地球上最大的书店”&#xff0c;到成为最大的综合网络零售商&#xff0c;再到成为“最以客户为中心的企业”&#xff0c;亚马逊最终以“客户中心”破除了对企业价值定位的束缚&#…

DNS风险分析及安全防护研究(三):DNS缓存投毒及防御策略

在前面章节中&#xff0c;我们简单介绍了DNS系统在协议、软件以及结构中脆弱性&#xff0c;并对DNSSEC协议、去中心化结构等安全增强进行了讨论&#xff0c;接下来针对DNS安全所面临的外部攻击威胁和相应的防御策略做下讨论。 1.DNS缓存投毒攻击 在目前各种DNS攻击手段中&…

安科瑞浅谈集成式电力电容器无功补偿装置的技术特点

安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘要&#xff1a;阐述了集成式电力电容器无功补偿装置的组成与应用状况&#xff0e;在与常规电力电容器对比的基础上&#xff0c;分析了集成式电力电容器无功补偿装置的技术特点。通过对集成式无功补偿装置原理结构的…

Linux文件系统、磁盘I/O是怎么工作的?

同CPU、内存一样&#xff0c;文件系统和磁盘I/O&#xff0c;也是Linux操作系统最核心的功能。磁盘为系统提供了最基本的持久化存储。文件系统则在磁盘基础上&#xff0c;提供了一个用来管理文件的树状结构。 目录&#xff1a; 一. 文件系统 1. 索引节点和目录项 2. 虚拟文件系…

提升国际品牌影响力:小企业海外网红营销实战指南

在当今数字化时代&#xff0c;小企业们越来越意识到海外市场的巨大潜力。与此同时&#xff0c;海外网红的崛起也为小企业提供了一个独特的机会&#xff0c;通过与他们合作&#xff0c;迅速拓展国际市场并吸引更多目标受众的关注。然而&#xff0c;对于许多小企业来说&#xff0…

超全性能测试-全链路压测总结,完整一套从环境到脚本详细...

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

类和对象 --- 封装+对象特性

&#x1f442; 快乐E调 - 林澜叶 - 单曲 - 网易云音乐 &#x1f442; Plain Jane (Freestyle) - Ombre2Choc Nation - 单曲 - 网易云音乐 1.5倍速&#xff0c;跟着敲&#xff0c;初识C 目录 &#x1f3c6;封装 &#x1f333;属性和行为作为整体 &#x1f333;案例 -- 设置…

js数组去重与循环对象

目录 一、数组对象去重 1.1、需要获取重复数据 1.2、直接过滤filterfindIndex 二、循环对象 三、多层数组对象过滤 一、数组对象去重 1.1、需要获取重复数据 let persons [{"name": "yzq","age": 20,"gender": true,"hei…

k8s配置资源管理|secret|configmap

k8s配置资源管理|secret|configmap 一 配置资源管理1 创建 Secret2 使用方式3 将 Secret 导出到环境变量中 二 ConfigMap1 Pod 中使用 ConfigMap2 Pod的创建3 用 ConfigMap 设置命令行参数4 通过数据卷插件使用ConfigMap 一 配置资源管理 //Secret Secret 是用来保存密码、tok…

2023年6月合肥/厦门/长春/深圳DAMA-CDGP数据治理专家认证报名

目前6月18日CDGA&CDGP考试目前开放的城市有&#xff1a;北京、上海、广州(满)、深圳、长沙、呼和浩特、杭州&#xff08;满&#xff09;、南京、济南&#xff08;满&#xff09;、成都、西安、武汉&#xff08;满&#xff09;、天津。 新增了武汉、天津这2个城市。另外合肥…

【Netty】Reactor 模型(十)

文章目录 前言一、传统服务的设计模型二、NIO 分发模型三、Reactor 模型3.1、Reactor 处理请求的流程3.2、Reactor 三种角色 四、单Reactor 单线程模型4.1、消息处理流程4.2、缺点 五、单Reactor 多线程模型5.1、消息处理流程5.2、缺点 六、主从Reactor 多线程模型6.1、Reactor…