Spring IoCDI(2)

IoC详解

通过上面的案例, 我们已经知道了IoC和DI的基本操作, 接下来我们来系统地学习Spring IoC和DI的操作.

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

Bean的存储

我们之前只讲到了@Component注解来使得对象交给IoC容器管理. 而Spring为了更好地管理Web应用程序, 提供了更丰富的注解.

当前有两类注解:

1.类注解@Controller(控制器存储), @Service(服务存储), @Reposity(仓库), @Component(组件), @Configuration(配置)

2.方法注解: @Bean

 类注解的使用

由于这里五个类注解在功能上基本是一致的, 所以这里用@Controller进行介绍.

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

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

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

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

@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context = SpringApplication.run(SpringbootDemoApplication.class);//从Spring上下文中获取对象MyController myController = context.getBean(MyController.class);//获取对象myController.sayHi();}
}

ApplicationContext 翻译过来就是: Spring上下文.

因为对象交给Spring管理, 所以获取对象要从Spring中获取, 那么就得先得到Spring的上下文.

关于上下文的概念

在计算机领域, 上下文这个概念, 我们之前在在进程PCB核心属性讲过, 它是指支持进程调度的重要属性. 等下次调度回CPU时,会把寄存器上的回复回来.

这里的上下文, 就是指当前的运行环境, 也可以看作是一个容器, 容器里存很多内容, 这些内容是当前运行的环境. 

观察运行结果, 发现成功从Spring中获取到Controller对象, 并执行Controller的SayHi方法.

 获取bean对象的其他方式

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

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

可以发现, 我们获取bean共有五种方法, 而常用的是第1, 2, 4三种. 第一种是根据名称获取bean对象, 第二种是通过名称, 类型获取bean对象. 第三种是通过类型获取对象.

其中1,2种都涉及根据名称来获取对象, bean的名称是什么呢?

Spring bean是Spring框架在运行时管理的对象, Spring会给管理的对象起一个名字.

比如学校管理学生, 会给每个学生分配一个学号, 根据学号, 可以找到对应学生.

Spring也是如此, 给每个对象起一个名字, 根据Bean名称(BeanId)就可以获取到对应对象. 

Bean命名约定

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

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

eg. MyController -> myController

也有一些特殊情况, 当有多个字符且第一个和第二个字符都大写时, 将保留原始的大小写. 

eg. UController -> UController

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

@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context = SpringApplication.run(SpringbootDemoApplication.class);//根据bean类型, 从Spring上下文中获取对象.MyController myController1 = context.getBean(MyController.class);//根据bean名称, 从Spring上下文中获取对象MyController myController2 = (MyController) context.getBean("myController");//根据bean名称+对象, 从Spring上下文中获取对象MyController myController3 = context.getBean("myController", MyController.class);//使用对象System.out.println(myController1);System.out.println(myController2);System.out.println(myController3);}
}

运行结果:

地址一样, 说明对象是一个.

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

ApplicationContext VS BeanFactory (面试题)

继承关系和功能来说: Spring有两个顶级的接口: ApplicationContext 和BeanFactory. 其中

BeanFactory提供了基础的访问容器的能力, 而Application属于BeanFactory的子类. 它除了继承BeanFactory的所有功能之外, 还有独特的特性: 对国际化的支持, 资源访问支持, 以及事件传播方面的支持. 

从性能来说: ApplicationContext是一次性加载并初始化的所有Bean对象(可类似于饿汉模式),BeanFactory是需要哪个再去加载哪个, 因此更加轻量.(空间换时间) (一般建议用ApplicationContext, 因为现在机器的性能更高了). 

为什么要这么多类注解?

这个也是和前面讲的应用分层相呼应. 让程序员看到注解之后, 就能知道这个类的用途.

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

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

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

@Configuration: 配置层. 处理项目中的一些配置信息. 

这个就类似于车牌号的功能, 一看开头, 不管后面的字符串是什么, 就能知道这个车是哪里的. 

程序的应用分层, 调用逻辑如下:

类注解之间的关系

查看@Controller, @Configuration, @Repository, @Service的源码发现:

这些注解中其实都有一个元注解: @Component, 说明它们本身就属于@Component的"子类", 说明它们本身就是属于@Component的"子类". @Component是一个元注解, 也就是说可以注解其它类注解, 如@Controller, @Service, @Repository, 这些注解都可以说是@Component的衍生注解.

方法注解@Bean

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

1.使用外部包里的类, 没办法添加类注解

2.一个类, 需要多个对象, 比如多个数据源.

 这种场景, 我们就需要注解@Bean

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

在Spring框架的设计中, 方法注解@Bean要配合类注解才能将对象正常地存储到Spring容器中.

举个栗子:

@Component
public class BeanConfig {@Beanpublic User user() {User user = new User();user.setName("lisi");user.setAge(20);return user;}
}

 运行下述代码:

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

得到运行结果:

定义多个对象

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

比如多数据源的场景, 类是同一个, 但是配置不同, 指向不同的数据源. 

我们看下@Bean的使用

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

当定义到多个对象时, 我们继续使用上面的代码, 能获取到什么对象? 我们来运行一下:

报错信息显示:期望只有一个匹配, 结果却发现了两个: user1, user2.

从报错信息中, 可以看出来, @Bean注解的bean, bean名称就是它的方法名.

接下来以正确的方式来获取Bean对象.

@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {//获取Spring上下文对象ApplicationContext context = SpringApplication.run(SpringbootDemoApplication.class);User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");System.out.println(user1);System.out.println(user2);}
}

运行结果: 

可以看到, @Bean针对同一个类, 定义多个对象.

重命名Bean

@Bean(name = {"u1", "user1"}) 

添加类似的注解仍可以运行成功, 这是将user1重命名为u1的一种方式. 类似地, 还有如下方式:

@Bean({"u1", "user1"})

//只有一个名称时, 其它的内容可以省略.

@Bean("u1")

扫描路径

使用前面注解声明的bean, 一定会生效吗?

不一定(原因: bean想要生效, 还需要被Spring扫描).

当在同一个包内, 可以直接被Spring扫描到, 如果不在同一个包, 就可以通过@ComponentScan来配置扫描路径.

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

{}里可以配置多个包路径.

这种做法仅作了解, 不做推荐使用. 

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

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

相关文章

SAP Fiori开发中的JavaScript基础知识10 - 变量作用域,变量提升

1. 背景 本文将会介绍JavaScript中两个相对复杂的概念,也即作用域和变量提升。这个概念在JavaScript中的设计和ABAP中的设计区别还是比较大的,特别是变量提升部分。第一次接触JavaScript的同学,要注意理解和区分。 2. 作用域 在JavaScript…

vscode安装

🌈个人主页:Rookie Maker 🏆🏆关注博主,随时获取更多关于IT的优质内容!🏆🏆 😀欢迎来到小田代码世界~ 😁 喜欢的小伙伴记得一键三连哦 ૮(˶ᵔ ᵕ ᵔ˶)ა …

商场促销--策略模式

1.1 商场收银软件 package com.lhx.design.pattern.test;import java.util.Scanner;public class Test {public static void main(String[] args){System.out.println("**********************************************"); System.out.println("《大话设计模式…

vue3鼠标向下滑动,导航条改变背景颜色和logo的封装

代码中使用了element-plus组件&#xff0c;需先安装 向下滑动前 向下滑动后&#xff08;改变了logo 字体 背景颜色&#xff09; <script lang"ts" setup> import router from /router; import { ArrowDown } from element-plus/icons-vue import { ref, …

【tensorflow框架神经网络实现鸢尾花分类—优化器】

文章目录 1、前言2、神经网络参数优化器2.1、SGD2.2、SGDM2.3、Adagrad2.4、RMSProp2.5、Adam 3、实验对比不同优化器4、结果对比 1、前言 此前&#xff0c;在【tensorflow框架神经网络实现鸢尾花分类】一文中使用梯度下降算法SGD&#xff0c;对权重 w w w和偏置 b b b进行更新…

如何在Windows上安装SSH

SSH&#xff08;Secure Shell&#xff09;协议是一种强大且安全的网络协议&#xff0c;它为用户提供了一种加密的方式来远程访问和管理终端设备。在Windows操作系统中&#xff0c;安装和配置SSH服务是一个相对直接的过程&#xff0c;可以让你享受到SSH带来的便利和安全性。下面…

软件设计原则:迪米特法则

定义 迪米特法则&#xff08;Law of Demeter, LoD&#xff09;&#xff0c;又称最少知识原则&#xff0c;它指导我们在设计软件时&#xff0c;应当尽量减少对象之间的交互&#xff0c;一个对象应该对其他对象有尽可能少的了解。具体来说&#xff0c;一个对象应该只调用属于以下…

Lua脚本的使用

一、使用lua脚本扣减单个商品的库存 SpringBootTest class LuaTests {AutowiredStringRedisTemplate stringRedisTemplate;Testvoid test3() {for (int i 1; i < 5; i) {stringRedisTemplate.opsForValue().set("product."i,String.valueOf(i));}}Testvoid test…

3.写一个char类型的字符数组,对该数组访问越界时抛出异常,并做处理。

#include <iostream>using namespace std;char arr[10]"12345678"; void show(int i) {if(i>10){throw int(2);}cout << arr[i] <<endl; } int main() {int i;cin >> i;try {show(i);} catch (int) {cout << "越界" <…

【华为OD机试C++】句子逆序

《最新华为OD机试题目带答案解析》:最新华为OD机试题目带答案解析,语言包括C、C++、Python、Java、JavaScript等。订阅专栏,获取专栏内所有文章阅读权限,持续同步更新! 文章目录 描述输入描述输出描述示例1示例2代码描述 将一个英文语句以单词为单位逆序排放。例如“I am …

【Web】记录Polar靶场<困难>难度题一遍过

目录 上传 PHP是世界上最好的语言 非常好绕的命令执行 这又是一个上传 网站被黑 flask_pin veryphp 毒鸡汤 upload tutu Unserialize_Escape 自由的文件上传系统​​​​​​​ ezjava 苦海 你想逃也逃不掉 safe_include CB链 phar PHP_Deserializatio…

Centos7环境下安装MySQL8详细教程

1、下载mysql安装包 2、检查是否安装过mysql ps:因为以前用yum安装过&#xff0c;所以先用yum卸载。如果不是此方式或者没安装过则跳过 [rootlocalhost ~]# yum remove mysql 已加载插件&#xff1a;fastestmirror 参数 mysql 没有匹配 不删除任何软件包 查看是否有mysql依赖 …

6.7物联网RK3399项目开发实录-驱动开发之Camera摄像头的使用(wulianjishu666)

90款行业常用传感器单片机程序及资料【stm32,stc89c52,arduino适用】 链接&#xff1a;https://pan.baidu.com/s/1M3u8lcznKuXfN8NRoLYtTA?pwdc53f Camera 使用 简介 AIO-3399J 开发板分别带有两个 MIPI&#xff0c;MIPI 支持最高 4K 拍照&#xff0c;并支持 1080P 30fp…

Java进阶-反射的详解与应用

本文深入探讨了Java反射机制的核心概念、应用实例及其在现代Java开发中的重要性。文章首先介绍了反射的基本原理和能力&#xff0c;包括在运行时动态获取类信息、操作对象字段和方法的能力。随后&#xff0c;通过具体代码示例&#xff0c;展示了如何利用反射进行字段访问、方法…

逆序对————权值线段树+离散化写法

今天写道这么一道题&#xff0c;鉴于不太熟悉归并和树状数组&#xff0c;还是用线段树水一下&#xff08; 板子如下 #include<iostream> #include<vector> #include<algorithm> using namespace std; const int N5e510; #define int long long #define lc …

java版本学习网站又添加了一个libgdx模块

java版本学习网站之前添加了docker&#xff0c;想了想还是再把libgdx添加进去吧。 访问地址&#xff1a;想飞跃的鱼 (nanshaws.github.io) github地址&#xff1a;nanshaws/JavaLearnNote: The new features from Java 9 to Java 21 help you quickly grasp the key features …

Mysql中的那些索引

主键索引 表的主键使用的就是主键索引&#xff0c;一张表只能有一个主键索引&#xff0c;主键索引不能为null,且不能重复。 主键索引存在于B树的非叶子节点&#xff0c;叶子节点存放的是数据。 非主键索引 非主键索引也叫二级索引&#xff0c;包括有唯一索引&#xff0c;普…

工业项目能耗管理可以看这个开源项目

软件介绍 Scaphandre是一个专注于电力和能源消耗指标的计量代理&#xff0c;旨在为公司和个人提供测量技术服务功耗的便捷工具&#xff0c;并以便于理解的方式获取数据。其名字来源于法语中的潜水服或潜水器&#xff0c;象征着深入测量和揭示技术服务耗能量的意图。 功能特点 …

【攻防世界】file_include (PHP伪协议+过滤器)

打开题目环境&#xff1a; 进行PHP代码审计&#xff0c;发现这是一个文件包含漏洞。 我们尝试利用PHP伪协议中的 php://filter来读取 check.php 中的内容。 构造payload 并提交&#xff1a; 发现payload被过滤掉了&#xff0c;我们就需要尝试使用不同的转换器。 PHP各类转换…