SpringBoot Bean管理

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

本篇主要介绍IOC容器中Bean的使用细节:

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

  • bean的作用域

  • 管理第三方的bean对象(重点)

1、如何从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容器对象 注入进来就可以了,java中万物皆对象。

  • step1: 创建 bean 容器

Mapper接口:‍

@Mapper
public interface UserMapper {//查询所有门派@Select("select * from sects")List<Sect> selectAll();
}

业务实现类:


@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper  userMapper ;@Overridepublic List<Sect> getAllSects() {List<Sect> sects =  sectsMapper.selectAll();return sects;}
}

控制器:

@RestController
@Slf4j
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/get/all")public Result getAll() {List<Sect> sects = sectsService.getAllSects();return Result.success(sects);}
}
  • step2: 获取 Bean 容器

测试类:

import org.springframework.context.ApplicationContext;@SpringBootTest
class TianlongManagementApplicationTests {@Autowiredprivate ApplicationContext applicationContext;@Testpublic void testGetBean() {//根据bean的名称获取SectsController bean1 = (UserController) applicationContext.getBean("userController");System.out.println(bean1);//根据bean的类型获取SectsController bean2 = applicationContext.getBean(UserController.class);System.out.println(bean2);//根据bean的名称及类型获取SectsController bean3 = applicationContext.getBean("userController", UserController.class);System.out.println(bean3);}
}

输出的bean对象地址值一样,说明在IOC容器中SectsController这个bean是 单例的。那能否将bean对象设置为非单例?

说到这,笔者之前想过一个问题,为什么在SpringBoot项目中,都是Controller类、ServiceImpl实现类和Mapper接口需要添加@Componet及其衍生注解,而我们写的POJO实现类却不用添加?POJO也是一个一个的类,在项目里也需要创建对象,为什么这些POJO对象不需要添加到IOC容器来管理呢?(如下图Sects这个实现类并没有添加@Component注解)

谈一下我的拙见,首先需要知道为啥Spring框架IOC控制反转很重要,因为通过这个可以实现Controller、Service、DAO三层的解耦,大白话就是当Controller需要用ServiceImpl对象,就不用new的方式创建,而是直接通过DI依赖注入从IOC容器中拿对象。

明白了上面这一点,我们想想为啥POJO实现类和一些工具类不用加入IOC容器?

  • 原因一:普通的POJO类、工具类通常是不涉及业务逻辑的辅助功能,不涉及复杂的依赖关系和配置,因此不需要被IOC容器管理;

  • 原因二:Controller、Service和Mapper这三层主要是处理业务,而普通的POJO类一般用于封装数据,封装数据意味着每次封装的数据可能不同,也就是每次对象不同,交给IOC容器管理反而更复杂。

2、bean的作用域

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

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

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

可以借助Spring中的@Scope注解来配置作用域:
在这里插入图片描述

再次运行后控制台日志显示 UserController这个bean就生成了多份,不过实际开发中,绝大多数bean都是单例的,也就是不用配置scope属性。
在这里插入图片描述

除此之外,Spring还提供了一个注解:@Lazy,用于延迟加载,意思是当第一次使用bean对象时,才会创建bean对象并交给ioc容器管理。

3、管理第三方的bean对象(重点)

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

Spring框架又提供了一个注解 @Bean,可以用来管理来第三方(不是自定义的)容器。

方法一: 在引导类/启动类上添加@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);}
}

运行测试方法,程序可以正常运行并解析xml数据,说明SAXReader类的对象被成功注入进来了。

Tom : 18

方法二: 在配置类中定义@Bean标识的方法 (推荐)

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

  • 创建配置类:CommonConfig
package com.nvyao.conf;import com.nvyao.pojo.Dept;
import com.nvyao.service.DeptService;
import org.dom4j.io.SAXReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.List;@Configuration  //配置类
public class CommonConfig {//声明第三方Bean,一般情况下专门定一个配置类来声名第三方bean对象//加了这个注解,spring框架会自动调用这个方法,并且将方法返回值交给IOC容器管理,成为IOC容器的bean对象//通过@Bean注解的name或value属性可以声明Bean的名称,如果不指定,默认bean的名称就是方法名@Bean//("reader")public SAXReader saxReader() {return new SAXReader();}
}

去除之前启动类的@Bean方法,重启依然有效。

假如第三方Bean在使用过程还需要使用其他Bean,也就是还需要依赖其他对象,可以直接通过在@Bean注解的这个方法添加需要依赖的对象的形参来解决,如下:


@Configuration  //配置类
public class CommonConfig {@Beanpublic SAXReader saxReader(DeptService deptService) {System.out.println(deptService);List<Dept> deptList = deptService.listDept();System.out.println(deptList);return new SAXReader();}
}


可以断点调试看到,形参的对象已经注入进来了,真挺好!
在这里插入图片描述

总结一下:

1)SpringBoot的启动类也是一个配置类,理论上声明第三方Bean的方法可以放在启动类,但一般是单独定义一个配置类

2)加了@Bean注解,Spring框架会自动调用@Bean注解的方法,并且将方法返回值交给IOC容器管理,成为IOC容器的bean对象

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

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

4、bean 三种注入方式

属性注入

属性注入目前最 常用的注入方式,使用@Autowired注解实现。
在类的属性上添加@Autowired注解,Spring会自动注入对应的Bean对象。
需要注意的是,属性注入可能会导致Bean状态的不完整性,因为它们是在构造函数后才被注入的,因此可能会出现空指针异常等问题。

适用于 类容器

  • Bean 容器
package com.xuzhongkj.components;import com.xuzhongkj.po.Users;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class WttFunBeanTest {@Bean(name = "aaa")public String aaa() {return "aaaaaaaaaaa";}@Bean(name = "bbb")public Users bb22b() {return new Users(1, "wtt");}public String Hi() {return "Hi";}
}
  • 属性注入
package com.xuzhongkj.controller;import com.xuzhongkj.components.WttFunBeanTest;
import com.xuzhongkj.po.Users;
import com.xuzhongkj.service.NewsService;
import com.xuzhongkj.service.impl.NewsServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class WttTest {@Autowiredprivate WttFunBeanTest wttFunBeanTest;@GetMapping("/wtt1")public int a1() {System.out.println(wttFunBeanTest.Hi());return 0;}
}

构造函数注入

构造函数注入是一种类型安全、清晰明了的方式,可以保证Bean的完整性。
在类中定义一个构造函数,并在其参数列表中声明需要注入的Bean对象。Spring会在初始化Bean的时候,自动将对应的Bean对象传入。

适用于 方法容器

package com.xuzhongkj.controller;import com.xuzhongkj.components.WttFunBeanTest;
import com.xuzhongkj.po.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class WttTest {private Users users;private String aaa2;// 注意: 这里 一定要使用 要注入的 bean 名称 为 形参的参数名public WttTest(Users bbb,String aaa) {this.users = bbb;this.aaa2 = aaa;}@GetMapping("/wtt1")public int a1() {System.out.println(users);System.out.println(aaa2);return 0;}
}
  • 上述代码的 简化版,也叫 @AllArgsConstructor 注解版
package com.xuzhongkj.controller;import com.xuzhongkj.components.WttFunBeanTest;
import com.xuzhongkj.po.Users;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
@AllArgsConstructor
public class WttTest {// 注意: 这里 一定要使用 要注入的 bean 名称 为 属性 的参数名private Users bbb;private String aaa;@GetMapping("/wtt1")public int a1() {System.out.println(bbb);System.out.println(aaa);return 0;}
}

方法注入

方法注入是一种灵活的注入方式,在类中定义一个方法,并在其参数列表中声明需要注入的Bean对象。
使用@Autowired注解标记该方法,Spring会在初始化Bean的时候,自动调用该方法并传入对应的Bean对象。

适用于 方法、类 容器 的 再封装 容器

  • 在 service 层 使用 方法注入:
package com.xuzhongkj.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuzhongkj.dao.NewsMapper;
import com.xuzhongkj.po.News;
import com.xuzhongkj.po.Users;
import com.xuzhongkj.service.NewsService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
@Data
public class NewsServiceImpl extends ServiceImpl<NewsMapper, News> implements NewsService {private Users bbb;private String aaa;// 注意: 这里 一定要使用 要注入的 bean 名称 为 形参的参数名@Autowiredpublic void aaa(Users bbb, String aaa) {this.bbb = bbb;this.aaa = aaa;}
}
  • 在 controller层,验证 是否注入成功
package com.xuzhongkj.controller;import com.xuzhongkj.components.WttFunBeanTest;
import com.xuzhongkj.po.Users;
import com.xuzhongkj.service.NewsService;
import com.xuzhongkj.service.impl.NewsServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class WttTest {@Autowiredprivate NewsServiceImpl newsServiceImpl;@GetMapping("/wtt1")public int a1() {System.out.println(newsServiceImpl.getAaa());System.out.println(newsServiceImpl.getBbb());return 0;}
}

好文分享, 一起加油!

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

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

相关文章

c++初阶知识——内存管理与c语言内存管理对比

目录 前言&#xff1a; 1.c&#xff0b;&#xff0b;内存管理方式 1.1 new和delete操作自定义类型 2.operator new与operator delete函数 2.1 operator new与operator delete函数 3.new和delete的实现原理 3.1 内置类型 3.2 自定义类型 new的原理 delete的原理 new…

gite+picgo+typora打造个人免费笔记软件

文章目录 1️⃣个人笔记软件2️⃣ 配置教程2.1 使用软件2.2 node 环境配置2.3 软件安装2.4 gite仓库设置2.5 配置picgo2.6 测试检验2.7 github教程 &#x1f3a1; 完结撒花 1️⃣个人笔记软件 最近换了环境&#xff0c;没有之前的生产环境舒适&#xff0c;写笔记也没有劲头&…

图——图的遍历(DFS与BFS算法详解)

前面的文章中我们学习了图的基本概念和存储结构&#xff0c;大家可以通过下面的链接学习&#xff1a; 图的定义和基本术语 图的类型定义和存储结构 这篇文章就来学习一下图的重要章节——图的遍历。 目录 一&#xff0c;图的遍历定义&#xff1a; 二&#xff0c;深度优先…

【代码随想录】【算法训练营】【第58天 2】 [卡码102]沉没孤岛

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 卡码网。 day 58&#xff0c;周四&#xff0c;ding~ 题目详情 [卡码102] 沉没孤岛 题目描述 卡码102 沉没孤岛 解题思路 前提&#xff1a;修改孤岛的值 思路&#xff1a;DFS or BFS&#xff0c;使用visite…

探寻大模型回答9.9和9.11犯错的根本原因

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

每日OJ_牛客_排序子序列

目录 牛客_排序子序列 题解及代码 牛客_排序子序列 排序子序列_牛客笔试题_牛客网 题解及代码 本题依次比较整个数组 v[i1]>v[i] &#xff0c;则进入非递减序列判断&#xff0c;直到遍历到下一个值不大于等于为止count&#xff0c;然后进行下一位置的判断v[i1]<v[i]…

算法之判断对称二叉树

94. 二叉树的中序遍历101. 对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;fa…

特斯拉新一代人形机器人Optimus二代:听说行走速度能够提升30%?

在当今这个快速变化的时代&#xff0c;人工智能已成为我们探索未来的一大驱动力。特斯拉以其在电动汽车领域的创新而闻名&#xff0c;而Optimus智能机器人的发布&#xff0c;更是将这种创新精神带到了一个新的领域 1. 智能机器人&#xff1a;Optimus的起源 2021年8月&#xff…

虚拟摄像头怎么用?安卓虚拟相机替换本地摄像头教程(内含3个虚拟摄像头)

虚拟摄像头是一个软件摄像机&#xff0c;电脑没有物理摄像头时可以借助虚拟摄像头进行视频通话。当我们电脑没有自带的摄像头时&#xff0c;必须要外接摄像头才可以进行网络会议、视频直播。普通的摄像头像素不高&#xff0c;直接将手机充当电脑摄像头效果更佳哦。 虚拟摄像头我…

自动驾驶算法——Vehicle Control(一)

“ 在过去的几年里&#xff0c;无人驾驶汽车已成为人工智能领域的主要主力之一。鉴于交通死亡人数众多、老年人和残疾人的行动能力有限以及交通拥堵和拥堵问题日益严重&#xff0c;自动驾驶汽车有望解决我们社会最重要的问题之一&#xff1a;移动的未来。然而&#xff0c;让汽车…

数学建模(1)

论文&#xff1a;做流程图 论文查重不能高于30% 论文 分模块备战 摘要不能超过一页的四分之三 数学建模的六个步骤: 【写作】---学术语言 团队练题

科普文:TaobaoVM信息收集

网上关于TaobaoVM的信息很少&#xff0c;只有一个简介&#xff0c;就没有其他信息。毕竟这是别人企业自己的jvm&#xff0c;不可能公开。 Taobao VM 由AliJVM团队发布。阿里&#xff0c;国内使用Java最强大的公司&#xff0c;覆盖云计算、金融、物流、电商等众多领域&#xf…

zabbix“专家坐诊”第246期问答

问题一 Q&#xff1a;有哪位大哥知道这是啥情况&#xff0c;6.4主动检查接口显示未知&#xff1f; A&#xff1a;看看agent配置文件的主采集有没有填写正确IP。 Q&#xff1a;我刚刚客户端重新授权&#xff0c;发现可以预警了&#xff0c;但是还是灰色的&#xff0c;我尝试输…

spring事件发布器ApplicationEventPublisher的使用

1、前言 spring中有一个事件发布器,使用了观察者模式,当有事件发布的时候,事件监听者会立刻收到发布的事件。今天我们来介绍下这个事件发布器怎么使用。 2、简单使用 2.1、创建事件实体类 事件实体类需要继承ApplicationEvent。我们模拟老师发布事件的诉求。 public class T…

【C++】C++ 学生信息管理系统(源码+面向对象)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

一文-深入了解Ansible常见模块、安装和部署

1 Ansible 介绍 Ansible是一个配置管理系统configuration management system, python 语言是运维人员必须会的语言, ansible 是一个基于python 开发的&#xff08;集合了众多运维工具 puppet、cfengine、chef、func、fabric的优点&#xff09;自动化运维工具, 其功能实现基于ss…

鸿蒙仓颉语言【类型class】

类与结构&#xff08;class & struct&#xff09; 面向对象的编程语言&#xff0c;必不可少的基础元素&#xff0c;类或者叫类型&#xff0c;在仓颉中类可以抽象(abstract)、继承&#xff08;<:&#xff09;&#xff0c;公开&#xff08;Public&#xff09;或者私有&am…

算法第十天:leetcode203.移除链表元素

一、203.移除链表元素题目描述 203.移除链表元素的链接如下所示&#xff0c;您可复制下面链接网址进入力扣学习&#xff0c;看题解之前一定要先做一遍哦&#xff01; https://leetcode.cn/problems/remove-linked-list-elements/description/https://leetcode.cn/problems/rem…

26_EfficientNet网络详解

1.1简介 EfficientNet是由Google Research团队开发的一种高效卷积神经网络&#xff08;CNN&#xff09;模型&#xff0c;首次在2019年的论文《EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks》中提出。此模型设计的核心在于平衡网络的深度、宽度以…

如何规划数据科学和机器学习领域的下一步职业发展

。 欢迎来到云闪世界。数据科学和机器学习专业人士面临着来自多个方面的不确定性 欢迎来到云闪世界。全球经济、人工智能工具及其对工作保障的影响&#xff0c;以及不断变化的技术堆栈&#xff0c;仅举几例。如今&#xff0c;谈论职业生涯是否能够抵御经济衰退…