五、Spring IoCDI ★ ✔

news2024/12/26 11:52:57

5. Spring IoC&DI

  • 1. IoC & DI ⼊⻔
    • 1.1 Spring 是什么?★ (Spring 是包含了众多⼯具⽅法的 IoC 容器)
      • 1.1.1 什么是容器?
      • 1.1.2 什么是 IoC?★ (IoC: Inversion of Control (控制反转))
        • 总结:把传统模式 被依赖对象创建依赖对象 改成 交给容器创建。用的时候注入即可。
    • 1.2 IoC 介绍
      • 需求: 造⼀辆⻋
      • 1.2.1 传统程序开发 ★
        • car-framework-bottom-tire
      • 1.2.2 问题分析
      • 1.2.3 解决⽅案
      • 1.2.4 IoC程序开发 ★
      • 1.2.5 IoC 优势
        • Tire -> Bottom -> Framework -> Car
          • 第⼀,资源集中管理,实现资源的可配置和易管理。
          • 第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。
    • 1.3 DI 介绍
  • 2. IoC & DI 使⽤
        • 以下是一个基于Spring Boot的IoC和DI的实战代码案例:
        • ⽬标: 把BookDao, BookService 交给Spring管理, 完成Controller层, Service层, Dao层的解耦
  • 3. IoC 详解
    • 3.1 Bean的存储
      • 3.1.1 @Controller(控制器存储)
        • 如何观察这个对象已经存在Spring容器当中了呢?
          • 接下来我们学习如何从Spring容器中获取对象 ★
            • ApplicationContext.getBean(手动获取bean对象)
            • XML的方式注入的获取 ClassPathXmlApplicationContext
          • 获取bean对象的其他⽅式(beanFactory)
        • ApplicationContext VS BeanFactory(常⻅⾯试题) ★
      • 3.1.2 @Service(服务存储)
      • 3.1.3 @Repository(仓库存储)
      • 3.1.4 @Component(组件存储)
      • 3.1.5 @Configuration(配置存储)
    • 3.2 为什么要这么多类注解?
    • 3.3 ⽅法注解 @Bean
      • 3.3.1 ⽅法注解要配合类注解使⽤
      • 3.3.2 定义多个对象
      • 3.3.3 重命名 Bean
    • 3.4 扫描路径
        • @ComponentScan({"com.example.demo"})
  • 4. DI 详解
    • 4.1 属性注⼊
    • 4.2 构造⽅法注⼊
    • 4.3 Setter 注⼊
    • 4.4 三种注⼊优缺点分析
    • 4.5 @Autowired存在问题
      • 当同⼀类型存在多个bean时, 使⽤@Autowired会存在问题
        • 使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现.
        • 使⽤@Qualifier注解:指定当前要注⼊的bean对象。 在@Qualifier的value属性中,指定注⼊的bean的名称。
        • 使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。
        • @Autowird 与 @Resource的区别
  • 5. 总结
    • Spring, Spring Boot 和Spring MVC的关系以及区别

本节⽬标

  1. 了解Spring,Spring MVC, Spring Boot 之间的联系及区别
  2. 掌握IoC&DI的概念以及写法

1. IoC & DI ⼊⻔

在前⾯的章节中, 我们学习了Spring Boot和Spring MVC的开发, 可以完成⼀些基本功能的开发了, 但是什么是Spring呢? Spring, Spring Boot 和SpringMVC⼜有什么关系呢? 咱们还是带着问题去学习.

我们先看什么是Spring

1.1 Spring 是什么?★ (Spring 是包含了众多⼯具⽅法的 IoC 容器)

通过前⾯的学习, 我们知道了Spring是⼀个开源框架, 他让我们的开发更加简单. 他⽀持⼴泛的应⽤场景, 有着活跃⽽庞⼤的社区, 这也是Spring能够⻓久不衰的原因.但是这个概念相对来说, 还是⽐较抽象.
我们⽤⼀句更具体的话来概括Spring, 那就是: Spring 是包含了众多⼯具⽅法的 IoC 容器
那问题来了,什么是容器?什么是 IoC 容器?接下来我们⼀起来看

1.1.1 什么是容器?

容器是⽤来容纳某种物品的(基本)装置。⸺来⾃:百度百科
⽣活中的⽔杯, 垃圾桶, 冰箱等等这些都是容器.
我们想想,之前课程我们接触的容器有哪些?

  • List/Map -> 数据存储容器
  • Tomcat -> Web 容器

1.1.2 什么是 IoC?★ (IoC: Inversion of Control (控制反转))

IoC 是Spring的核⼼思想, 也是常⻅的⾯试题, 那什么是IoC呢?
其实IoC我们在前⾯已经使⽤了, 我们在前⾯讲到, 在类上⾯添加 @RestController 和 @Controller 注解, 就是把这个对象交给Spring管理, Spring 框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想

IoC: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器.
什么是控制反转呢? 也就是控制权反转. 什么的控制权发⽣了反转? 获得依赖对象的过程被反转了也就是说, 当需要某个对象时, 传统开发模式中需要⾃⼰通过 new 创建对象, 现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊ (Dependency Injection,DI)就可以了.
这个容器称为:IoC容器. Spring是⼀个IoC容器, 所以有时Spring 也称为Spring 容器.

总结:把传统模式 被依赖对象创建依赖对象 改成 交给容器创建。用的时候注入即可。

1.2 IoC 介绍

接下来我们通过案例来了解⼀下什么是IoC

需求: 造⼀辆⻋

1.2.1 传统程序开发 ★

我们的实现思路是这样的:
先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦

car-framework-bottom-tire

在这里插入图片描述

最终程序的实现代码如下

public class NewCarExample {
	public static void main(String[] args) {
		ar ar = ew ar );
		car.run();
	}
	
	/**
	* 汽⻋对象
	*/
	static class Car {
		private Framework framework;
		public Car() {
			framework = new Framework();
			System.out.println("Car init....");
		}
		public void run(){
			System.out.println("Car run...");
		}
	}

	/**
	* ⻋⾝类
	*/
	static class Framework {
		private Bottom bottom;
		public Framework() {
			bottom = new Bottom();
			System.out.println("Framework init...");
		}
	}
	/**
	* 底盘类
	*/
	static class Bottom {
		private Tire tire;
		public Bottom() {
			this.tire = new Tire();
			System.out.println("Bottom init...");
		}
	}
	/**
	* 轮胎类
	*/
	static class Tire {
		// 尺⼨
		private int size;
		public Tire(){
			this.size = 17;
			System.out.println("轮胎尺⼨:" + size);
		}
	}
}

1.2.2 问题分析

这样的设计看起来没问题,但是可维护性却很低.
接下来需求有了变更: 随着对的⻋的需求量越来越⼤, 个性化需求也会越来越多,我们需要加⼯多种尺⼨的轮胎.
那这个时候就要对上⾯的程序进⾏修改了,修改后的代码如下所⽰:
在这里插入图片描述
修改之后, 其他调⽤程序也会报错, 我们需要继续修改
在这里插入图片描述
在这里插入图片描述
从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要修改.
程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)

1.2.3 解决⽅案

在上⾯的程序中, 我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改. 同样因为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改

我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋

这就类似我们打造⼀辆完整的汽⻋, 如果所有的配件都是⾃⼰造,那么当客⼾需求发⽣改变的时候,⽐如轮胎的尺⼨不再是原来的尺⼨了,那我们要⾃⼰动⼿来改了,但如果我们是把轮胎外包出去,那么即使是轮胎的尺⼨发⽣变变了,我们只需要向代理⼯⼚下订单就⾏了,我们⾃⾝是不需要出⼒的.

在这里插入图片描述
如何来实现呢:
我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,⾃⼰也要跟着修改.
此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式),因为我们不需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修改任何代码,这样就完成了程序的解耦.

1.2.4 IoC程序开发 ★

基于以上思路,我们把调⽤汽⻋的程序⽰例改造⼀下,把创建⼦类的⽅式,改为注⼊传递的⽅式.
具体实现代码如下:

public class Main {
    public static void main(String[] args) {
        Tire tire = new Tire(19,"red");
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.run();
    }
}
public class Bottom {
    private Tire tire;

    public Bottom(Tire tire) {
        this.tire = tire;
        System.out.println("bottom init...");
    }

}
public class Car {
    private Framework framework;

    public Car(Framework framework) {
        this.framework = framework;
        System.out.println("car init...");
    }

    public void run() {
        System.out.println("car run...");
    }
}
public class Framework {
    private Bottom bottom;

    public Framework(Bottom bottom) {
        this.bottom = bottom;
        System.out.println("framework init...");
    }
}
public class Tire {
    private int size;
    private String color;

    public Tire(int size,String color) {
        System.out.println("tire size:"+size+",color:"+color);
    }
}

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

1.2.5 IoC 优势

Tire -> Bottom -> Framework -> Car

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car


我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.
这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。

学到这⾥, 我们⼤概就知道了什么是控制反转了, 那什么是控制反转容器呢, 也就是IoC容器
在这里插入图片描述
这部分代码, 就是IoC容器做的⼯作.
从上⾯也可以看出来, IoC容器具备以下优点:
资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。

第⼀,资源集中管理,实现资源的可配置和易管理。
第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。
  1. 资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取就可以了
  2. 我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度, 也就是耦合度.Spring 就是⼀种IoC容器, 帮助我们来做了这些资源管理.

1.3 DI 介绍

上⾯学习了IoC, 什么是DI呢?

DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。

程序运⾏时需要某个资源,此时容器就为其提供这个资源
从这点来看, 依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。

上述代码中, 是通过构造函数的⽅式, 把依赖对象注⼊到需要使⽤的对象中的
在这里插入图片描述
IoC 是⼀种思想,也是"⽬标", ⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。所以也可以说, DI 是IoC的⼀种实现.

⽐如说我今天⼼情⽐较好,吃⼀顿好的犒劳犒劳⾃⼰,那么"吃⼀顿好的"是思想和⽬标(是IoC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是 DI。

2. IoC & DI 使⽤

对IoC和DI有了初步的了解, 我们接下来具体学习Spring IoC和DI的代码实现.
依然是先使⽤, 再学习

既然 Spring 是⼀个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:
• 存
• 取
Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出对象

当涉及到Spring Boot的IoC(控制反转)和DI(依赖注入)时,一个常见的实战案例是创建一个简单的RESTful API。

以下是一个基于Spring Boot的IoC和DI的实战代码案例:

首先,你需要创建一个简单的Maven项目,并添加Spring Boot的依赖。然后创建一个Controller类来处理RESTful请求,并创建一个Service类来处理业务逻辑。最后,通过依赖注入将Service类注入到Controller类中。

// Service类
@Service
public class UserService {
    public String getUserInfo() {
        return "User information";
    }
}

// Controller类
@RestController
public class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user")
    public String getUser() {
        return userService.getUserInfo();
    }
}

// Spring Boot应用入口类
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

在这个案例中,UserService类使用了@Service注解来告诉Spring它是一个Bean,而UserController类使用了@Autowired注解来告诉Spring需要将UserService注入到它的构造函数中。当Spring Boot应用启动时,它会自动扫描并创建这些Bean,并且处理它们之间的依赖关系。

通过这个案例,你可以看到IoC和DI是如何在Spring Boot应用中发挥作用的。当你发送GET请求到/user时,UserController会调用UserService来获取用户信息,并返回给客户端。这展示了IoC和DI如何帮助我们编写松耦合、可测试的代码。

⽬标: 把BookDao, BookService 交给Spring管理, 完成Controller层, Service层, Dao层的解耦

步骤:

  1. Service层及Dao层的实现类,交给Spring管理: 使⽤注解: @Component
  2. 在Controller层 和Service层 注⼊运⾏时依赖的对象: 使⽤注解 @Autowired实现:
  3. 把BookDao 交给Spring管理, 由Spring来管理对象

3. IoC 详解

通过上⾯的案例, 我们已经知道了Spring IoC 和DI的基本操作, 接下来我们来系统的学习Spring IoC和DI的操作.
前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。也就是bean的存储

3.1 Bean的存储

在之前的⼊⻔案例中,要把某个对象交给IOC容器管理,需要在类上添加⼀个注解: @Component ⽽Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解.

共有两类注解类型可以实现:

  1. 类注解:@Controller、@Service、@Repository@Component、@Configuration.
  2. ⽅法注解:@Bean.
    接下来我们分别来看

3.1.1 @Controller(控制器存储)

使⽤ @Controller 存储 bean 的代码如下所⽰:

@Controller // 将对象存储到 Spring 中
public class UserController {
	public void sayHi(){
		System.out.println("hi,UserController...");
	}
}
如何观察这个对象已经存在Spring容器当中了呢?
接下来我们学习如何从Spring容器中获取对象 ★

在Spring框架中,你可以使用注解来实现对象的注入和获取。首先,你需要在你的类中使用@Component或者其他相关的注解来标识这个类是一个Spring容器管理的Bean。然后,你可以使用@Autowired注解来实现对象的注入,或者使用@Resource注解来指定注入的对象。

举个例子,假设你有一个名为UserService的类,你可以这样标识它是一个Bean:

@Component
public class UserService {
    // ...
}

然后,在另一个类中,你可以使用@Autowired注解来注入UserService

@Component
public class UserController {
    @Autowired
    private UserService userService;

    // ...
}

这样,Spring容器会在启动时自动将UserService注入到UserController中。

如果你想手动从Spring容器中获取对象,你可以使用@Autowired或者@Resource注解来注入ApplicationContext,然后通过getBean方法来获取对象。示例代码如下:

ApplicationContext.getBean(手动获取bean对象)
@Component
public class SomeOtherClass {
    @Autowired
    private ApplicationContext context;

    public void doSomething() {
        UserService userService = context.getBean(UserService.class);
        // 使用userService对象进行操作
    }
}

这样,你就可以通过注解的方式实现对象的注入和获取。希望这能帮到你!

XML的方式注入的获取 ClassPathXmlApplicationContext

在Spring容器中获取对象通常需要使用ApplicationContext接口。以下是一个简单的示例代码,演示如何从Spring容器中获取对象:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        // 加载Spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从容器中获取对象
        YourObject yourObject = (YourObject) context.getBean("yourObjectBeanName");

        // 使用获取到的对象
        yourObject.doSomething();
    }
}

在上面的示例中,假设你有一个名为"YourObject"的类,并且在Spring配置文件"applicationContext.xml"中定义了该类的bean。通过调用context.getBean("yourObjectBeanName")方法,你可以从Spring容器中获取到该对象的实例。

获取bean对象的其他⽅式(beanFactory)

上述代码是根据类型来查找对象, 如果Spring容器中, 同⼀个类型存在多个bean的话, 怎么来获取呢?
ApplicationContext 也提供了其他获取bean的⽅式, ApplicationContext 获取bean对象的功能, 是⽗类BeanFactory提供的功能

public interface BeanFactory {
 
 //以上省略...
 
	 // 1. 根据bean名称获取bean
	 Object getBean(String var1) throws BeansException;
	 // 2. 根据bean名称和类型获取bean
	 <T> T getBean(String var1, Class<T> var2) throws BeansException;
	 // 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bean
	 Object getBean(String var1, Object... var2) throws BeansException;
	 // 4. 根据类型获取bean
	 <T> T getBean(Class<T> var1) throws BeansException;
	 // 5. 按bean类型和构造函数参数动态创建bean, 只适⽤于具有原型(prototype)作⽤域的bean
	 <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
 
 //以下省略...
}

常⽤的是上述1,2,4种, 这三种⽅式,获取到的bean是⼀样的
其中1,2种都涉及到根据名称来获取对象.

bean的名称是什么呢?
Spring bean是Spring框架在运⾏时管理的对象, Spring会给管理的对象起⼀个名字.
⽐如学校管理学⽣, 会给每个学⽣分配⼀个学号, 根据学号, 就可以找到对应的学⽣.
Spring也是如此, 给每个对象起⼀个名字, 根据Bean的名称(BeanId)就可以获取到对应的对象.

Bean 命名约定
我们看下官⽅⽂档的说明: Bean Overview :: Spring Framework

程序开发⼈员不需要为bean指定名称(BeanId), 如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称.
命名约定使⽤Java标准约定作为实例字段名. 也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写

⽐如
类名: UserController, Bean的名称为: userController
类名: AccountManager, Bean的名称为: accountManager
类名: AccountService, Bean的名称为: accountService

也有⼀些特殊情况, 当有多个字符并且第⼀个和第⼆个字符都是⼤写时, 将保留原始的⼤⼩写. 这些规则与java.beans.Introspector.decapitalize (Spring在这⾥使⽤的)定义的规则相同.
⽐如
类名: UController, Bean的名称为: UController
类名: AManager, Bean的名称为: AManager

根据这个命名规则, 我们来获取Bean

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		//根据bean类型, 从Spring上下⽂中获取对象
		UserController userController1 = context.getBean(UserController.class);
		//根据bean名称, 从Spring上下⽂中获取对象
		UserController userController2 = (UserController) context.getBean("userCon
		//根据bean类型+名称, 从Spring上下⽂中获取对象
		UserController userController3 = context.getBean("userController",UserCont
		
		System.out.println(userController1);
		System.out.println(userController2);
		System.out.println(userController3);
	}
}

在这里插入图片描述
地址⼀样, 说明对象是⼀个

获取bean对象, 是⽗类BeanFactory提供的功能

ApplicationContext VS BeanFactory(常⻅⾯试题) ★
  • 继承关系和功能⽅⾯来说:Spring 容器有两个顶级的接⼝:BeanFactory 和 ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能⼒,⽽ApplicationContext 属于 BeanFactory 的⼦类,它除了继承了 BeanFactory 的所有功能之外,它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持.
  • 从性能⽅⾯来说:ApplicationContext 是⼀次性加载并初始化所有的 Bean 对象,⽽BeanFactory 是需要那个才去加载那个,因此更加轻量. (空间换时间)

3.1.2 @Service(服务存储)

使⽤ @Service 存储 bean 的代码如下所⽰

@Service
public class UserService {
	public void sayHi(String name) {
		System.out.println("Hi," + name);
	}
}

读取 bean 的代码:

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring中获取UserService对象
		UserService userService = context.getBean(UserService.class);
		//使⽤对象
		userService.sayHi();
		}
	}

在这里插入图片描述

3.1.3 @Repository(仓库存储)

使⽤ @Repository 存储 bean 的代码如下所⽰

@Repository
public class UserRepository {
	public void sayHi() {
		System.out.println("Hi, UserRepository~");
	}
}

读取 bean 的代码

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		UserRepository userRepository = context.getBean(UserRepository.class);
		//使⽤对象
		userRepository.sayHi();
	}
}

在这里插入图片描述

3.1.4 @Component(组件存储)

使⽤ @Component 存储 bean 的代码如下所⽰:

@Component
public class UserComponent {
	public void sayHi() {
		System.out.println("Hi, UserComponent~");
	}
}

读取

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		UserComponent userComponent = context.getBean(UserComponent.class);
		//使⽤对象
		userComponent.sayHi();
	}
}

3.1.5 @Configuration(配置存储)

使⽤ @Configuration 存储 bean 的代码如下所⽰:

@Configuration
public class UserConfiguration {
	public void sayHi() {
		System.out.println("Hi,UserConfiguration~");
	}
}

读取

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		UserConfiguration userConfiguration = context.getBean(UserConfiguration.cl
		//使⽤对象
		userConfiguration.sayHi();
	}
}

3.2 为什么要这么多类注解?

这个也是和咱们前⾯讲的应⽤分层是呼应的. 让程序员看到类注解之后,就能直接了解当前类的⽤途.
• @Controller:控制层, 接收请求, 对请求进⾏处理, 并进⾏响应.
• @Servie:业务逻辑层, 处理具体的业务逻辑.
• @Repository:数据访问层,也称为持久层. 负责数据访问操作
• @Configuration:配置层. 处理项⽬中的⼀些配置信息.

这和每个省/市都有⾃⼰的⻋牌号是⼀样的.
⻋牌号都是唯⼀的, 标识⼀个⻋辆的. 但是为什么还需要设置不同的⻋牌开头呢.
⽐如陕西的⻋牌号就是:陕X:XXXXXX,北京的⻋牌号:京X:XXXXXX,甚⾄⼀个省不同的县区也是不同的,⽐如西安就是,陕A:XXXXX,咸阳:陕B:XXXXXX,宝鸡,陕C:XXXXXX,⼀样.这样做的好处除了可以节约号码之外,更重要的作⽤是可以直观的标识⼀辆⻋的归属地.

程序的应⽤分层,调⽤流程如下:
在这里插入图片描述
类注解之间的关系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发现:

在这里插入图片描述
其实这些注解⾥⾯都有⼀个注解 @Component ,说明它们本⾝就是属于 @Component 的"⼦类".
@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service ,@Repository 等. 这些注解被称为 @Component 的衍⽣注解.

@Controller , @Service 和 @Repository ⽤于更具体的⽤例(分别在控制层, 业务逻辑层, 持久化层), 在开发过程中, 如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更好的选择

⽐如杯⼦有喝⽔杯, 刷⽛杯等, 但是我们更倾向于在⽇常喝⽔时使⽤⽔杯, 洗漱时使⽤刷⽛杯.
更多资料参考:
https://docs.spring.io/spring-framework/reference/core/beans/classpathscanning.html#beans-stereotype-annotations

3.3 ⽅法注解 @Bean

类注解是添加到某个类上的, 但是存在两个问题:

  1. 使⽤外部包⾥的类, 没办法添加类注解
  2. ⼀个类, 需要多个对象, ⽐如多个数据源

这种场景, 我们就需要使⽤⽅法注解 @Bean

我们先来看看⽅法注解如何使⽤:

public class BeanConfig {
	@Bean
	public User user(){
		User user = new User();
		user.setName("zhangsan");
		user.setAge(18);
		return user;
	}
}

然⽽,当我们写完以上代码,尝试获取 bean 对象中的 user 时却发现,根本获取不到:

3.3.1 ⽅法注解要配合类注解使⽤

在 Spring 框架的设计中,⽅法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中,如下代码所⽰

@Component
public class BeanConfig {
	@Bean
	public User user(){
		User user = new User();
		user.setName("zhangsan");
		user.setAge(18);
		return user;
	}
}

3.3.2 定义多个对象

对于同⼀个类, 如何定义多个对象呢?

⽐如多数据源的场景, 类是同⼀个, 但是配置不同, 指向不同的数据源.

我们看下@Bean的使⽤

@Component
public class BeanConfig {
	@Bean
	public User user1(){
		User user = new User();
		user.setName("zhangsan");
		user.setAge(18);
		return user;
	}
	@Bean
	public User user2(){
		User user = new User();
		user.setName("lisi");
		user.setAge(19);
		return user;
	}
}

定义了多个对象的话, 我们根据类型获取对象, 获取的是哪个对象呢?

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		User user = context.getBean(User.class);
		//使⽤对象
		System.out.println(user);
	}
}

报错信息显⽰: 期望只有⼀个匹配, 结果发现了两个, user1, user2
从报错信息中, 可以看出来, @Bean 注解的bean, bean的名称就是它的⽅法名

接下来我们根据名称来获取bean对象

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//根据bean名称, 从Spring上下⽂中获取对象
		User user1 = (User) context.getBean("user1");
		User user2 = (User) context.getBean("user2");
		System.out.println(user1);
		System.out.println(user2);
	}
}

在这里插入图片描述
运⾏结果:
可以看到, @Bean 可以针对同⼀个类, 定义多个对象.

3.3.3 重命名 Bean

可以通过设置 name 属性给 Bean 对象进⾏重命名操作,如下代码所⽰:

@Bean(name = {"u1","user1"})
public User user1(){
	User user = new User();
	user.setName("zhangsan");
	user.setAge(18);
	return user;
}

此时我们使⽤ u1 就可以获取到 User 对象了,如下代码所⽰:

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		User u1 = (User) context.getBean("u1");
		//使⽤对象
		System.out.println(u1);
	}
}

name={} 可以省略,如下代码所⽰

@Bean({"u1","user1"})
public User user1(){
	 User user = new User();
	 user.setName("zhangsan");
	 user.setAge(18);
	 return user;
}

只有⼀个名称时, {}也可以省略, 如

@Bean("u1")
public User user1(){
	User user = new User();
	user.setName("zhangsan");
	user.setAge(18);
	return user;
}

3.4 扫描路径

@ComponentScan({“com.example.demo”})

Q: 使⽤前⾯学习的四个注解声明的bean,⼀定会⽣效吗?
A: 不⼀定(原因:bean想要⽣效,还需要被Spring扫描)

下⾯我们通过修改项⽬⼯程的⽬录结构,来测试bean对象是否⽣效:

在这里插入图片描述
再运⾏代码:

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
	//获取Spring上下⽂对象
	ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
	//从Spring上下⽂中获取对象
	User u1 = (User) context.getBean("u1");
	//使⽤对象
	System.out.println(u1);
	}
}

在这里插入图片描述
解释: 没有bean的名称为u1
为什么没有找到bean对象呢?
使⽤五⼤注解声明的bean,要想⽣效, 还需要配置扫描路径, 让Spring扫描到这些注解
也就是通过 @ComponentScan 来配置扫描路径.

@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		User u1 = (User) context.getBean("u1");
		//使⽤对象
		System.out.println(u1);
	}
}

{} ⾥可以配置多个包路径
这种做法仅做了解, 不做推荐使⽤

那为什么前⾯没有配置 @ComponentScan注解也可以呢?
@ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication 中了

默认扫描的范围是SpringBoot启动类所在包及其⼦包

在配置类上添加 @ComponentScan 注解, 该注解默认会扫描该类所在的包下所有的配置类

在这里插入图片描述
推荐做法:
把启动类放在我们希望扫描的包的路径下, 这样我们定义的bean就都可以被扫描到
在这里插入图片描述

4. DI 详解

上⾯我们讲解了控制反转IoC的细节,接下来呢,我们学习依赖注⼊DI的细节。

依赖注⼊是⼀个过程,是指IoC容器在创建Bean时, 去提供运⾏时所依赖的资源,⽽资源指的就是对象.在上⾯程序案例中,我们使⽤了 @Autowired 这个注解,完成了依赖注⼊的操作.
简单来说, 就是把对象取出来放到某个类的属性中.

在⼀些⽂章中, 依赖注⼊也被称之为 “对象注⼊”, “属性装配”, 具体含义需要结合⽂章的上下⽂来理解

关于依赖注⼊, Spring也给我们提供了三种⽅式:

  1. 属性注⼊(Field Injection)
  2. 构造⽅法注⼊(Constructor Injection)
  3. Setter 注⼊(Setter Injection)

接下来,我们分别来看。
下⾯我们按照实际开发中的模式,将 Service 类注⼊到Controller 类中。

4.1 属性注⼊

属性注⼊是使⽤ @Autowired 实现的,将 Service 类注⼊到 Controller 类中.
Service 类的实现代码如下:

import org.springframework.stereotype.Service;
@Service
public class UserService {
	public void sayHi() {
		System.out.println("Hi,UserService");
	}
}

Controller 类的实现代码如下:

@Controller
public class UserController {
	//注⼊⽅法1: 属性注⼊
	@Autowired
	private UserService userService;
	public void sayHi(){
		System.out.println("hi,UserController...");
		userService.sayHi();
	}
}

获取 Controller 中的 sayHi⽅法:

@SpringBootApplication
public class SpringIocDemoApplication {
	public static void main(String[] args) {
		//获取Spring上下⽂对象
		ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
		//从Spring上下⽂中获取对象
		UserController userController = (UserController) context.getBean("userCont
		//使⽤对象
		userController.sayHi();
	}
}

在这里插入图片描述
去掉@Autowired , 再运⾏⼀下程序看看结果

4.2 构造⽅法注⼊

构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所⽰:

@Controller
public class UserController2 {
	//注⼊⽅法2: 构造⽅法
	private UserService userService;
	@Autowired
	public UserController2(UserService userService) {
		this.userService = userService;
	}
	public void sayHi(){
		System.out.println("hi,UserController2...");
		userService.sayHi();
	}
}

注意事项:如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,
那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法。

4.3 Setter 注⼊

Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加上 @Autowired 注解 ,如下代码所⽰

@Controller
public class UserController3 {
	//注⼊⽅法3: Setter⽅法注⼊
	private UserService userService;
	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	public void sayHi(){
		System.out.println("hi,UserController3...");
		userService.sayHi();
	}
}

练习⼀下:尝试⼀下 set ⽅法如果不加 @Autowired 注解能注⼊成功吗?

4.4 三种注⼊优缺点分析

  • 属性注⼊

    • 优点: 简洁,使⽤⽅便;
    • 缺点:
      • 只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空指针异常)
      • 不能注⼊⼀个Final修饰的属性
  • 构造函数注⼊(Spring 4.X推荐)

    • 优点:
      • 可以注⼊final修饰的属性
      • 注⼊的对象不会被修改
      • 依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法.
      • 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的
      • 缺点:
        • 注⼊多个对象时, 代码会⽐较繁琐
  • Setter注⼊(Spring 3.X推荐)

    • 优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
    • 缺点:
      • 不能注⼊⼀个Final修饰的属性
      • 注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险.

4.5 @Autowired存在问题

当同⼀类型存在多个bean时, 使⽤@Autowired会存在问题

@Component
public class BeanConfig {
	@Bean("u1")
	public User user1(){
	User user = new User();
	user.setName("zhangsan");
	user.setAge(18);
	return user;
}
	@Bean
	public User user2() {
		User user = new User();
		user.setName("lisi");
		user.setAge(19);
		return user;
	}
}
@Controller
public class UserController {
 
	@Autowired
	private UserService userService;
	//注⼊user
	@Autowired
	private User user;
	public void sayHi(){
		System.out.println("hi,UserController...");
		userService.sayHi();
		System.out.println(user);
	}
}

在这里插入图片描述
报错的原因是,⾮唯⼀的 Bean 对象。
如何解决上述问题呢?Spring提供了以下⼏种解决⽅案:

  • @Primary
  • @Qualifier
  • @Resource
使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现.
@Component
public class BeanConfig {
	@Primary //指定该bean为默认bean的实现
	@Bean("u1")
	public User user1(){
		User user = new User();
		user.setName("zhangsan");
		user.setAge(18);
		return user;
	}
	@Bean
	public User user2() {
		User user = new User();
		user.setName("lisi");
		user.setAge(19);
		return user;
	 }
}
使⽤@Qualifier注解:指定当前要注⼊的bean对象。 在@Qualifier的value属性中,指定注⼊的bean的名称。
  • @Qualifier注解不能单独使⽤,必须配合@Autowired使⽤
@Controller
public class UserController {
	@Qualifier("user2") //指定bean名称
	@Autowired
	private User user;
	public void sayHi(){
		System.out.println("hi,UserController...");
		System.out.println(user);
	}
}
使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。
@Controller
public class UserController {
	@Resource(name = "user2")
	private User user;
	public void sayHi(){
		System.out.println("hi,UserController...");
		System.out.println(user);
	}
}

常⻅⾯试题:

@Autowird 与 @Resource的区别

• @Autowired 是spring框架提供的注解,⽽@Resource是JDK提供的注解
• @Autowired 默认是按照类型注⼊,⽽@Resource是按照名称注⼊. 相⽐于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean

5. 总结

Spring, Spring Boot 和Spring MVC的关系以及区别

Spring: 简单来说,== Spring 是⼀个开发应⽤框架==,什么样的框架呢,有这么⼏个标签:轻量级、⼀站式、模块化,其⽬的是⽤于简化企业级应⽤程序开发.

Spring的主要功能: 管理对象,以及对象之间的依赖关系, ⾯向切⾯编程, 数据库事务管理, 数据访问, web框架⽀持等.

但是Spring具备⾼度可开放性, 并不强制依赖Spring, 开发者可以⾃由选择Spring的部分或者全部, Spring可以⽆缝继承第三⽅框架, ⽐如数据访问框架(Hibernate 、JPA), web框架(如Struts、JSF)

Spring MVC: Spring MVC是Spring的⼀个⼦框架, Spring诞⽣之后, ⼤家觉得很好⽤, 于是按照MVC模式设计了⼀个 MVC框架(⼀些⽤Spring 解耦的组件), 主要⽤于开发WEB应⽤和⽹络接⼝,所以,Spring MVC 是⼀个Web框架.
Spring MVC基于Spring进⾏开发的, 天⽣的与Spring框架集成. 可以让我们更简洁的进⾏Web层开发, ⽀持灵活的 URL 到⻚⾯控制器的映射, 提供了强⼤的约定⼤于配置的契约式编程⽀持, ⾮常容易与其他视图框架集成,如 Velocity、FreeMarker等

Spring Boot: Spring Boot是对Spring的⼀个封装, 为了简化Spring应⽤的开发⽽出现的,中⼩型企业,没有成本研究⾃⼰的框架, 使⽤Spring Boot 可以更加快速的搭建框架, 降级开发成本, 让开发⼈员更加专注于Spring应⽤的开发,⽽⽆需过多关注XML的配置和⼀些底层的实现.

Spring Boot 是个脚⼿架, 插拔式搭建项⽬, 可以快速的集成其他框架进来⽐如想使⽤SpringBoot开发Web项⽬, 只需要引⼊Spring MVC框架即可, Web开发的⼯作是pringMVC完成的, ⽽不是SpringBoot, 想完成数据访问, 只需要引⼊Mybatis框架即可.Spring Boot只是辅助简化项⽬开发的, 让开发变得更加简单, 甚⾄不需要额外的web服务器, 直接⽣成jar包执⾏即可.

最后⼀句话总结: Spring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的⼀个MVC 框架,⽽Spring Boot 是基于Spring的⼀套快速开发整合包.

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

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

相关文章

带上作弊器,我不得起飞

前言 过去,我们对人工智能既期待又害怕.人类的惰性希望人工智能可以帮助大家从大部分繁重的工作中解放出来,但又害怕它失控. 智能系统的好处 工作方面 自动化与效率提升&#xff1a;可以自动执行许多重复性和低技能的任务&#xff0c;如制造业中的装配、数据输入和办公室的客户…

java的序列化和反序列化

一、概念 序列化是将对象的常态存储到特定的存储介质中的过程。 反序列化是将特定的存储介质中的数据重新构建对象的过程。 问题 为每个对象属性——编写读写代码&#xff0c;过程很繁琐且非常容易出错&#xff0c;如何解决&#xff1f; 二、使用Object Output Stream类实现…

敏捷开发笔记(第9章节)--开放-封闭原则(OCP)

目录 1&#xff1a;PDF上传链接 9.1 开放-封闭原则&#xff08;OCP&#xff09; 9.2 描述 9.3 关键是抽象 9.3.1 shape应用程序 9.3.2 违反OCP 糟糕的设计 9.3.3 遵循OCP 9.3.4 是的&#xff0c;我说谎了 9.3.5 预测变化和“贴切的”结构 9.3.6 放置吊钩 1.只受一次…

Spring专题一:源码编译

下载源码 因为公司使用的是Spring5.2.x所以就下载了这个版本&#xff0c;github源码地址如下&#xff1a; GitHub - spring-projects/spring-framework at v5.2.6.RELEASE&#xff1a; 如果网络不稳定可以使用下载压缩版即可&#xff0c;网络稳定的话还是建议使用git clone …

C语言的数据结构:树与二叉树(哈夫曼树篇)

前言 上篇讲完了二叉树&#xff0c;二叉树的查找性能要比树好很多&#xff0c;如平衡二叉树保证左右两边节点层级相差不会大于1&#xff0c;其查找的时间复杂度仅为 l o g 2 n log_2n log2​n&#xff0c;在两边层级相同时&#xff0c;其查找速度接近于二分查找。1w条数据&am…

今日AI提示词|新媒体运营场景-小红薯笔记通用指令

指令写作的技巧与步骤 明确定义需求 提供足够的上下文 使用简单直白的语言 举例说明 添加限制条件 多次迭代优化&#xff0c;给出详细的要求 小红薯笔记通用指令 从现在开始&#xff0c;你担任我的小红书创作者。你的任务是根据我提供给你的主体&#xff0c;撰写一篇小…

运维锅总详解HAProxy

本文尝试从HAProxy简介、HAProxy工作流程及其与Nginx的对比对其进行详细分析&#xff1b;在本文最后&#xff0c;给出了为什么Nginx比HAProxy更受欢迎的原因。希望对您有所帮助&#xff01; HAProxy简介 HAProxy&#xff08;High Availability Proxy&#xff09;是一款广泛使…

开源项目-商城管理系统

哈喽,大家好,今天主要给大家带来一个开源项目-商城管理系统 商城管理系统分前后端两部分。前端主要有商品展示,我的订单,个人中心等内容;后端的主要功能包括产品管理,门店管理,会员管理,订单管理等模块 移动端页面

汽车电子工程师入门系列——AUTOSAR通信服务框架(上)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

uniapp+vue3开发微信小程序踩坑集

本文主要记录使用uniappvue3开发微信小程序遇见的各种常见问题及注意点。&#xff08;持续更新&#xff09; 问题&#xff1a; 自定义组件为什么有些样式加不上去 给自定义组件增加class的时候&#xff0c;有时候不生效有时候生效&#xff0c;一度让我怀疑自己记忆错乱。后来…

实验 1 图像基本操作

1. 实验目的 ①熟悉 Photoshop 基本操作&#xff1b; ②掌握 Matlab 、PythonOpenCV 中处理图像的基本方法&#xff1b; ③掌握图像的半调转换和抖动转换。 2. 实验内容 ①Photoshop 基本操作&#xff1a;打开图像文件&#xff0c;选择区域&#xff0c;旋转、裁剪图像、图层…

PHP电商系统开发指南数据库管理

回答&#xff1a;数据库管理是电商系统开发的关键&#xff0c;涉及数据的存储、管理和检索。选择合适的数据库引擎&#xff0c;如mysql或 postgresql。创建数据库架构&#xff0c;定义数据的组织方式&#xff08;如产品表、订单表&#xff09;。进行数据建模&#xff0c;考虑实…

华润万家超市卡怎么用?

华润的礼品卡不仅能线下门店使用&#xff0c;还能直接叫送货上门 我最近用积分兑了几张华润卡&#xff0c;但是又没有购物需求&#xff0c;送朋友吧面值又不大&#xff0c;朋友也说用不上 最后朋友建议我在收卡云上把卡出掉&#xff0c;我试了下92折出掉了&#xff0c;价格还…

MySQL高级-MVCC-基本概念(当前读、快照读)

文章目录 1、MVCC基本概念1.1、当前读1.1.1、创建表 stu1.1.2、测试 1.2、快照读 1、MVCC基本概念 全称Multi-Version Concurrency Control&#xff0c;多版本并发控制。指维护一个数据的多个版本&#xff0c;使得读写操作没有冲突&#xff0c;快照读为MySQL实现MVCC提供了一个…

Python之父推荐!Star 60k!这本 CPython 书把内部实现全讲透了!

都说 Python 是人工智能的“天选”语言&#xff0c;为什么呢&#xff1f; 可能很多读者都知道&#xff0c;Python 的解释器是用 C 语言写的&#xff0c;所以其实我们在谈论 “Python” 的时候&#xff0c;99.9% 的情况说的就是 “CPython”&#xff01; CPython 是目前最流行的…

《昇思25天学习打卡营第11天 | 昇思MindSpore基于 MindSpore 实现 BERT 对话情绪识别》

11天本节学习到BERT全称是来自变换器的双向编码器表征量&#xff0c;它是Google于2018年末开发并发布的一种新型语言模型。BERT模型的主要创新点都在pre-train方法上&#xff0c;即用了Masked Language Model和Next Sentence Prediction两种方法分别捕捉词语和句子级别的repres…

数学学习与研究杂志社《数学学习与研究》杂志社2024年第6期目录

课改前沿 基于核心素养的高中数学课堂教学研究——以“直线与圆、圆与圆的位置关系”为例 张亚红; 2-4 核心素养视角下初中生数学阅读能力的培养策略探究 贾象虎; 5-7 初中数学大单元教学实践策略探索 耿忠义; 8-10《数学学习与研究》投稿&#xff1a;cn7kantougao…

x3daudio1_7.dll在哪个文件夹?打开游戏提示找不到x3daudio1_7.dll怎么解决?

电脑打开游戏软件时候&#xff0c;我相信大部分人都会遇到提示找不到x3daudio1_7.dll文件。或错误代码126&#xff1a;加载x3daudio1_7.dll失败等等问题&#xff0c;那这个是怎么回事呢&#xff1f;需要怎么解决这个问题&#xff1f;下面我给大家一一解答。 一、x3daudio1_7.dl…

C#测试调用DotnetSpider爬取网页内容

微信公众号“DotNet”的文章《.NET快速实现网页数据抓取》介绍了调用开源网页爬取模块DotnetSpider爬取cnblog网站文章的基本方式。之前学习过使用HtmlAgilityPack抓取并分析网页内容&#xff0c;DotnetSpider也依赖HtmlAgilityPack模块&#xff0c;不过前者属于轻量、高效的爬…

昇思MindSpore学习笔记5--数据变换Transforms

摘要&#xff1a; 昇思MindSpore的数据变换&#xff0c;包括通用变换Common Transforms、图像变换Vision Transforms、标准化Normalize、文本变换Text Transforms、匿名函数变换Lambda Transforms。 一、数据变换Transforms概念 原始数据需预处理后才能送入神经网络进行训练…