SpringBoot原理-Bean管理(黑马学习笔记)

Bean管理

我们可以通过Spring当中提供的注解@Component以及它的三个衍生注解(@Controller、@Service、@Repository)来声明IOC容器中的bean对象,同时我们也学习了如何为应用程序注入运行时所需要依赖的bean对象,也就是依赖注入DI。

我们今天主要学习IOC容器中Bean的其他使用细节,主要学习以下三方面:

  1. 如何从IOC容器中手动的获取到bean对象

  2. bean的作用域配置

  3. 管理第三方的bean对象

接下来我们先来学习第一方面,从IOC容器中获取bean对象。

获取Bean

默认情况下,SpringBoot项目在启动的时候会自动的创建IOC容器(也称为Spring容器),并且在启动的过程当中会自动的将bean对象都创建好,存放在IOC容器当中。应用程序在运行时需要依赖什么bean对象,就直接进行依赖注入就可以了。

而在Spring容器中提供了一些方法,可以主动从IOC容器中获取到bean对象,下面介绍3种常用方式:

    1.根据name获取bean

Object getBean(String name)

    2.根据类型获取bean

<T> T getBean(Class<T> requiredType)

    3.根据name获取bean(带类型转换)

<T> T getBean(String name, Class<T> requiredType)

思考:要从IOC容器当中来获取到bean对象,需要先拿到IOC容器对象,怎么样才能拿到IOC容器呢?

    ● 要获取到IOC容器,直接将IOC容器对象注入进来就可以了

控制器:DeptController

@RestController
@RequestMapping("/depts")
public class DeptController {@Autowiredprivate DeptService deptService;public DeptController(){System.out.println("DeptController constructor ....");}@GetMappingpublic Result list(){List<Dept> deptList = deptService.list();return Result.success(deptList);}@DeleteMapping("/{id}")public Result delete(@PathVariable Integer id)  {deptService.delete(id);return Result.success();}@PostMappingpublic Result save(@RequestBody Dept dept){deptService.save(dept);return Result.success();}
}

业务实现类:DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Overridepublic List<Dept> list() {List<Dept> deptList = deptMapper.list();return deptList;}@Overridepublic void delete(Integer id) {deptMapper.delete(id);}@Overridepublic void save(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.save(dept);}
}

Mapper接口:

@Mapper
public interface DeptMapper {//查询全部部门数据@Select("select * from dept")List<Dept> list();//删除部门@Delete("delete from dept where id = #{id}")void delete(Integer id);//新增部门@Insert("insert into dept(name, create_time, update_time) values (#{name},#{createTime},#{updateTime})")void save(Dept dept);
}

测试类:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {@Autowiredprivate ApplicationContext applicationContext; //IOC容器对象//获取bean对象@Testpublic void testGetBean(){//根据bean的名称获取DeptController bean1 = (DeptController) applicationContext.getBean("deptController");System.out.println(bean1);//根据bean的类型获取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);//根据bean的名称 及 类型获取DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);System.out.println(bean3);}
}

程序运行后控制台日志:

问题:输出的bean对象地址值是一样的,说明IOC容器当中的bean对象有几个?

答案:只有一个。(默认情况下,IOC中的bean对象是单例)

那么能不能将bean对象设置为非单例的(每次获取的bean都是一个新对象)?

可以,在下一个知识点(bean作用域)中讲解。

注意事项:

    ● 上述所说的【Spring项目启动时,会把其中的bean都创建好】还会受到作用域及延迟初始化影响,这里主要针对于默认的单例非延迟加载的bean而言。

Bean作用域

在前面我们提到的IOC容器当中,默认bean对象是单例模式(只有一个实例对象)。那么如何设置bean对象为非单例呢?需要设置bean的作用域。

在Spring中支持五种作用域,后三种在web环境才生效:

作用域说明
singleton容器内同名称的bean只有一个实例(单例)(默认)
prototype每次使用该bean时会创建新的实例(非单例)
request每个请求范围内会创建新的实例(web环境中,了解)
session每个会话范围内会创建新的实例(web环境中,了解)
application

每个应用范围内会创建新的实例(web环境中,了解)

知道了bean的5种作用域了,我们要怎么去设置一个bean的作用域呢?

● 可以借助Spring中的@Scope注解来进行配置作用域

1). 测试一

    ● 控制器

//默认bean的作用域为:singleton (单例)
@Lazy //延迟加载(第一次使用bean对象时,才会创建bean对象并交给ioc容器管理)
@RestController
@RequestMapping("/depts")
public class DeptController {@Autowiredprivate DeptService deptService;public DeptController(){System.out.println("DeptController constructor ....");}//省略其他代码...
}

    ● 测试类

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {@Autowiredprivate ApplicationContext applicationContext; //IOC容器对象//bean的作用域@Testpublic void testScope(){for (int i = 0; i < 10; i++) {DeptController deptController = applicationContext.getBean(DeptController.class);System.out.println(deptController);}}
}

重启SpringBoot服务,运行测试方法,查看控制台打印的日志:

注意事项:

    ● IOC容器中的bean默认使用的作用域:singleton(单例)

    ● 默认singleton的bean,在容器启动时被创建,可以使用@Lazy注解来延迟初始化(延迟到第一次使用时)

2).测试二

修改控制器DeptController代码:

@Scope("prototype") //bean作用域为非单例
@Lazy //延迟加载
@RestController
@RequestMapping("/depts")
public class DeptController {@Autowiredprivate DeptService deptService;public DeptController(){System.out.println("DeptController constructor ....");}//省略其他代码...
}

重启SpringBoot服务,再次执行测试方法,查看控制台打印的日志:

注意事项:

    ● prototype的bean,每一次使用该bean的时候都会创建一个新的实例

    ● 实际开发当中,绝大部分的Bean都是单例的,也就是说绝大部分Bean不需要配置scope属性

第三方Bean

学习完bean的获取、bean的作用域之后,接下来我们再来学习第三方bean的配置。

之前我们所配置的bean,像controller、service、dao三层体系下编写的类,这些类都是我们在项目当中自己定义的类(自定义类)。当我们要声明这些bean,也非常简单,我们只需在类上加上@Component以及它的这三个衍生注解(@Controller、@Service、@Reposity),就可以来生命这个bean对象了。

但是在我们项目开发当中,还有一种情况就是这个类它不是我们自己编写的,而是我么引入的第三方依赖当中提供的。

在pom.xml文件中,引入dom4j:

<!--Dom4j-->
<dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version>
</dependency>

dom4j就是第三方组织提供的。dom4j中的SAXReader类就是第三方编写的。

当我们需要使用到SAXReader对象时,直接进行依赖注入是不是就可以了呢?

● 按照我们之前的做法,需要在SAXReader类上添加一个注解@Component(将当前类交给IOC容器管理)

结论:第三方提供的类是只读的。无法在第三方类上添加@Component注解或衍生注解。

那么我们应该怎样使用并定义第三方的bean呢?

    ● 如果要管理的bean对象来自于第三方(不是自定义的),是无法用@Component及衍生注解声明bean的,就需要用到@Bean注解。

解决方案1:在启动类上添加@Bean标识的方法

@SpringBootApplication
public class SpringbootWebConfig2Application {public static void main(String[] args) {SpringApplication.run(SpringbootWebConfig2Application.class, args);}//声明第三方bean@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器beanpublic SAXReader saxReader(){return new SAXReader();}
}

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<emp><name>Tom</name><age>18</age>
</emp>

测试类:

@SpringBootTest
class SpringbootWebConfig2ApplicationTests {@Autowiredprivate SAXReader saxReader;//第三方bean的管理@Testpublic void testThirdBean() throws Exception {Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));Element rootElement = document.getRootElement();String name = rootElement.element("name").getText();String age = rootElement.element("age").getText();System.out.println(name + " : " + age);}//省略其他代码...
}

重启SpringBoot服务,执行测试方法后,控制台输出日志:

Tom : 18

说明:以上在启动类中声明第三方Bean的作法,不建议使用(项目中要保证启动类的纯粹性)

解决方案2:在配置类中定义@Bean标识的方法

    ● 如果需要定义第三方Bean时, 通常会单独定义一个配置类

@Configuration //配置类  (在配置类当中对第三方bean进行集中的配置管理)
public class CommonConfig {//声明第三方bean@Bean //将当前方法的返回值对象交给IOC容器管理, 成为IOC容器bean//通过@Bean注解的name/value属性指定bean名称, 如果未指定, 默认是方法名public SAXReader reader(DeptService deptService){System.out.println(deptService);return new SAXReader();}}

注释掉SpringBoot启动类中创建第三方bean对象的代码,重启服务,执行测试方法,查看控制台日志:

Tom : 18

在方法上加上一个@Bean注解,Spring 容器在启动的时候,它会自动的调用这个方法,并将方法的返回值声明为Spring容器当中的Bean对象。

注意事项:

    ● 通过@Bean注解的name或value属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。

    ● 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。

关于bean大家只需要保持一个原则:

    ● 如果是项目当中我们自己定义的类,想将这些类交给IOC容器管理,我们直接使用@Component以及它的衍生注解来声明皆可以。

    ● 如果这个类它不是我们自己定义的,而是引入的第三方依赖当中提供的类,而且我们还想将这个类交给IOC容器管理。此时我们就需要在配置类中定义一个方法,在方法上加上一个@Bean注解,通过这种方式来声明第三方的bean对象。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 方法简介

package com.ly.lianxi4;/*** 狮子类** 体重* 年龄* 描述** 跑** 吃*/ public class Lion {// 属性private double weight;//体重private int age;//年龄private String desc;//描述/*** 跑*/public void run(){System.out.println("lion 正在奔跑");System.out.pri…

Java类加载器 和 双亲委派【详解】

一.类加载器&#xff1a; 由JDK提供的&#xff0c;用于加载一些资源文件到JVM内存里的一项技术。主要是加载class文件到内存&#xff0c;也可以加载一些资源文件。 2.JDK提供了三个类加载器&#xff1a; BootstrapClassLoader&#xff1a;引导类加载器&#xff0c; 是c语言编写…

Springboot项目实战

文章目录 SpringBootVue后台管理系统所需软件下载、安装、版本查询Vue搭建一个简单的Vue项目 *Spring项目项目架构 SpringBootVue后台管理系统 学习视频&#xff1a; https://www.bilibili.com/video/BV1U44y1W77D/?spm_id_from333.337.search-card.all.click&vd_sourcec…

vscode设置打开浏览器

安装这个插件 Open Browser Preview

ORACLE 基础

一.ORACLE简介 1.1什么是oracle ORACLE 数据库系统是美国 ORACLE 公司&#xff08;甲骨文&#xff09;提供的以分布式数据库为核心的一组软件产品&#xff0c;是目前最流行的客户/服务器(CLIENT/SERVER)或 B/S 体系结构的数据库之一。 ORACLE 通常应用于大型系统的数据库产品。…

最佳实践:Websocket 长连接状态如何保持

WebSocket 是一种支持通过单个 TCP 连接进行全双工通信的协议&#xff0c;相较于传统的 HTTP 协议&#xff0c;它更适合需要实时交互的应用场景。此协议在现代 Web 应用中扮演着至关重要的角色&#xff0c;尤其是在需要实时更新和通信的场合下维持持久连接。本文将探讨 WebSock…

VSCODE SFTP本地上传文件报错

之前都是好好的&#xff0c;突然今天上传文件报错。误打误撞发现解决方式 [03-01 09:29:08] [error] Error: Failureat 101 (c:\Users\d1312117\.vscode\extensions\natizyskunk.sftp-1.16.3\node_modules\ssh2\lib\protocol\SFTP.js:2854:19)at SFTP.push (c:\Users\d1312117\…

瑞_Redis_Redis的Java客户端

文章目录 1 Redis的Java客户端1.1 Jedis快速入门1.1.1 入门案例1.1.1.1 项目构建1.1.1.2 引入依赖1.1.1.3 建立连接1.1.1.4 释放资源1.1.1.5 测试1.1.1.6 完整测试类代码 1.1.2 Jedis连接池1.1.2.1 连接池工具类1.1.2.2 改造原始代码 1.2 SpringDataRedis1.2.1 RedisTemplate1.…

【快速选择】解决TopK问题

目录 一、什么是TopK问题 二、优先级队列 优先级队列介绍 代码实现 三、使用优先级队列解决TopK问题 四、快速选择算法解决TopK问题 快速选择 图解快速选择 代码解决前k小个元素 五、优先级队列与快速选则算法比较 优先级队列 快速选择 一、什么是TopK问题 TopK问题…

精酿啤酒:创新原料的研发与市场前景

随着消费者口味和需求的不断变化&#xff0c;创新已成为啤酒行业持续发展的重要驱动力。Fendi Club啤酒在创新原料的研发方面走在行业前列&#xff0c;积极探索新型原料和风味组合&#xff0c;以满足市场对多样化、个性化产品的需求。 Fendi Club啤酒注重研发新型原料和添加剂。…

节省时间,创造价值:人工智能在工作中的实际应用

AI时代的工作流程&#xff1a;智能化操作&#xff0c;创新不止步 在当前的人工智能技术领域&#xff0c;无论是国内研发还是国际上的先进大型模型&#xff0c;本质上均采用了GPT&#xff0c;即生成式预训练Transformer模型。该模型的核心能力在于基于已学习的知识库生成回答。其…

数据分析-Pandas数据探查初步圆饼图

数据分析-Pandas数据探查初步圆饼图 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&am…