0


【Spring】Spring 入门介绍

文章目录

1. Spring 介绍

1.1 Spring 是什么?

Spring(Spring Framework) 是一个开源的轻量级框架,是包含了众多工具方法的 IoC 容器。

那么什么 是 IoC 容器呢?

容器 本身的含义是用来容纳某种物品的装置,而在之前的学习中,我们就应该接触过一些容器了,比如存储数据的容器 List、Map、Set 等等,Web 容器 Tomcat 等等。

那么 IoC 是什么呢?

1.2 IoC 是什么?

IoC(Inversion of Control),译为控制反转,它不是什么技术,而是一种思想。在 Java 开发中,IoC 意味着你将设计好的依赖对象 B 交给容器控制,而不是按照传统的方式,在你需要使用依赖对象 B 的对象 A 内部直接控制。

IoC 既然译为控制反转,那么我们就要理解谁控制谁,控制什么?要理解为何要反转,反转了什么?

谁控制谁,控制什么?

按照传统的设计思想,如果我们想要在 A 对象内部使用 B 对象,那么我们就会在 A 中直接 new 一个 B,这是我们程序员主动去创建的依赖对象;而 IoC 容器能够存储你需要的对象 B,当你要使用这个依赖对象 B 时,IoC 容器就会来控制依赖对象的创建,而程序只需要引入这个已经创建好的对象 B 就行。IoC 容器主要是控制了外部资源的获取(不只是包含要依赖的对象,还包括文件等等)。

为何要反转,反转了什么?

按照传统的设计思想,如果我们想要在 A 对象内部使用 B 对象,那么我们就会在 A 中直接 new 一个 B,这是我们程序员主动去创建的依赖对象;而反转则是使容器来帮忙创建并注入依赖对象,它使得对象 A 不需要再主动去创建对象 B 了,而是被动的接受由容器已经创建好的依赖对象,即对象创建、管理的控制权被反转了,依赖对象的获取被反转了。

IoC 的作用:

IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了 IoC 容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试。除此之外,将对象存储在 IoC 容器相当于将以后可能⽤到的所有⼯具制作好后都放到仓库中,需要的时候直接取出就⾏,⽤完再把它放回到仓库,利于复用。⽽ new 对象的⽅式相当于,每次需要⼯具时,才现做,⽤完就扔掉了也不会保存,下次再⽤的时候还得重新做。

注意:

并不是只有 Spring 的容器才叫 IoC 容器,基于 IoC 容器的框架还有很多,并非是 Spring 特有的

到这里 IoC 已经差不多介绍完了,从上面的介绍可知 IoC 它只是一种思想,那么 IoC 思想具体的实现是怎么样的呢?我们就不得不提到 DI。

1.3 DI 是什么?

DI(Dependency Injection),译为依赖注入,它是指 IoC 容器在运行期间,动态地将某种依赖关系注入到对象之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

DI 既然译为依赖注入,那么我们就要理解谁依赖谁,为什么需要依赖,谁注入谁,注入了什么?

  • 谁依赖谁:应用程序依赖 IoC 容器。
  • 为什么需要依赖:应用程序需要 IoC 容器来提供对象所需的外部资源。
  • 谁注入谁:IoC 容器注入应用程序某个对象。
  • 注入了什么:注入了某个对象所需的外部资源(包括对象、资源、常量数据等等)。

IoC 和 DI 的关系:

IoC 和 DI 其实是同一个概念的不同角度的描述,IoC 是一种思想,而 DI 是具体的实现,通过引入 IoC 容器,利用依赖关系注入的方式,就能实现对象之间的解耦。

1.4 Spring 的核心功能

回归主题,Spring 是包含了众多工具方法的 IoC 容器,我们已经介绍了 IoC 是什么,那么如何理解“Spring 就是一个 IoC 容器”呢?

上面介绍了很多关于 IoC 的知识,但是 Spring 的本质上是一个容器,容器才是 Spring 框架实现功能的核心,既然 Spring 是一个容器,它就会具备容器的两个最基础的功能:

  • 将对象存入到容器
  • 从容器中取出对象

也就是说 Spring 最核心的功能 就是将对象存入到 Spring 中,再从 Spring 中获取到对象。又因为 Spring 是⼀个 IoC 容器,那么除了它本身具备的存储对象和获取对象的能⼒,还具有管理对象的创建和销毁的权利。

1.5 Spring 的应用上下文

我们已经了解了 Spring 是一个 IoC 容器,但是容器只是一个提供给需要被管理的对象的空间,还需要通过 Spring 的应用上下文,来向容器中添加我们需要的被管理的对象。

Spring 的应用上下文 可以简单的理解成将你需要 Spring 帮你管理的对象放入到容器的容器对象,它是 Spring 容器的一种抽象化表述。

常用的 Spring 上下文对象为

ApplicationContext

,它本质上就是一个维护 Bean 定义以及对象之间协作关系的高级接口,它是继承了上下文对象

BeanFactory

后派生而来的应用上下文的抽象接口。在功能上,相比于

BeanFactory

只能提供基本的 DI 功能,它能提供更多的企业级的服务,比如对国际化支持、资源访问、以及事件传播等等。在性能上,

ApplicationContext

是⼀次性加载并初始化所有的 Bean 对象(在获取上下文时,就会创建初始化所有的 Bean对象),所以调用快,⽽

BeanFactory

是需要哪个 Bean 才去加载哪个 Bean(在 getBean 时才会创建初始化指定的 Bean 对象),因此更加轻量,但调用慢。

对于上述两种上下文抽象接口,Spring 提供了多种类型的容器实现,用于不同场景的使用

  • ClassPathXmlApplicationContext:从类路径下的一个或多个 xml 配置文件中加载上下文,适用于 xml 配置的方式。
  • AnnotationConfigApplicationContext:从基于一个或多个 Java 的配置类中加载上下文,适用于 Java 注解的方式。
  • FileSystemXmlApplicationContext:从文件系统下的一个或多个 xml 配置文件中加载上下文,从系统盘符中加载 xml 配置文件。
  • AnnotationConfigWebApplicationContext:专门为 web 应用准备的,适用于注解方式。
  • XmlWebApplicationContext:从 web 应用下的一个或多个 xml 配置文件加载上下文,适用于 xml 配置方式。

2. Spring 项目的创建和使用

在 Java 语言中对象也叫做 Bean,因此以下遇到的对象将以 Bean 著称。

2.1 创建 Maven 项目

  1. 创建一个 Maven 项目(在 IDEA 中创建好 Maven 项目)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2nWup5wP-1652100428086)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220502191634995.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fTCOwtyt-1652100428087)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220502192038704.png)]
  2. 添加 Spring 框架支持(在项目的 pom.xml 文件中添加 Spring 框架的支持,配置如下)> Spring 项目需要添加的依赖有 > > spring-context> > (Spring 上下文)和 > > spring-beans> > (管理对象的模块)。可以去 Maven 中央仓库搜索,也可以直接使用下面的依赖。<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.3.RELEASE</version></dependency></dependencies>
  3. 添加启动类(在 /src/main/java 目录下创建一个启动类,类名自定义,包含 main 方法即可)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VbFWEQrY-1652100428087)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220502193459796.png)]

2.2 存储 Bean 对象

  1. 创建好需要的 Bean(可以创建一个包,用于存放要创建的 Bean)> 存储 Bean 分为两个步骤,先创建好需要的 Bean,再将创建好的 Bean 注册到 Spring 容器中[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fZmrW0f7-1652100428088)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220502194813400.png)]
  2. 将 Bean 注册到 Spring 容器中> 先在 > > resources> > 目录下创建一个 > > xml> > 文件(文件名没有要求),用于存放 Spring 的配置文件,配置文件是固定的内容,内容如下。<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"></beans>> 将创建好的 Bean 添加到 Spring 配置文件中。在原有的 beans 标签内再创建一个 beans 标签,里面用于存放要注册的 Bean,然后在创建好的 beans 标签内创建一个 bean 标签,表示要注册的某个 Bean,该 bean 标签内添加一个 id 属性表示存储对象在 Spring 中的身份标识,即 Bean 对象的名字,再添加一个 class 属性表示要存储的对象(包含包名和类名)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LvMmNwgl-1652100428088)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220502200326618.png)]补充: Spring 存储 Bean 时的命名规则> > - 当 bean 标签中主动设置 id 属性来命名 Bean 对象的名字时,Spring 中存储该 Bean 的名字即为 id 的值。(源码如下)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PAotCmTW-1652100428088)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505095038931.png)]> > - 当 bean 标签没有设置 id 属性来命名 Bean 对象的名字时,Spring 中存储该 Bean 时生成的命名规则为:当类名的长度大于1,且第一个字符和第二个字符都为大写时,则直接命名为类名;否则将类名的第一个字符转成小写后,再返回新生成的字符。(源码如下)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8WFVbNCi-1652100428089)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505095234487.png)]

2.3 获取并使用 Bean 对象

  1. 创建 Spring 上下文(这里使用 ApplicationContext 作为上下文对象,也可以使用 BeanFactory// 得到 Spring 的上下⽂对象,创建的时候需要配置 Spring 配置信息ApplicationContext context =newClassPathXmlApplicationContext("spring-config.xml");
  2. 获取指定的 Bean 对象(这里使用上文正已经注册到 Spring 容器中的 Bean 对象 User)> > getBean> > 方法用于加载上下文中的 Bean 对象,它有多种重载的方法> > > - Object getBean(Bean 对象的名字)> - T getBean(Bean 对象的名字, 要加载的类对象)> - T getBean(要加载的类对象)> > 注意: 如果当前的一个类型被重复注册到 Spring 的配置文件中,那么不能使用第三种方式去获取 Bean 对象,需要根据名称来获取。> > [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y6UPvNZ1-1652100428089)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220503022424788.png)]// 方式一User user =(User) context.getBean("user");// 方式二User user =(User) context.getBean("user",User.class);// 方式三User user =(User) context.getBean(User.class);
  3. 使用 Beanuser.say();[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K02UORe9-1652100428089)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220503020729626.png)]注意:Spring 中的 Bean 默认是单例模式。可以再创建一个 User 实例,打印两个实例得到结论[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1aLYXj9s-1652100428090)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505102211209.png)]

3. Spring 更简单的读取和存储对象方式

上面实现了基本的 Spring 存储和读取对象的操作,但是在操作过程中并不是那么的简单,接下来将介绍更简单的存储和读取 Bean 对象的方法,即使用注解。

3.1 存储 Bean 对象

之前将 Bean 存储到 Spring 中的方法,是在 Spring 的配置文件中直接添加 bean 注册内容,示例如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSb4IGFC-1652100428090)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220504174434374.png)]

而通过使用注解,就无需在存储一个 Bean 对象时,在 Spring 的配置文件中再添加一个注册内容,只要在 Spring 的配置文件中配置一个扫描路径即可实现 Bean 的批量注册。

3.1.1 配置扫描路径

Spring 引入了组件自动扫描机制,它可以在类路径底下,扫描配置的

base-package

包下所有标注了

@Component

@Service

@Controller

@Repository

@Configuration

注解的类,并把这些类纳入进Spring 容器中管理。

在 Spring 配置文件中添加如下配置:

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:content="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
https://www.springframework.org/schema/context/spring-context.xsd"><content:component-scanbase-package="com.t4.beans"></content:component-scan></beans>

3.1.2 注册 Bean 相关的注解介绍

想要将对象存储在 Spring 中,有两种类型的注解可以实现:

  • 类注解: 注解在类上,用于标识组件的类型注解描述@Controller组合了 @Component 注解,应用在 mvc 层(控制层),DispatcherServlet 会自动扫描注解了此注解的类,然后将 web 请求映射到注解了@RequestMapping 的方法上。@Service组合了 @Component 注解,应用在 service 层(业务逻辑层)。@Repository组合了 @Component 注解,应用在 dao 层(数据访问层)。@Component表示该类是一个“组件”,成为 Spring 管理的 Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component 还是一个元注解。@Configuration声明当前类为配置类,其中内部组合了@Component 注解,表明这个类是一个 Bean。
  • 方法注解: 注解在方法上注解描述@Bean声明当前方法的返回值是一个 Bean,返回的 Bean 对应的类中可以定义 init() 方法和 destroy() 方法。

为何说

@Controller

@Service

@Repository

@Configuration

都组合了

@Component

注解呢?

通过源码发现,这些注解本身都带了一个注解

@Component

,即它们本身就属于

@Component

的“子类”

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dXMZhle6-1652100428091)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505092450155.png)]

3.1.3 添加 @Controller 注解存储 Bean 对象

示例代码:

packagecom.t4.beans;importorg.springframework.stereotype.Controller;@ControllerpublicclassUserController{publicvoidsay(){System.out.println("你好 Controller!");}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qFB1HCuF-1652100428091)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505084504964.png)]

3.1.4 添加 @Service 注解存储 Bean 对象

示例代码:

packagecom.t4.beans;importorg.springframework.stereotype.Service;@ServicepublicclassUserService{publicvoidsay(){System.out.println("你好 Service!");}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5mNCbs4J-1652100428091)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505085203591.png)]

3.1.5 添加 @Repository 注解存储 Bean 对象

示例代码:

packagecom.t4.beans;importorg.springframework.stereotype.Repository;@RepositorypublicclassUserRepository{publicvoidsay(){System.out.println("你好 Repository!");}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRRQdrh0-1652100428092)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505085513721.png)]

3.1.6 添加 @Component 注解存储 Bean 对象

示例代码:

packagecom.t4.beans;importorg.springframework.stereotype.Component;@ComponentpublicclassUserComponent{publicvoidsay(){System.out.println("你好 Component!");}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-un8wOnbe-1652100428092)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505085900127.png)]

3.1.7 添加 @Configuration 注解存储 Bean 对象

示例代码:

packagecom.t4.beans;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassUserConfiguration{publicvoidsay(){System.out.println("你好 Configuration!");}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqIB2Peo-1652100428092)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505090351963.png)]

3.1.8 添加 @Bean 注解存储 Bean 对象

注解

@Bean

需要与类注解搭配使用,例如常与注解

@Configuration

结合使用。带有

@Bean

注解的方法返回的对象会存到 Spring 容器中,Bean 对象的名字为方法名。

虽说使用

@Bean

注解要搭配类注解使用,看似要多出一笔,但是加上了类注解后能大大加快扫描的性能。

示例代码:

packagecom.t4.beans;importcom.t4.model.UserInfo;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassUserBeans{@BeanpublicUserInfogetUserInfo(){UserInfo userInfo =newUserInfo();
        userInfo.setId(1);
        userInfo.setName("张三");
        userInfo.setPassword("1234");return userInfo;}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WKdR0ZEv-1652100428093)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505114949761.png)]

重命名 Bean:

由于方法名不能很直观的显示 Bean 名,为此可以重命名 Bean。重命名方式为:在

@Bean

注解后面增加一个 name 属性,该属性可以含多个值,其中

name = {}

都可以省略,只带新的 Bean 名。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0kUyViBj-1652100428093)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505120005640.png)]

注意1: 重命名后,如果起了多个名字,则使用任意一个都可以。但是不能再使用原方法名去获取 Bean

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bg6RPMtT-1652100428093)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505120400000.png)]

注意2: 重命名后,如果起了多个名字,获取的对象都是同一个[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2uivQsFD-1652100428093)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220505145534680.png)]

3.2 获取 Bean 对象

获取 Bean 对象也叫做对象装配或者对象注入,是把对象从容器中取出来放到某个类中。

之前我们介绍了先通过获取 Spring 应用上下文,再从中获取 Bean 对象的方法去得到 Bean,但是整体显得比较麻烦。接下来将介绍三种更简单的对象注入的方法:

  • 方法一:属性注入
  • 方法二:构造方法注入
  • 方法三:Setter 注入

3.2.1 注入 Bean 相关注解介绍

这里介绍三种和注入 Bean 相关的注解:
注解描述包含的属性

@Autowired

可以标注在属性、构造方法和 Setter 方法上,用于完成自动装配。默认通过 Bean 类型进行查询,如果查询不到则会再通过 Bean 对象名进行查询,为 Spring 提供的注解。

required
@Resource

可以标注在属性和 Setter 方法上,用于完成自动装配。默认通过 Bean 名进行查询,为 JDK 提供的注解。

name

type

@Qualifier

用于指定需要注入的 Bean 对象的名字

value
  • 使用 @Autowired 自动注入的时候,可以在属性或参数加上 @Qualifier("xxx") 指定注入到对象;
  • 使用 @Autowired 注解时,当 Spring 无法找到匹配的 Bean 装配,它会抛出异常。要解决这个问题,可以通过 @Autowiredrequired 属性设置为 false 来禁用此检查功能。
  • Spring 将 @Resource 注解的 name 属性的值解析为为 Bean 的名字,type 属性的值解析为为 Bean 的类型。
  • 使用 @Resource 注解默认通过 Bean 名进行查询装配。如果使用 name 属性,则使用 Bean 名 自动注入策略;如果使用 type 属性,则使用 Bean 类型自动注入策略。
  • @Autowired 注解用于构造方法注入时,如果只有一个构造方法,可以省略使用 @Autowired,如果有多个注解则不能省略。
  • @Autowired 可以用于数组和使用泛型的集合类型,然后 Spring 会将容器中所有类型符合的 Bean 注入进来。@Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。
  • @Autowired 标注作用于普通方法时,会产生一个副作用,就是在容器初始化该 Bean 实例的时候就会调用该方法。当然,前提是执行了自动装配,对于不满足装配条件的情况,该方法也不会被执行。

3.2.2 属性注入 Bean 对象

在需要的类中先创建一个要被注入的对象(该对象可以是一个集合,那么得到的结果就是所有匹配的 Bean 的集合),并在该对象上加上

@Autowired

@Resource

注解。

代码情景:

创建了一个 UserService 类,里面包含了 name 和 password 两个字段,将这个类存储到 Spring 中。在上述代码中的 UserController 类中通过 @Autowired 注解来将 UserService 这个对象注入到该类中,并创建了一个 getUserService 方法打印获取到的 Bean 对象。而 UserController 类本身又在启动类中被获取后调用 getUserService 方法。

示例代码1: 使用

@Autowired

注解

@ControllerpublicclassUserController{@AutowiredprivateUserService userService;publicvoidgetUserService(){System.out.println(userService);}}

示例代码2: 使用

@Resource

注解

@ControllerpublicclassUserController{@ResourceprivateUserService userService;publicvoidgetUserService(){System.out.println(userService);}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y22FnvUW-1652100428094)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220506174714930.png)]

3.2.3 构造方法注入 Bean 对象

在需要的类中先创建一个要被注入的对象,然后创建该类的构造方法,将要被注入的对象进行赋值,并在构造方法上加上

@Autowired

注解。

代码情景:

创建了一个 UserService 类,里面包含了 name 和 password 两个字段,将这个类存储到 Spring 中。在上述代码中的 UserController 类中通过 @Autowired 注解来将 UserService 这个对象注入到该类中,并创建了一个 getUserService 方法打印获取到的 Bean 对象。而 UserController 类本身又在启动类中被获取后调用 getUserService 方法。

示例代码:

使用 @Autowired 注解
@ControllerpublicclassUserController{privateUserService userService;@AutowiredpublicUserController(UserService userService){this.userService = userService;}publicvoidgetUSerService(){System.out.println(userService);}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWqpqTbd-1652100428094)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220506174955200.png)]

3.2.4 Setter 注入 Bean 对象

在需要的类中先创建一个要被注入的对象,然后创建该类的 Setter 方法,将要被注入的对象进行赋值,并在 Setter方法上加上

@Autowired

@Resource

注解。

代码情景:

创建了一个 UserService 类,里面包含了 name 和 password 两个字段,将这个类存储到 Spring 中。在上述代码中的 UserController 类中通过 @Autowired 注解来将 UserService 这个对象注入到该类中,并创建了一个 getUserService 方法打印获取到的 Bean 对象。而 UserController 类本身又在启动类中被获取后调用 getUserService 方法。

示例代码1: 使用

@Autowired

注解

@ControllerpublicclassUserController{privateUserService userService;@AutowiredpublicvoidsetUserService(UserService userService){this.userService = userService;}publicvoidgetUSerService(){System.out.println(userService);}}

示例代码2: 使用

@Resource

注解

@ControllerpublicclassUserController{privateUserService userService;@ResourcepublicvoidsetUserService(UserService userService){this.userService = userService;}publicvoidgetUSerService(){System.out.println(userService);}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1fWtCZ1v-1652100428094)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220506175121522.png)]

3.2.5 三种注入方式的优缺点

注入方式优点缺点属性注入写法最简单,可读性高。只适应 IoC 容器,移植性差。构造方法注入可以适应非 IoC 容器,通用性好,代码移植性高。如果有多个注入,代码会显得比较臃肿。Setter 注入只有对象是需要被注入时,才会注入依赖,而不是在这个类初始化的时候就注入。可以适应非 IoC 容器,通用性好,代码移植性高。不能将对象设为 final。

3.2.6 同一类型多个 @Bean 报错问题

当出现多个 Bean 返回的对象类型都相同时,如果注入的注解不设置具体注入的哪个 Bean,则会报错。对于这个问题有两种解决方式:

  • 对于 @Autowired 注解,可以搭配一个 @Qualifuer 来指定要注入的 Bean
  • 对于 @Resource 注解,可以设置一个 name 属性来指定要注入的 Bean

代码情景:

创建了一个 User 类,里面包含了 name 和 password 两个字段。再创建一个 UserService 类这个类通过两个 @Bean 注解的方法注册两个类型相同,名字不同的 Bean 存储到 Spring 中。在上述代码中的 UserController 类中通过 @Autowired 注解来将 User 这个对象注入到该类中,并创建了一个 printUser 方法打印获取到的 Bean 对象。而 UserController 类本身又在启动类中被获取后调用 printUser 方法。

示例代码1: 对于

@Autowired

的解决方式

@ControllerpublicclassUserController{@Autowired@Qualifier(value ="user1")privateUser user;publicvoidprintUser(){System.out.println(user);}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y3wwt1dB-1652100428095)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220507031744725.png)]

示例代码2: 对于

@Resource

的解决方式

@ControllerpublicclassUserController{@Resource(name ="user2")privateUser user;publicvoidprintUser(){System.out.println(user);}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75qT9eLb-1652100428095)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220507031654728.png)]

4. Bean 的作用域

当在 Spring 中定义一个 bean 时,你可以声明该 bean 的作用域。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype,即多例作用域。同理,如果你想让 Spring 在每次需要时都返回同一个 bean 实例,你应该声明 bean 的作用域的属性为 singleton,即单例作用域。

在 Spring 中 Bean 默认情况下是单例状态,即所有人拿到的 Bean 都是同一个对象。设置为单例减少了新生成实例的消耗、减少了 JVM 垃圾回收、能够快速获取到 Bean,也就是说能够很大程度的提高性能。

4.1 Bean 的六种作用域

Spring 容器在初始化一个 Bean 实例时,同时会指定该实例的作用域。Spring 有六种作用域,前两种是基于 整个 Spring 生态生效的,后四种是基于 Spring MVC 生效的。

4.1.1 单例作用域 singleton

  • 官方说明: (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
  • 描述: 该作⽤域下的 Bean 在 IoC 容器中只存在⼀个实例:获取 Bean(即通过 applicationContext.getBean等⽅法获取)及装配 Bean(即通过 @Autowired 注⼊)都是同⼀个对象。
  • 场景: 通常⽆状态的 Bean 使⽤该作⽤域。⽆状态表示 Bean 对象的属性状态不需要更新。
  • 备注: Spring 默认选择该作⽤域

4.1.2 原型作用域/多例作用域 prototype

  • 官⽅说明: Scopes a single bean definition to any number of object instances.
  • 描述: 每次对该作⽤域下的 Bean 的请求都会创建新的实例:获取 Bean(即通过 applicationContext.getBean 等⽅法获取)及装配Bean(即通过 @Autowired 注⼊)都是新的对象实例。
  • 场景: 通常有状态的 Bean 使⽤该作⽤域

4.1.3 请求作用域 request

  • 官⽅说明: Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:每次 HTTP 请求会创建新的 Bean 实例,类似于 prototype
  • 场景: ⼀次 HTTP 的请求和响应的共享 Bean
  • 备注: 限定 Spring MVC 中使⽤

4.1.4 会话作用域 session

  • 官⽅说明: Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述:在⼀个 HTTP Session 中,定义⼀个 Bean 实例
  • 场景: ⽤户会话的共享 Bean,⽐如:记录⼀个⽤户的登陆信息
  • 备注: 限定 Spring MVC 中使⽤

4.1.5 全局作用域 application

  • 官⽅说明: Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述: 在⼀个 http servlet Context 中,定义⼀个 Bean 实例
  • 场景: Web 应⽤的上下⽂信息,⽐如:记录⼀个应⽤的共享信息
  • 备注: 限定 SpringMVC 中使⽤

4.1.6 HTTP WebSocket 作用域 websocket

  • 官⽅说明: Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
  • 描述: 在⼀个 HTTP WebSocket 的⽣命周期中,定义⼀个 Bean 实例
  • 场景: WebSocket 的每次会话中,保存了⼀个 Map 结构的头信息,将⽤来包裹客户端消息头。第⼀次初始化后,直到 WebSocket 结束都是同⼀个 Bean。
  • 备注: 限定 Spring WebSocket 中使⽤

4.2 单例作用域和全局作用域的区别

  • singleton 是 Spring Core 的作用域;application 是 Spring Web 的作用域
  • singleton 作用于 IoC 容器;application 作用于 Servlet 容器

4.3 设置作用域的方法

设置 Bean 的作用域有两种方式

  • 方式一:在 Spring 配置文件中,对于注册的每一个 Bean 可以增加一个 scope 属性来设置 Bean 的作用域
  • 方式二:通过 @Scope 注解就可以声明 Bean 的作用域,它既可以修饰方法也可以修饰类

示例代码1: 方式一

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3OthSFoB-1652100428095)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220509143555032.png)]

代码示例2: 方式二

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CJF6mIGI-1652100428096)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220509131151818.png)]

5. Bean 的原理分析

5.1 Spring 的执行流程

Spring 的执行流程可以分为以下几步:

  1. 启动 Spring 容器(在 main 方法中启动)
  2. 实例化 Bean(加载 Spring 配置文件,实例化并申请内存)
  3. 将 Bean 注册到 Spring 中(将添加了和 Spring 注册 Bean 相关的注解的对象存储到容器中)
  4. 将 Bean 装配到需要的类中

5.2 Bean 的生命周期

Bean 的生命周期可以分为以下几个部分:

  1. 实例化 Bean(为 Bean 分配内存空间)
  2. 设置 Bean 属性(依赖注入和装配,必须在初始化 Bean 之前,因为初始化的时候可能会用到 Bean 对象)
  3. 初始化 Bean(初始化 Bean 时会按顺序执行以下几小步)- 实现各种 Aware 通知的方法,如 BeanNameAwareBeanFactoryAwareApplicationContextAware 的接口方法- 执行 BeanPostProcessor 初始化前置方法- 执行 @PostConstruct 初始化方法,依赖注入操作之后被执行- 判断是否继承了 InitializingBean 接口(调用 afterPropertiesSet 方法)- 执行自己的 init-method 初始化方法- 执行 BeanPostProcessor 初始化后置方法
  4. 使用 Bean
  5. 销毁 Bean- 执行 @PreDestory 销毁前的方法- 判断是否继承了 DisposableBean 接口(调用- 执行自己的 destory-method 销毁前的方法

接下来可以通过一段代码来验证 Bean 的生命周期的过程,示例代码如下:

@ControllerpublicclassBeanLifeimplementsBeanNameAware,InitializingBean,DisposableBean{@OverridepublicvoidsetBeanName(String s){System.out.println("执行 BeanNameAware 接口的方法:"+ s);}@PostConstructpublicvoidpostConstruct(){System.out.println("执行 @PostConstruct");}@OverridepublicvoidafterPropertiesSet()throwsException{System.out.println("继承了 InitializingBean");}publicvoidmyInit(){System.out.println("执行 init-method");}@PreDestroypublicvoidpreDestroy(){System.out.println("执行 @PreDestroy");}publicvoiddestroy(){System.out.println("继承了 DisposableBean");}publicvoidmyDestroy(){System.out.println("执行 destroy-method");}}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9lcsWITe-1652100428096)(C:/Users/bbbbbge/Pictures/%E6%8E%A5%E5%8D%95/image-20220509204337936.png)]

标签: spring java 后端

本文转载自: https://blog.csdn.net/weixin_51367845/article/details/124674940
版权归原作者 吞吞吐吐大魔王 所有, 如有侵权,请联系我们删除。

“【Spring】Spring 入门介绍”的评论:

还没有评论