【Java EE】 IoC详解(Bean的存储)

文章目录

  • 🎍@Controller(控制器存储)
    • 🌸如何从Spring容器中获取对象(ApplicationContext)
    • 🌸获取bean对象的其他方式(BeanFactory)
    • 🌸Bean 命名约定
    • 🌸Bean面试题
  • 🍀@Service、@Repository、@Component、@Configuration.
  • 🌳为什么要这么多类注解?
  • 🌲类注解之间的关系
  • 🌴方法注解 @Bean
    • 🌸方法注解要配合类注解使用
    • 🌸定义多个对象
    • 🌸重命名 Bean
    • 🌸扫描路径

既然 Spring 是⼀个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:

Spring 容器 管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理, 由
Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出
对象

前⾯我们提到IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对
象。
也就是bean的存储.

把某个对象交给IOC容器管理,Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解.

共有两类注解类型可以实现bean的存储:

  1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration.
  2. ⽅法注解:@Bean.、

🎍@Controller(控制器存储)

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

@Controller // 将对象存储到 Spring 中
public class UserController {public void sayHi(){System.out.println("hi,UserController...");}
}

如何观察这个对象已经存在Spring容器当中了呢?

🌸如何从Spring容器中获取对象(ApplicationContext)

接下来我们学习如何从Spring容器中获取对象

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

ApplicationContext 翻译过来就是: Spring 上下⽂
因为对象都交给 Spring 管理了,所以获取对象要从 Spring 中获取,那么就得先得到 Spring 的上下

关于上下⽂的概念
上学时, 阅读理解经常会这样问: 根据上下⽂, 说⼀下你对XX的理解
在计算机领域, 上下⽂这个概念, 咱们最早是在学习线程时了解到过, ⽐如我们应⽤进⾏线程切换的时
候,切换前都会把线程的状态信息暂时储存起来,这⾥的上下⽂就包括了当前线程的信息,等下次该
线程⼜得到CPU时间的时候, 从上下⽂中拿到线程上次运⾏的信息
这个上下⽂, 就是指当前的运⾏环境, 也可以看作是⼀个容器, 容器⾥存了很多内容, 这些内容是当前
运⾏的环境

观察运⾏结果, 发现成功从Spring中获取到Controller对象, 并执⾏Controller的sayHi⽅法
在这里插入图片描述
如果把@Controller删掉, 再观察运⾏结果
在这里插入图片描述
报错信息显⽰: 找不到类型是: com.example.demo.controller.UserController的bean

🌸获取bean对象的其他方式(BeanFactory)

上述代码是根据类型来查找对象, 如果Spring容器中, 同⼀个类型存在多个bean的话, 怎么来获取呢?

ApplicationContext 也提供了其他获取bean的方式, ApplicationContext 获取bean对象的功能, 是父类BeanFactory提供的功能.

public interface BeanFactory {//以上省略...// 1. 根据bean名称获取beanObject getBean(String var1) throws BeansException;// 2. 根据bean名称和类型获取bean<T> T getBean(String var1, Class<T> var2) throws BeansException;// 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的beanObject 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指定名称(BeanId), 如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称.

命名约定使⽤Java标准约定作为实例字段名. 也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写.

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

也有⼀些特殊情况, 当有多个字符并且第⼀个和第⼆个字符都是⼤写时, 将保留原始的⼤⼩写

⽐如
类名: UController, Bean的名称为: UController
类名: AManager, Bean的名称为: AManager

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

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

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

🌸Bean面试题

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

ApplicationContext VS BeanFactory(常⻅⾯试题)

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

🍀@Service、@Repository、@Component、@Configuration.

使用与Controller一致,这里不做演示

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

这个也是和咱们前⾯讲的应⽤分层是呼应的. 让程序员看到类注解之后,就能直接了解当前类的⽤途.

• @Controller:控制层, 接收请求, 对请求进⾏处理, 并进⾏响应.
• @Servie:业务逻辑层, 处理具体的业务逻辑.
• @Repository:数据访问层,也称为持久层. 负责数据访问操作
• @Configuration:配置层. 处理项⽬中的⼀些配置信息.

程序的应⽤分层,调⽤流程如下:
在这里插入图片描述

🌲类注解之间的关系

查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发
现:
在这里插入图片描述
其实这些注解⾥⾯都有⼀个注解 @Component ,说明它们本⾝就是属于 @Component 的"⼦类".

@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller , @Service ,
@Repository 等. 这些注解被称为 @Component 的衍⽣注解.

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

🌴方法注解 @Bean

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

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

这种场景, 我们就需要使⽤⽅法注解 @Bean
我们先来看看⽅法注解如何使⽤:

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

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

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

以上程序的执⾏结果如下:

在这里插入图片描述

🌸方法注解要配合类注解使用

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

🌸定义多个对象

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

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

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

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

@Bean 注解的bean, bean的名称就是它的⽅法名

🌸重命名 Bean

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

@Bean(name = {"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;
}

🌸扫描路径

bean想要⽣效,还需要被Spring扫描)

使⽤五⼤注解声明的bean,要想⽣效, 还需要配置扫描路径, 让Spring扫描到这些注解
也就是通过 @ComponentScan 来配置扫描路径

@ComponentScan({"com.example.demo"})

那为什么前⾯没有配置 @ComponentScan注解也可以呢?

@ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解
@SpringBootApplication 中了

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

推荐做法:

把启动类放在我们希望扫描的包的路径下, 这样我们定义的bean就都可以被扫描到

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

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

相关文章

判断密码c++

题目描述 某平台对新用户注册密码做如下限制: ①长度是8到16位&#xff0c;如果不符会给出提示“password should be 8 to 16 long" ②逐一判断密码字符&#xff0c;如果是纯数字就给出提示“password should not be entirely numeric”&#xff0c;如果密码符合以上要…

支持向量机模型

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个支持向量机模型程序,最后打印5个条件分别的影响力。 示例一 为了计算每个条件对一件事情发生的影响力&#xff0c…

Linux nfs挂载失败处理

mount.nfs: access denied by server while mounting 192.168.0.1:/home/test 其中一种可能原因是文件目录没有nfs权限&#xff0c;可以编辑/etc/exports文件添加权限后重试&#xff1a; /home/xxx *(insecure,rw,sync,no_root_squash,no_all_squash,no_subtree_check) 参考资…

6-测试内存告警

在 CentOS 8 中&#xff0c;如果你无法直接找到 epel-release 包或是遇到其他仓库配置问题&#xff0c;你可能需要使用其他方式添加EPEL仓库。由于 CentOS 8 已经达到了其生命周期的结束&#xff0c;官方仓库和EPEL仓库的管理可能会有所不同。这里有一种方法可以手动添加EPEL仓…

【笔记】EF文件中定义的SPN显示协议规则

规则配置 SPN_bit 和PLMN_bit对应EF_SPN的bit1和bit2 如EF_SPN: bit10&#xff1b;bit2 0&#xff0c; 则HOME显示SPN&#xff0c;ROAMING显示SPN-PLMN SPN_bit 2, PLMN_bit 0 显示SPN&#xff0c;不显示PLMN。 客制化通过CarrierConfig “spn_display_condition_override_…

【Spring进阶系列丨第九篇】基于XML的面向切面编程(AOP)详解

文章目录 一、基于XML的AOP1.1、打印日志案例1.1.1、beans.xml中添加aop的约束1.1.2、定义Bean 1.2、定义记录日志的类【切面】1.3、导入AOP的依赖1.4、主配置文件中配置AOP1.5、测试1.6、切入点表达式1.6.1、访问修饰符可以省略1.6.2、返回值可以使用通配符&#xff0c;表示任…

静电场中的导体与介质

静电场可能分布于填充了各种媒质的区域。虽然媒质宏观上保持电中性&#xff0c;但其内部的各种微观带电系统不可避免地会与静电场相互作用。 一般而言&#xff0c;媒质可分为三类&#xff1a;导体、介质(绝缘体)和半导体。在静电场中半导体特性与导体类似&#xff0c;因此仅就…

10. TypeScript面向对象的类(Class)

在 TypeScript 中&#xff0c;类是面向对象编程的基础&#xff0c;它们提供了一种方式来封装数据和行为。本文将详细介绍 TypeScript 中类的概念和用法。TypeScript扩展了ES的功能&#xff0c;跟JAVA关于面向对象的概念和写法很类似。 1. 类的基本概念 在 TypeScript 中&#…

964: 数细胞

样例&#xff1a; 解法&#xff1a; 1.遍历矩阵 2.判断矩阵[i][j]&#xff0c;若是未标记细胞则遍历相邻所有未标记细胞并标记&#xff0c;且计数 实现&#xff1a;遍历相邻所有未标记细胞 以DFS实现&#xff1a; function dfs(当前状态) {if (终止条件) {}vis[标记当前状…

.NET 设计模式—迭代器模式(Iterator Pattern)

简介 迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许我们通过提供一种方法来访问聚合对象中的元素&#xff0c;而不需要暴露聚合对象的内部实现。在迭代器模式中&#xff0c;我们通过创建一个迭代器对象来遍历聚合对象中的元素&a…

PyQt5结合Yolo框架打包python为exe文件完整流程

一、准备 1.安装 pyinstaller pip install pyinstaller 更新&#xff08;初次安装忽略&#xff09; pip install --upgrade pyinstaller 2.安装 auto-py-to-exe 安装 pip install auto-py-to-exe 打开工具 auto-py-to-exe.exe auto-py-to-exe 可视化转换工具&#xff1…

JAVAEE之Spring AOP

1. AOP概述 AOP是Spring框架的第⼆⼤核⼼(第⼀⼤核⼼是IoC) 1.1 什么是AOP&#xff1f; • Aspect Oriented Programming&#xff08;⾯向切⾯编程&#xff09; 什么是⾯向切⾯编程呢? 切⾯就是指某⼀类特定问题, 所以AOP也可以理解为⾯向特定⽅法编程. 什么是⾯向特定⽅法编…

jenkins+docker集成harbor实现可持续集成

目录 一、前言 二、Harbor介绍 2.1 什么是Harbor 2.1.1 Harbor架构图 2.2 Harbor 特征 2.3 Harbor 核心组件 2.4 Harbor使用场景 三、Harbor部署 3.1 安装docker compose 3.1.1 安装方式一 3.2 基于python3 pip安装docker compose 3.2.1 安装python3 3.2.2 安装pyt…

Linux makefile文件

makefile格式: make makefile/Makefile&#xff08;大小写都可以&#xff09;&#xff1a; make是一个命令&#xff0c;makefile是一个目录文件 现在你写了一个test.c文件&#xff0c;要编译运行。 输入命令&#xff1a;vim makefile 在makefile文件内输入&#xff1a; myte…

Vue项目Nginx配置自定义路径别名

第一步&#xff1a;在vite.config.js中配置base的路径 在打包项目之前需要在vite.config.js中配置base的路径&#xff0c;路径名为服务器自定义的路由别名&#xff1a; 比如: import { fileURLToPath, URL } from "node:url";import { defineConfig } from "v…

什么是隐马模型

目录 什么是隐马模型 举例简单理解 什么是隐马模型 隐马尔可夫模型(Hidden Markov Model,HMM)是一种统计模型,用于描述一个含有隐含未知参数的马尔可夫过程。其难点在于从可观察的参数中确定该过程的隐含参数,并利用这些参数来作进一步的分析,例如模式识别。 隐马尔可…

互联网轻量级框架整合之设计模式

反射技术 Java的反射技术能够通过配置类的全限定名、方法和参数完成对象的初始化&#xff0c;甚至反射某些方法&#xff0c;大大的增强了Java的可配置型&#xff0c;这也是Spring IoC的底层原理&#xff0c;Java的反射技术覆盖面很广&#xff0c;包括对象构建、反射方法、注解、…

JavaScript 中什么应用场景下必须用 map 而不是对象来实现功能

前言 很多情况下&#xff0c;能用 map 实现的功能用对象也可以实现&#xff0c;都是基于键值对&#xff0c;但是在一些情况下&#xff0c;必须要使用 map 才可以。 必须用 map 而不是 object 的情况 键的类型不限&#xff1a;普通对象的键总是被转换为字符串或者 Symbols&a…

C#简单工厂模式的实现

using System.Diagnostics.Metrics; using System.Runtime.InteropServices; using static 手写工厂模式.Program;namespace 手写工厂模式 {internal class Program{public interface eats {void eat();}//定义了一个接口public class rice : eats{public void eat() {Console.…

Qt快速入门(Opencv小案例之人脸识别)

Qt快速入门&#xff08;Opencv小案例之人脸识别&#xff09; 编译出错记录 背景 因为主要使用qt&#xff0c;并且官网下载的win版本的编译好的opencv默认是vc的&#xff0c;所以我们需要自己下载opencv的源码使用mingw自行编译&#xff0c;我直接使用的vscode。 报错 报错…