spring IOC DI -- IOC详解

ops/2024/9/25 23:12:29/

在这里插入图片描述

T04BF

👋专栏: 算法|JAVA|MySQL|C语言

🫵 今天你敲代码了吗

文章目录

      • 4.2 Ioc 详解
        • 4.2.1 Bean的存储
          • @Controller(控制器存储)
          • @Service (服务存储)
          • @Repository(仓库存储)
          • @Component(组件存储)
          • @Configuration(配置存储)
        • 4.2.2 为什么需要这么多类注解?
        • 4.2.3方法注解@Bean
          • 定义多个对象
          • 重命名Bean
        • 4.3 Sping扫描路径

4.2 Ioc 详解

Ioc控制反转,就是将对象的控制权交给Spring的Ioc容器,由Ioc容器创建并管理对象,也就是Bean的存储

4.2.1 Bean的存储

共有两类注解可以实现:

  1. 类注解:@Controller @Service @Repository @Component @Configuration
  2. 方法注解: @Bean
@Controller(控制器存储)

使用@Controller存储bean

java">@Controller
public class UserController {public void sayHi() {System.out.println("Hi,UserController");}
}

从Spring容器中获取对象

java">@SpringBootApplication
public class Je20240721Application {public static void main(String[] args) {//获取Spring上下文ApplicationContext context = SpringApplication.run(Je20240721Application.class, args);//从Spring上下文中获取对象UserController controller = context.getBean(UserController.class);//使用对象controller.sayHi();}
}
/*
Spring上下文指的就是ApplicationContext,就是表示当前的运行环境,
也可以看成一个容器,容器里面存了很多内容,这些内容是当前运行的环境
*/

运行后查看日志:


但是如果我们将@Controller去掉:



报错信息显示:找不到类型org.jwcb.je20240721.iocExample.UserController的bean

获取bean的其他方式



这里我们是根据类型来查找对象,但是如果同一个类型存在多个Bean,怎么来获取呢??


还可以通过Bean的名称来获取Bean对象

那么Bean的名称是什么呢??

来自官方的定义是:

即Spring为bean生成了唯一的名字,命名约定使用java标准约定最为实例字段名,即以小写字母开头,使用小驼峰式
如UserController -> userController

但是存在特殊情况:当有多个字符并且第一个和第二个都是大写的时候,将保留原来的大小写,也就是bean名和类名一致

java">@SpringBootApplication
public class Je20240721Application {public static void main(String[] args) {//获取Spring上下文ApplicationContext context = SpringApplication.run(Je20240721Application.class, args);//从Spring上下文中获取对象UserController controller1 = (UserController) context.getBean("userController");UserController controller2 = context.getBean(UserController.class);UserController controller3 = context.getBean(UserController.class, "userController");System.out.println(controller1);System.out.println(controller2);System.out.println(controller3);}
}

查看日志:


地址一样,说明是同一个对象,即Spring框架默认使用的是单例模式来管理Bean

Spring框架默认使用单例模式来管理Bean的优势??

  1. 资源利用:减少了对象的创建和销毁,特别是在那些创建实例需要消耗大量资源的情况(如连接数据库等)
  2. 状态共享:应用于需要共享状态(如配置信息,缓存数据等)的场景
  3. 易于测试:可以轻松地替换或模拟Bean
  4. 简化编程模型:开发者不必再担心对象的创建和销毁,也不需要考虑对象之间的依赖关系
  5. 一致性:对于分布式系统来说,单例模式有利于保证应用行为的一致性

但是,值得注意的是,单例模式也有局限性.在多线程环境下,不正确使用单例模式可能会出现线程安全问题
ApplicationContext 提供的获取

bean的方式,是父类BeanFactory提供的功能,那么这两者的区别在哪?

  1. 从继承与功能方面来说,BeanFactory提供了基础的访问容器的能力,而ApplicationContext 除了继承BeanFactory的所有功能之外,还提供了国际化支持,资源访问支持,以及事件传播方面的支持

(1)国际化支持:使得应用可以个人根据不同的语言环境展示相应的内容.这主要通过 MessageSource
接口实现,该接口允许应用访问不同语言的消息属性文件(如 properties 文件)。通过配MessageSource
bean,并指定资源文件的基础名称(basename),ApplicationContext
可以在运行时根据当前的语言环境(Locale)来查找和返回相应的消息。国际化支持在开发多语言应用时非常有用,例如,一个网站可能需要根据用户的语言偏好显示不同的内容。通过配置和使用
ApplicationContext 的国际化支持,可以轻松地实现这一需求。

(2)资源访问支持:ApplicationContext 实现了 ResourceLoader
接口,提供了资源访问的能力。这意味着应用可以通过 ApplicationContext 访问各种资源,如文件、URL 等。通过使用
getResource() 方法,应用可以获取到资源的 Resource
表示,进而进行读取、写入等操作。资源访问支持使得应用能够灵活地访问和管理各种资源。例如,应用可能需要读取配置文件、模板文件或图片等资源,通过
ApplicationContext 提供的资源访问支持,可以方便地实现这些需求。

(3)事件传播支持:ApplicationContext
提供了事件传播的能力,允许应用中的组件在特定事件发生时进行通信和响应。这主要通过 ApplicationEvent 类和
ApplicationListener
接口实现。当一个组件发布一个事件时,所有注册了该事件监听的组件都会收到通知,并执行相应的处理逻辑。事件传播支持在需要实现松耦合组件间通信的应用中非常有用。例如,当一个业务操作完成后,可能需要通知其他组件进行相应的处理(如更新缓存、发送通知等)。通过事件传播机制,可以轻松地实现这一需求,而无需在组件间建立直接的依赖关系。

  1. 从性能方面来看,ApplicationContext 是一次性加载并初始化所有的Bean对象,而BeanFactory是需要那个才去加载,因此更加轻量

@Service (服务存储)
java">@Service
public class UserService {public void sayHello() {System.out.println("hello,UserService");}
}

@Repository(仓库存储)
java">@Repository
public class UserRepository {public void sayHello() {System.out.println("hello,Repository");}
}

@Component(组件存储)
java">@Component
public class UserComponent {public void sayHello() {System.out.println("hello,Component");}
}

@Configuration(配置存储)
java">@Configuration
public class UserConfiguration {public void sayHello() {System.out.println("Hello Configuration");}
}

4.2.2 为什么需要这么多类注解?

实际上是和应用分层是相呼应的,让开发者看到类注解之后,就能了解当前类的用途

  • @Controller:控制层
  • @Service:业务逻辑层
  • @Repository:数据访问层
  • @Configuration:配置层

类注解之间的关系:

可以看到,除了@Component是一个元注解,也就是可以注解其他类注解

4.2.3方法注解@Bean

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

  1. 使用外部包里面的类,没办法添加注解
  2. 一个类,需要多个对象.比如多个数据源

这种场景,就需要使用方法注解@Bean

java">public class BeanConfig {@Beanpublic UserInfo userInfo() {UserInfo userInfo = new UserInfo();userInfo.setUserName("zhangsan");userInfo.setPassword("123456");return userInfo;}
}

但是当我们尝试去获取对象的时候:

java">@SpringBootApplication
public class Je20240721Application {public static void main(String[] args) {//获取Spring上下文ApplicationContext context = SpringApplication.run(Je20240721Application.class, args);//从Spring上下文中获取对象UserInfo userInfo = context.getBean(UserInfo.class);System.out.println(userInfo);}
}


实际上,方法注解@Bean是需要搭配5大类注解才能将对象正常的存储到Spring容器里面,5大类注解标记的类使得Spring能够识别并且管理其中的@Bean方法

java">@Component
public class BeanConfig {@Beanpublic UserInfo userInfo() {UserInfo userInfo = new UserInfo();userInfo.setUserName("zhangsan");userInfo.setPassword("123456");return userInfo;}
}

再次执行:

定义多个对象

在多个数据源的创场景,类是同一个,但是配置不一样,指向不同的数据源,就需要多个对象

java">@Component
public class BeanConfig {@Beanpublic UserInfo userInfo1() {UserInfo u = new UserInfo();u.setUserName("zhangsan");u.setPassword("123456");return u;}@Beanpublic UserInfo userInfo2() {UserInfo u = new UserInfo();u.setUserName("lisi");u.setPassword("123456");return u;}
}

那么我们如果直接根据类型获取对象:

即期望只有一个匹配,结果发现了两个 userInfo1,userInfo2

从报错信息也可以看出来,实际上**@Bean**注解的bean的名称就是方法名本身

因此可以根据名称获取对象

java">@SpringBootApplication
public class Je20240721Application {public static void main(String[] args) {//获取Spring上下文ApplicationContext context = SpringApplication.run(Je20240721Application.class, args);//从Spring上下文中获取对象UserInfo userInfo1 = (UserInfo) context.getBean("userInfo1");System.out.println(userInfo1);UserInfo userInfo2 = (UserInfo) context.getBean("userInfo2");System.out.println(userInfo2);}
}


重命名Bean

可以通过设置name属性给Bean对象进行重命名

java">@Bean(name = {"u1","u2"})
public UserInfo userInfo1() {UserInfo u = new UserInfo();u.setUserName("zhangsan");u.setPassword("123456");return u;
}


4.3 Sping扫描路径

前面使用的注解声明的bean,一定会生效吗?
尝试改变一下:

再次运行代码:

实际上Spring默认的扫描路径是:

我们可以通过@ComponentScan来配置扫描路径

但是这种做法不推荐使用

感谢您的访问!!期待您的关注!!!

在这里插入图片描述

T04BF

🫵 今天记得敲代码

http://www.ppmy.cn/ops/85985.html

相关文章

Mac安装Hoomebrew与升级Python版本

参考 mac 安装HomeBrew(100%成功)_mac安装homebrew-CSDN博客 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装了Python 3.x版本,你可以使用以下命令来设置默认的Python版本: # 首先找到新安…

【音视频之SDL2】Windows配置SDL2项目模板

文章目录 前言 SDL2 简介核心功能 Windows配置SDL2项目模板下载SDL2编译好的文件VS配置SDL2 测试代码效果展示 总结 前言 在开发跨平台的音视频应用程序时,SDL2(Simple DirectMedia Layer 2)是一个备受欢迎的选择。SDL2 是一个开源库&#x…

[k8s源码]9.workqueue

client-go 是一个库,提供了与 Kubernetes API 服务器交互的基础设施。它提供了诸如 Informer、Lister、ClientSet 等工具,用于监听、缓存和操作 Kubernetes 资源。而自定义控制器则利用这些工具来实现特定的业务逻辑和自动化任务。业务逻辑实现&#xff…

模式Hash和history

vuerouter有两种路由模式Hash和history。区别:Hash为默认模式,url中包含一个#符号的哈希部分。优势:兼容性好,不需要后端服务器的特殊配置。缺点:不够美观,搜索引擎优化较差。History模式使用的浏览器的His…

免费【2024】springboot 编程语言在线学习平台的设计与实现

博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

50、PHP 实现选择排序

题目: PHP 实现选择排序 描述: n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:(1)初始状态:无序区为R[1…n],有序区为空。(2)第1趟排序在无序区R[1…n]中选出关键字最小的记录R[k],将…

Redis 哨兵搭建

Redis哨兵(sentinel)搭建 7.2.5 文章目录 一、单节点哨兵1. 环境介绍2. 环境前准备工作3. 安装 Redis 7.2.54. redis 配置修改并且启动4.1 修改配置文件4.2 编写启动脚本 5. 开启主从5.1 开启5.2 主库实例查看主从信息 6. 创建sentinel的配置文件并启动6.1 创建配置文件6.2 启…

便携式气象仪:科技赋能,让气象观测更智能

随着科技的快速发展,越来越多的领域受益于技术的进步。其中,气象观测领域也不例外。传统的气象观测设备虽然精确可靠,但往往体积庞大、携带不便,且需要专业人员进行操作和维护。而便携式气象仪的出现,则打破了这一局限…