Spring 中存储 Bean 的相关注解

在这里插入图片描述

Bean的存

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

类注解:五大注解

@Controller(控制器存储)
@Service(服务存储)
@Component(组件存储)
@Repository(仓库存储)
@Configuration(配置存储)
五大注解的存的过程都近似一样的,因此,下面我们就只介绍Controller的,其余的类似

@Controller(控制器存储)

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

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

如何观察这个对象已经存在Spring容器当中了呢?
接下来我们学习如何从Spring容器中获取对象

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

ApplicationContext翻译过来就是:Spring上下⽂,因为对象都交给Spring管理了,所以获取对象要从Spring中获取,那么就得先得到Spring的上下
这个上下⽂,就是指当前的运⾏环境,也可以看作是⼀个容器,容器⾥存了很多内容,这些内容是当前运⾏的环境
观察运⾏结果,发现成功从Spring中获取到Controller对象,并执⾏Controller的doController⽅法
在这里插入图片描述
如果把@Controller删掉,再观察运⾏结果
在这里插入图片描述
报错信息显⽰:找不到类型是:com.example.demo.controller.UserController的bean

获取bean对象的其他⽅式

上述代码是根据类型来查找对象,如果Spring容器中,同⼀个类型存在多个bean的话,怎么来获取呢?
ApplicationContext也提供了其他获取bean的⽅式,ApplicationContext获取bean对象的功能,是⽗类BeanFactory提供的功能.
在这里插入图片描述
常⽤的是上述1,2,4种,这三种⽅式,获取到的bean是⼀样的
其中1,2种都涉及到根据名称来获取对象.bean的名称是什么呢?
Spring bean是Spring框架在运⾏时管理的对象,Spring会给管理的对象起⼀个名字.
⽐如学校管理学⽣,会给每个学⽣分配⼀个学号,根据学号,就可以找到对应的学⽣.
Spring也是如此,给每个对象起⼀个名字,根据Bean的名称(BeanId)就可以获取到对应的对象.

Bean的命名约定

我们看下官⽅⽂档的说明:BeanOverview::SpringFramework
程序开发⼈员不需要为bean指定名称(BeanId),如果没有显式的提供名称(BeanId),Spring容器将为该bean⽣成唯⼀的名称.
命名约定使⽤Java标准约定作为实例字段名.也就是说,bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写.
⽐如
类名:UserController,Bean的名称为:userController
类名:AccountManager,Bean的名称为:accountManager
类名:AccountService,Bean的名称为:accountService
也有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写.这些规则与java.beans.Introspector.decapitalize(Spring在这⾥使⽤的)定义的规则相同.
⽐如
类名:UController,Bean的名称为:UController
类名:AManager,Bean的名称为:AManager
根据这个命名规则,我们来获取Bean

		ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UserController userController = context.getBean(UserController.class);userController.doController();System.out.println(userController);UserController userController1 = (UserController)context.getBean("userController");userController1.doController();System.out.println(userController1);UserController userController2 = context.getBean("userController", UserController.class);userController2.doController();System.out.println(userController2);

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

为什么要这么多类注解?

这个也是和咱们前⾯讲的应⽤分层是呼应的.让程序员看到类注解之后,就能直接了解当前类的⽤途.
• @Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
• @Servie:业务逻辑层,处理具体的业务逻辑.
• @Repository:数据访问层,也称为持久层.负责数据访问操作
• @Configuration:配置层.处理项⽬中的⼀些配置信息.
这和每个省/市都有⾃⼰的⻋牌号是⼀样的.
⻋牌号都是唯⼀的,标识⼀个⻋辆的.但是为什么还需要设置不同的⻋牌开头呢.
⽐如陕西的⻋牌号就是:陕X:XXXXXX,北京的⻋牌号:京X:XXXXXX,甚⾄⼀个省不同的县区也是不同的,⽐如西安就是,陕A:XXXXX,咸阳:陕B:XXXXXX,宝鸡,陕C:XXXXXX,⼀样.
这样做的好处除了可以节约号码之外,更重要的作⽤是可以直观的标识⼀辆⻋的归属地.
程序的应⽤分层,调⽤流程如下:
在这里插入图片描述
类注解之间的关系
查看 @Controller / @Service / @Repository / @Configuration 等注解的源码发
现:
在这里插入图片描述
在这里插入图片描述
其实这些注解⾥⾯都有⼀个注解@Component,说明它们本⾝就是属于@Component 的“⼦类”.
@Component 是⼀个元注解,也就是说可以注解其他类注解,如 @Controller ,@Service ,@Repository 等.这些注解被称为 @Component 的衍⽣注解.
@Controller ,@Service 和 @Repository ⽤于更具体的⽤例(分别在控制层,业务逻辑层,持久化层),在开发过程中,如果你要在业务逻辑层使⽤ @Component 或@Service,显然@Service是更好的选择

方法注解:@Bean

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

  1. 使⽤外部包⾥的类,没办法添加类注解
  2. ⼀个类,需要多个对象,⽐如多个数据源
    这种场景,我们就需要使⽤⽅法注解@Bean
    我们先来看看⽅法注解如何使⽤:
@Beanpublic UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName("zhangsan");return userInfo;}

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

        UserInfo contextBean = context.getBean(UserInfo.class);System.out.println(contextBean);

在这里插入图片描述
这是为什么呢?

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

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


@Controller
public class BeanController {@Beanpublic UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName("zhangsan");return userInfo;}}

在这里插入图片描述

定义多个对象

对于同⼀个类,如何定义多个对象呢?
⽐如多数据源的场景,类是同⼀个,但是配置不同,指向不同的数据源.
我们看下@Bean的使⽤

    @Beanpublic UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName("zhangsan");return userInfo;}@Beanpublic UserInfo userInfo2(){UserInfo userInfo = new UserInfo();userInfo.setName("lisi");userInfo.setId(2);userInfo.setAge(39);return userInfo;}

在这里插入图片描述
报错信息显⽰:期望只有⼀个匹配,结果发现了两个,user1,user2
从报错信息中,可以看出来,@Bean注解的bean,bean的名称就是它的⽅法名
接下来我们根据名称来获取bean对象

        UserInfo userInfo1 = (UserInfo)context.getBean("userInfo1");System.out.println(userInfo1);UserInfo userInfo2 = (UserInfo)context.getBean("userInfo2");System.out.println(userInfo2);

在这里插入图片描述

重命名 Bean

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

    @Bean(name = {"u1","userInfo1"})public UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName("zhangsan");return userInfo;}@Bean(name = {"u2", "userInfo2"})public UserInfo userInfo2(){UserInfo userInfo = new UserInfo();userInfo.setName("lisi");userInfo.setId(2);userInfo.setAge(39);return userInfo;}
		UserInfo userInfo1 = (UserInfo)context.getBean("u1");System.out.println(userInfo1);UserInfo userInfo2 = (UserInfo)context.getBean("u2");System.out.println(userInfo2);

在这里插入图片描述
name={}可以省略,如下代码所⽰:

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

只有⼀个名称时,{}也可以省略,如:

    @Bean("u1")

注意:类注解的五大注解也可以使用该方法进行重命名操作

Bean的取

上⾯我们讲解了控制反转IoC的细节,接下来呢,我们学习依赖注⼊DI的细节,依赖注⼊是⼀个过程,是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源,⽽资源指的就是对象.简单来说,就是把对象取出来放到某个类的属性中.在⼀些⽂章中,依赖注⼊也被称之为"对象注⼊",“属性装配”,具体含义需要结合⽂章的上下⽂来理解
关于依赖注⼊,Spring也给我们提供了三种⽅式:

  1. 属性注⼊(Field Injection)
  2. 构造⽅法注⼊(Constructor Injection)
  3. Setter注⼊(Setter Injection)
  4. 接下来,我们分别来看。
    下⾯我们按照实际开发中的模式,将Service类注⼊到Controller类中

属性注⼊

属性注⼊是使⽤@Autowired实现的,将Service类注⼊到Controller类中。
Service类的实现代码如下:

@Service
public class UserService {public void doService(){System.out.println("do service");}
}

Controller类的实现代码如下:

@Controller
public class UserController {@Autowiredprivate UserService userService;public void doController(){userService.doService();System.out.println("do controller");}
}

获取Controller中的doController⽅法

ApplicationContext context = SpringApplication.run(DemoApplication.class, args);UserController userController = context.getBean(UserController.class);userController.doController();

在这里插入图片描述
去掉@Autowired,再运⾏⼀下程序看看结果
在这里插入图片描述

构造⽅法注⼊

@Controller
public class UserController {
//    @Autowiredprivate UserService userService;public UserController(UserService userService) {this.userService = userService;}public void doController(){userService.doService();System.out.println("do controller");}
}

在这里插入图片描述

注意事项:如果类只有⼀个构造⽅法,那么@Autowired注解可以省略;如果类中有多个构造⽅法,
那么需要添加上@Autowired来明确指定到底使⽤哪个构造⽅法

@Controller
public class UserController {
//    @Autowiredprivate UserService userService;public UserController() {}public UserController(UserService userService) {this.userService = userService;}public void doController(){userService.doService();System.out.println("do controller");}
}

在这里插入图片描述


@Controller
public class UserController {
//    @Autowiredprivate UserService userService;public UserController() {}
@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void doController(){userService.doService();System.out.println("do controller");}
}

在这里插入图片描述

Setter注⼊

Setter注⼊和属性的Setter⽅法实现类似,只不过在设置set⽅法的时候需要加上@Autowired注解,如下代码所⽰:

@Controller
public class UserController {
//    @Autowiredprivate UserService userService;
@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void doController(){userService.doService();System.out.println("do controller");}
}

在这里插入图片描述

三种注⼊优缺点分析

属性注⼊
◦ 优点:简洁,使⽤⽅便;
◦ 缺点:
▪ 1.只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
▪ 不能注⼊⼀个Final修饰的属性
• 构造函数注⼊(Spring4.X推荐)
◦ 优点:
▪ 1.可以注⼊final修饰的属性
▪ 2.注⼊的对象不会被修改
▪ 3.依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法。
▪ 4.通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
◦ 缺点:
▪ 注⼊多个对象时,代码会⽐较繁琐
• Setter注⼊(Spring3.X推荐)
◦ 优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
◦ 缺点:
▪ 1.不能注⼊⼀个Final修饰的属性
▪ 2.注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险
更多DI相关内容参考:Dependencies :: Spring Framework

@Autowired存在问题

当同⼀类型存在多个bean时,使⽤@Autowired会存在问题

  @Bean("u1")public UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName("zhangsan");return userInfo;}@Bean(name = {"u2", "userInfo2"})public UserInfo userInfo2(){UserInfo userInfo = new UserInfo();userInfo.setName("lisi");userInfo.setId(2);userInfo.setAge(39);return userInfo;}
@Controller
public class UserController {
//    @Autowiredprivate UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@Autowiredprivate UserInfo userInfo;public void doController(){userService.doService();System.out.println("do controller");System.out.println(userInfo);}
}

在这里插入图片描述
如何解决上述问题呢?Spring提供了以下⼏种解决⽅案:

@Primary

使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现

 @Primary@Bean("u1")public UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setAge(26);userInfo.setName("zhangsan");return userInfo;}

在这里插入图片描述

@Qualifier

使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean的名称
@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤

@Controller
public class UserController {
//    @Autowiredprivate UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}@Qualifier("u2")@Autowiredprivate UserInfo userInfo;public void doController(){userService.doService();System.out.println("do controller");System.out.println(userInfo);}
}

在这里插入图片描述

@Resource

使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称

@Controller
public class UserController {
//    @Autowiredprivate UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}
//    @Qualifier("u2")
//    @Autowired@Resource(name = "u1")private UserInfo userInfo;public void doController(){userService.doService();System.out.println("do controller");System.out.println(userInfo);}
}

在这里插入图片描述
⾯试题:@Autowird与@Resource的区别
• @Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
• @Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊
@Autowired和@Resource的区别
• @Autowired来⾃于Spring,⽽@Resource来⾃于JDK的注解
• 使⽤时设置的参数不同:相⽐于@Autowired来说,@Resource⽀持更多的参数设置,例如name设置,根据名称获取Bean

bean的命名

1)五⼤注解存储的bean
①前两位字⺟均为⼤写,bean名称为类名
②其他的为类名⾸字⺟⼩写
③通过value属性设置 @Controller(value = “user”)
2)@Bean注解存储的bean
①bean名称为⽅法名
②通过name属性设置 @Bean(name = {“u1”,“user1”})

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

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

相关文章

深思:C与C++相互调用问题

背景 上周,偶然看到同事愁眉苦脸的样子,便善意咨询了下发生了什么。简单沟通下,才知道他遇到了一个工程编译的问题,一直无法编译通过,困扰了他快一天时间。出于个人的求知欲和知识的渴望,我便主动与他一同分…

【数据结构】堆的实现

目录 1. 前言2. 堆的实现2.1 初始化2.2 插入2.2.1 分析2.2.1.1 情况一2.2.1.2 情况二2.2.1.3 情况三 2.2.2 插入代码实现2.2.2.1 向上调整代码 2.3 删除2.3.1 分析2.3.2 删除代码实现2.3.2.1 向下调整代码 2.4 找根节点数据2.5 元素个数2.6 判空2.7 销毁 3. 源代码3.1 Heap.h3.…

许战海战略文库|主品牌升级为产业技术品牌,引领企业全球化发展

在当今高速发展的全球经济中,企业品牌已经成为其核心资产之一。这不仅仅是因为品牌可以为消费者带来识别度,更重要的是,它们可以为企业带来深厚的竞争壁垒。但对于许多企业来说,特别是技术密集型企业,仅仅依靠主品牌的…

如何让消费者接受品牌,口碑营销怎么做?

当新品牌进入小红书时,如何进行口碑营销是一个重要的问题。很多新品牌在刚刚进入小红书时,对于一些敏感时机把握的不准其实本质上,就是不明白什么阶段该做什么事。今天分享的就是如何让消费者接受品牌,口碑营销怎么做?…

NX二次开发UF_CURVE_ask_spline_data 函数介绍

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_spline_data Defined in: uf_curve.h int UF_CURVE_ask_spline_data(tag_t spline_tag, UF_CURVE_spline_p_t spline_data ) overview 概述 Reads the spline data a…

Java核心知识点整理大全18-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

Linux驱动开发——网络设备驱动(理论篇)

目录 一、前言 二、网络层次结构 三、网络设备驱动核心数据结构和函数 一、前言 网络设备驱动是 Linux 的第三大类驱动,也是我们学习的最后一类 Linux 驱动。这里我们首先简单学习一下网络协议层次结构,然后简单讨论 Linux 内核中网络实现的层次结构。…

接口测试工具(Jmeter)必学技巧

安装 使用JMeter的前提需要安装JDK,需要JDK1.7以上版本目前在用的是JMeter5.2版本,大家可自行下载解压使用 运行 进入解压路径如E: \apache-jmeter-5.2\bin,双击jmeter.bat启动运行 启动后默认为英文版本,可通过Options – Cho…

【知网稳定检索】2024年应用经济学,管理科学与社会发展国际学术会议(AEMSS 2024)

2024年应用经济学,管理科学与社会发展国际学术会议(AEMSS 2024) 2024 International Conference on Applied Economics, Management Science and Social Development 2024年应用经济学,管理科学与社会发展国际学术会议&#xff…

uniapp在H5端实现PDF和视频的上传、预览、下载

上传 上传页面 <u-form-item :label"(form.ququ3 1 ? 参培 : form.ququ3 2 ? 授课 : ) 证明材料" prop"ququ6" required><u-button click"upload" slot"right" type"primary" icon"arrow-upward" t…

流媒体播放器EasyPlayer播放H.265与H.264时进度条样式异常该如何解决?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…

网易云音乐7天黑胶VIP会员免费领取入口怎么领取网易云音乐黑胶VIP7天会员?

网易云音乐7天黑胶VIP会员免费领取入口怎么领取网易云音乐黑胶VIP7天会员&#xff1f; 1、百度搜索「词令」&#xff0c;在搜索框内输入词令「vip163」关键词直达口令&#xff0c;进入网易云音乐7天黑胶VIP会员免费领取入口&#xff1b; 2、输入网易云音乐黑胶VIP7天会员领取词…

AJAX技术-04-- 跨域说明

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1 同源策略同源策略介绍规定要求 请求协议://域名:端口号 关于同源策略练习关于同源策略总结 2.JSONPJSONP原理说明关于JSONP优化 3.CORS介绍介绍不允许跨域说明跨域…

Cascader 级联选择器动态加载数据的回显

如果后端没有只返回第三级的id,而是同时把第三级的名字一起返回了&#xff0c;那么就可以通过下面的方法来实现 1.在级联选择器里面加上这句代码 placeholder"请选择" 2.注册一个字符串 pleasett:"" 3.赋值 如过后端返回的有第三级的选项名 直接进行赋…

【WP】Geek Challenge 2023 web 部分wp

官方出的题很好 学到很多东西 前面几道入门提就不写了 klf_ssti 目录扫描扫到一个robots.txt 打开存在hack路径&#xff0c;查看源码存在klf 传参,结合题目 就是ssti注入了&#xff0c;然后使用tplmap工具发现是盲注&#xff0c;我们这里直接用脚本找popen&#xff1a; im…

一键修复0xc000007b错误代码,科普关于0xc000007b错误的原因

最近很多用户都有遇到过0xc000007b错误的问题&#xff0c;出现这样的问题想必大家都会手足无措吧&#xff0c;其实解决这样的问题也有很简单的解决方法&#xff0c;这篇文章就来教大家如何一键修复0xc000007b&#xff0c;同时给大家科普一下关于0xc000007b错误的原因&#xff0…

Redis多机数据库

文章目录 Redis多机数据库一、主从复制1、旧版复制功能的实现a、同步b、命令传播 2、旧版复制功能的缺陷3、新版复制功能的实现a、部分同步功能b、复制实现步骤 4、心跳检测 二、哨兵1、Sentinel概念2、Sentinel初始化流程3、故障转移过程 三、集群1、几个概念2、集群创建流程a…

逆袭之战,线下门店如何在“?”萧条的情况下实现爆发增长?

未来几年&#xff0c;商业走势将受到全球经济形势、科技进步和消费者需求变化等多种因素的影响。随着经济复苏和消费者信心提高&#xff0c;消费市场将继续保持增长&#xff0c;品质化、个性化、智能化等将成为消费趋势。同时&#xff0c;线上购物将继续保持快速增长&#xff0…

Spring Data Redis切换底层Jedis 和 Lettuce实现

1 简介 Spring Data Redis是 Spring Data 系列的一部分&#xff0c;它提供了Spring应用程序对Redis的轻松配置和使用。它不仅提供了对Redis操作的高级抽象&#xff0c;还支持Jedis和Lettuce两种连接方式。 可通过简单的配置就能连接Redis&#xff0c;并且可以切换Jedis和Lett…

springboot+vue实现websocket通信实例,进入页面建立连接

springbootvue实现websocket通信实例 进入页面建立连接 前端代码&#xff1a; <template><div class"app-container"><el-form :model"queryParams" ref"queryForm" size"small" :inline"true" v-show&qu…