五、深入了解IoC

news2025/1/26 15:18:00

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

5.1Bean的存储

共有两类注解类型可以实现:
1.类注解:@Controller、@Service、@Repository、@Component、@Configuration.
2.方法注解:@Bean.

5.1.1@Controller(控制器存储)

使⽤@Controller 存储bean

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

从Spring容器中获取对象

@SpringBootApplication
public class DemoApplication {

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

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

观察运⾏结果,发现成功从Spring中获取到Controller对象,并执⾏Controller的sayHi⽅法

 删掉@Controller,再观察运⾏结果

报错信息显⽰:找不到类型是:com.example.demo.controller.UserController的bean 

5.1.2 Bean命名约定

程序开发⼈员不需要为bean指定名称(BeanId),如果没有显式的提供名称(BeanId),Spring容器将为该 bean⽣成唯⼀的名称.

命名约定使用Java标准约定作为实例字段名.也就是说,bean名称以小写字母开头,然后使用驼峰式大小写

⽐如:

类名:UserController, Bean的名称为:userController

类名:AccountManager,Bean的名称为: accountManager

类名:AccountService, Bean的名称为:accountService

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

⽐如:

类名:UController, Bean的名称为:UController

类名:AManager,Bean的名称为: AManager

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

        //根据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对象,是⽗类BeanFactory提供的功能

ApplicationContext VS BeanFactory(常⻅⾯试题)

• 继承关系和功能方面来说:Spring容器有两个顶级的接⼝:BeanFactory和 ApplicationContext。其中BeanFactory提供了基础的访问容器的能⼒,⽽ ApplicationContext 属于 BeanFactory 的⼦类,它除了继承了BeanFactory的所有功能之外, 它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持.

• 从性能方面来说:ApplicationContext⼀次性加载并初始化所有的Bean对象,⽽ BeanFactory需要那个才去加载那个,因此更加轻量.(空间换时间) 

5.1.3 @Service(服务存储)

使⽤@Service 存储bean的代码:
 

@Service
public class UserService {
    public void sayHi() {
        System.out.println("Hi,UserService");
    }
}

读取bean:

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


        //从Spring中获取UserService对象
        UserService userService = context.getBean(UserService.class);
        userService.sayHi();
}
}

观察运⾏结果,发现成功从Spring中获取到UserService对象,并执⾏UserService的sayHi⽅法

把注解@Service删掉,再观察运⾏结果

5.1.4 @Repository(仓库存储)

使用@Repository 存储bean的代码如下所示:

package com.example.demo.repo;

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    public void doRepository() {
        System.out.println("de repo...");
    }
}

读取bean的代码:

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


        //从Spring中获取UserRepository对象
        UserRepository userRepository = context.getBean(UserRepository.class);
        userRepository.doRepository();
    }
}

 观察运⾏结果,发现成功从Spring中获取到UserRepository对象,并执⾏UserRepository的sayHi⽅法

把注解@Repository删掉,再观察运⾏结果

5.1.5 @Component(组件存储)

使用@Component 存储bean的代码如下所示:

@Component
public class UserComponent {
    public void doComponent() {
        System.out.println("doComponent...");
    }
}

读取bean的代码:

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

        //从Spring中获取UserComponent对象
        UserComponent userComponent = context.getBean(UserComponent.class);
        userComponent.doComponent();

}
}

观察运⾏结果,发现成功从Spring中获取到UserComponent对象,并执⾏UserComponent的sayH方法 。

把注解@Component删掉,再观察运⾏结果 

 5.1.6 @Configuration(配置存储)

使用@Configuration 存储bean的代码如下所示:

@Configuration
public class UserConfig {
    public void doConfig() {
        System.out.println("do configuration...");
    }
}

读取bean的代码:

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

        //从Spring中获取UserConfig对象
        UserConfig userConfig = context.getBean(UserConfig.class);
        userConfig.doConfig();
}
}

观察运⾏结果,发现成功从Spring中获取到UserConfiguration对象,并执⾏UserConfiguration的 sayHi⽅法

把注解@Configuration删掉,再观察运⾏结果

 5.2使用多类注解的好处

与应⽤分层是呼应的.让程序员看到类注解之后,就能直接了解当前类的⽤途.

• @Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.

• @Servie:业务逻辑层,处理具体的业务逻辑.

• @Repository:数据访问层,也称为持久层.负责数据访问操作

• @Configuration:配置层.处理项⽬中的⼀些配置信息.

这和每个省/市都有自己的车牌号是一样的,
车牌号都是唯一的,标识一个车辆的.但是为什么还需要设置不同的车牌开头呢.
比如江苏的车牌号就是:苏X:XXXXXX,北京的车牌号:京X:XXXXXX,甚至一个省不同的县区也
是不同的,比如南京就是,苏A:XXXXX,无锡:苏B:XXXXXX,,苏州E:XXXXXX,一样.
这样做的好处除了可以节约号码之外,更重要的作用是可以直观的标识一辆车的归属地.

程序的应⽤分层,调⽤流程如下:

5.2.1 类注解之间的关系

查看 @Controller  @Service   @Repository   @Configuration 等注解的源码

其实这些注解里面都有一个注解@Component,说明它们本身就是属于@Component」的"子类"
@Component是一个元注解,也就是说可以注解其他类注解,如@Controller,@Service
@Repository等.这些注解被称为@Component的衍生注解.@Contrller,@Service和@Repository用于更具体的用例(分别在控制层,业务逻辑层,持久化层),在开发过程中,如果你要在业务逻辑层使用@Component或@Service,显然@Service是更好的选择。

5.3 ⽅法注解@Bean

类注解是添加到某个类上的,但是存在两个问题:
1.使用外部包里的类,没办法添加类注解
2.一个类,需要多个对象,比如多个数据源
这种场景,我们就需要使用方法注解@Bean

5.3.1 ⽅法注解要配合类注解使⽤

方法注解的使用:

public class BeanConfig {
    @Bean
    public UserInfo user() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("张三");
        userInfo.setAge(18);
        return userInfo;
    }
}

尝试获取bean对象中的UserInfo

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

程序报错

 原因是方法注解要配合类注解使⽤!

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

@Component
public class BeanConfig {
    @Bean
    public UserInfo user() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("张三");
        userInfo.setAge(18);
        return userInfo;
    }
}

再次运⾏程序结果如下:

5.3.2 定义多个对象

对于同⼀个类,定义多个对象

@Bean的使用如下:

@Component
public class BeanConfig {


    @Bean
    public UserInfo userInfo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("张三");
        userInfo.setAge(18);
        return userInfo;
    }

    @Bean
    public UserInfo userInfo2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("李四");
        userInfo.setAge(20);
        return userInfo;
    }
}

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

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

运⾏结果:

 报错信息显⽰:期望只有⼀个匹配,结果发现了两个,userInfo1,userInfo2 从报错信息中,可以看出来, @Bean注解的bean,bean的名称就是它的⽅法名

接下来我们根据名称来获取bean对象

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

运⾏结果:

5.3.3 重命名Bean

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

@Component
public class BeanConfig {
    @Bean(name = {"u1", "user1"})
    public UserInfo userInfo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("张三");
        userInfo.setAge(18);
        return userInfo;
    }
}

此时我们使用u1或user1就可以获取到User对象了,如下代码所示:

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

name={} 可以省略,如下代码所示:

@Component
public class BeanConfig {
    @Bean({"u1", "user1"})
    public UserInfo userInfo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("张三");
        userInfo.setAge(18);
        return userInfo;
    }
}

只有⼀个名称时,{}也可以省略,如下代码所示:

@Component
public class BeanConfig {
    @Bean("u1")
    public UserInfo userInfo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setName("张三");
        userInfo.setAge(18);
        return userInfo;
    }
}

5.3 扫描路径

Q: 使⽤前⾯学习的四个注解声明的bean,不⼀定会⽣效。原因是bean想要生效,还需要被Spring扫描。

修改项目工程的目录结构,来测试bean对象是否生效:

运⾏代码: 

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

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

运行结果:

 

那为什么前⾯没有配置@ComponentScan注解也可以呢? @ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注@SpringBootApplication 中了。默认扫描的范围是SpringBoot启动类所在包及其子包。

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

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

相关文章

python-leetcode-有效的字母异位词

242. 有效的字母异位词 - 力扣(LeetCode) class Solution:def isAnagram(self, s: str, t: str) -> bool:return sorted(s) sorted(t)

RHCE实验详解

目录 实验分析 环境拓扑结构 项目需求 主机环境描述 实验步骤 一、密钥互信和主机名更改 二、DNS 三、NGINX 四、MARIADB 五、NFS 六、NTP 七、论坛服务 结果展示及痛点解答 实验分析 环境拓扑结构 项目需求 1. 172.25.250.101 主机上的 Web 服务要求提供 www.ex…

【Unity】ScrollViewContent适配问题(Contentsizefilter不刷新、ContentSizeFilter失效问题)

最近做了一个项目,菜单栏读取数据后自动生成,结果用到了双重布局 父物体 尝试了很多方式,也看过很多大佬的文章,后来自己琢磨了一下,当子物体组件自动生成之后,使用以下以下代码效果会好一些: …

linux如何修改密码,要在CentOS 7系统中修改密码

要在CentOS 7系统中修改密码,你可以按照以下步骤操作: 步骤 1: 登录到系统 在登录提示符 localhost login: 后输入你的用户名。输入密码并按回车键。 步骤 2: 修改密码 登录后,使用 passwd 命令来修改密码: passwd 系统会提…

Qt Creator 15.0.0如何更换主题和字体

1.打开Qt Creator 15.0.0 (Community), 2.点击编辑栏3.点击Preferences... 4.修改主题,点击环境,修改Theme:栏 5.修改字体大小,点击文本编辑器,修改字号栏。,修改Theme:栏

Java 日志技术、Logback日志框架、日志级别

一. 日志 1. 日志:程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息。 二. 日志技术 1. 日志技术:可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中) 2. 可以随时以开关的…

【多视图学习】显式视图-标签问题:多视图聚类的多方面互补性研究

Explicit View-labels Matter:A Multifacet Complementarity Study of Multi-view Clustering TPAMI 2024 论文链接 代码链接 0.论文摘要 摘要-一致性和互补性是促进多视图聚类(MVC)的两个关键因素。最近,随着流行的对比学习的引入&#…

Datax可视化工具Datax-web安装部署

文章目录 一、Datax-web官网二、Datax-web介绍 1、Datax-web概述2、架构图3、系统环境要求4、特性支持 三、安装部署 1、环境准备2、Datax-web安装包准备 一、Datax-web官网 github:Datax-web gitee: Datax-web 二、Datax-web介绍 1、Datax-web概述 DataX Web…

Spark Streaming编程基础

文章目录 1. 流式词频统计1.1 Spark Streaming编程步骤1.2 流式词频统计项目1.2.1 创建项目1.2.2 添加项目依赖1.2.3 修改源目录1.2.4 添加scala-sdk库1.2.5 创建日志属性文件 1.3 创建词频统计对象1.4 利用nc发送数据1.5 启动应用,查看结果 2. 编程模型的基本概念3…

最新-CentOS 7 基于1 Panel面板安装 JumpServer 堡垒机

CentOS 7 基于1 Panel面板安装 JumpServer 堡垒机 一、前言二、设备要求三、环境要求四、安装4.1 环境安装4.2 JumpServer安装4.3 访问JumpServerWeb端,进行登录 五、登录Web控制台 一、前言 JumpServer是广受欢迎的开源堡垒机。运维必备神器!JumpServe…

【电脑无法通过鼠标和键盘唤醒应该怎么办】

【电脑无法通过鼠标和键盘唤醒应该怎么办】 方法一(有时候不起作用):方法二(方法一无效时,使用方法二): 方法一(有时候不起作用): 方法二(方法一无效时,使用方法二):

python学习笔记2-简单数据类型

不同类型的变量可以进⾏的运算是不同的,所以必须理解变量的类型,python中数据类型可以分为: Number(数值) 整型(int) python3中只有int⼀种,可以表⽰整数,例如&#xf…

iOS开发设计模式篇第二篇MVVM设计模式

目录 一、什么是MVVM 二、MVVM 的主要特点 三、MVVM 的架构图 四、MVVM 与其他模式的对比 五、如何在iOS中实现MVVM 1.Model 2.ViewModel 3.View (ViewController) 4.双向绑定 5.文中完整的代码地址 六、MVVM 的优缺点 1.优点 2.缺点 七、MVVM 的应用场景 八、结…

Kafak 单例生产者实现-C#操作

前面写了一篇入门操作的文章,因为工作需要,简单修改了下如何实现单例生产者。 Kafka入门-C#操作_c# kafka-CSDN博客文章浏览阅读1.6k次,点赞20次,收藏9次。2).报错:“kafka.zookeeper.ZooKeeperClientTimeoutException: Timed out waiting for connection while in state…

JAVA与数据结构-线性表

目录 一.线性表的概念 二.线性表的关系及分类 三.数组与顺序表 四.链表 1.静态链表(链表的的数组底层实现) 2.循环链表 3.双向链表 五.栈 1.栈的概念 2.栈的底层实现 3.共享空间栈 4.逆波兰表达式(后缀表达式) 5.栈与递归 六.…

2024.1.22 安全周报

政策/标准/指南最新动态 01 工信部印发《关于加强互联网数据中心客户数据安全保护的通知》 原文: https://www.secrss.com/articles/74673 互联网数据中心作为新一代信息基础设施,承载着千行百业的海量客户数据,是关系国民经济命脉的重要战略资源。…

WPS数据分析000005

目录 一、数据录入技巧 二、一维表 三、填充柄 向下自动填充 自动填充选项 日期填充 星期自定义 自定义序列 1-10000序列 四、智能填充 五、数据有效性 出错警告 输入信息 下拉列表 六、记录单 七、导入数据 ​编辑 八、查找录入 会员功能 Xlookup函数 VL…

如何使用 Node.js 构建一个简单的 API?

如何使用 Node.js 构建一个简单的 API? 在现代 Web 开发中,构建高效的 API 是连接前端与后端的核心任务之一。本文将向您展示如何使用 Node.js 构建一个简单的 API,同时通过示例说明如何测试 API。 步骤一:安装 Node.js 和创建项…

StarRocks强大的实时数据分析

代码仓库:https://github.com/StarRocks/starrocks?tabreadme-ov-file StarRocks | A High-Performance Analytical Database 快速开始:StarRocks | StarRocks StarRocks 是一款高性能分析型数据仓库,使用向量化、MPP 架构、CBO、智能物化…