【Spring】使用注解的方式获取Bean对象(对象装配)
目录
一、了解对象装配
1、属性注入
1.1、属性注入的优缺点分析
2、setter注入
2.1、setter注入的优缺点分析
3、构造方法注入
3.1、构造方法注入的优缺点
二、@Resource注解
三、综合练习
上一个博客中,我们了解了使用注解快速的将对象存储到Spring中,当然存储有简单方法,读取对象也可以使用注解的简单方法来实现,下面我们来了解一下,简单的获取对象的方法。
一、了解对象装配
获取Bean对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入。
对象装配(对象注入)的实现方法有下面的三种方式
- 属性注入:会根据属性的类型,在容器种查找并获取对象,然后赋值给类的成员变量。
- 构造方法注入:通过构造方法将对象注入到对象中。
- Setter注入:通过setXXX 方法将对象注入到类中。
1、属性注入
属性注入只需要在需要注入对象的属性上加上@Autowired或者@Resource注解即可,这两个注解存在什么样的区别,我们在后面分析,这里我们以@Autowired注解来举例说明。
1️⃣容器中同类型的对象只有一个:直接将获取到的对象注入到当前属性上。
这里我们想让UserService类种获取到UserRepository类的对象,我们就需要在UserService类种设置一个类型是UserRepository的属性,给这个属性添加上@Autowired。表示的意思为从容器种获取这个属性类型的对象注入给这个属性。
首先给UserRepository类上添加类注解,将Bean存放在容器中。
package com.java.demo.dao;import org.springframework.stereotype.Repository;@Repository
public class UserRepository {public int add(){System.out.println("hello UserRepository");return 1;}
}
属性注入:将UserRepository在容器中的对象注入到UserService类中。
package com.java.demo.service;import com.java.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {//1.属性注入(DI:依赖注入)@Autowiredprivate UserRepository userRepository;public int add(){System.out.println("do UserService add method");return userRepository.add();}}
上面两步完成之后,我们就可以在测试类中,通过获取上下文对象(容器对象)来获取到userService对象(也就是依赖查找的方式获取到userService对象),然后调用userService对象的add方法,就可以观察到执行了UserRepository类的add方法,此时说明属性注入获取对象成功,我们并没有手动的new 这个userRepository对象。这里设置这个类只是用来检测属性注入(依赖注入)获取对象是否成功。
package com.java.demo.test;import com.java.demo.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService userService = context.getBean("userService",UserService.class);userService.add();}
}
容器中同类型的对象只有一个的情况,属性注入的时候根据类型在Spring中查找,找到对象之后,直接复制给这个类型的属性,但是如果容器中同类型的对象存在多个的情况,就需要给属性指定注入那个对象。如果不指定这程序就会报错。
2️⃣容器中同类型的对象存在多个:如果获取到多个同类型对象,会根据属性的名字来进行匹配。
我们通过下面的例子来了解容器中存在多个同类型对象,在获取对象是没有指定给属性指定注入那个对象,程序出现的错误。
创建一个普通实体类User,然后再Users类中使用@Bean的方式向Spring中添加多个对象,然后再UserService类中使用属性注入的方式获取User类的对象注入到属性中。
package com.java.demo.model;public class User {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}
}package com.java.demo.model;import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class Users {@Bean("user1")public User user1(){User user = new User();user.setId(1);user.setName("张三");return user;}@Bean("user2")public User user2(){User user = new User();user.setId(2);user.setName("李四");return user;}
}package com.java.demo.service;import com.java.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService2 {@Autowiredprivate User user;public void sayHi(){System.out.println(user.toString());}
}package com.java.demo.test;import com.java.demo.service.UserService2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService2 userService2 = context.getBean("userService2",UserService2.class);userService2.sayHi();}
}
上述的代码中由于获取到多个同类型的对象,不能直接根据类型将对象直接注入到当前类的属性中,需要根据属性的名称,将获取到的对象注入到属性中,但是属性的名称和对象名不相同的情况下,属性注入就会失败。想要解决这个问题,就需要设置对象名与属性名匹配,下面是三种解决这个问题的方法。
✨解决方案
1️⃣将属性的名字和Bean的名字对应上即可。
2️⃣ 也可以通过@Autowired注解和@Qualifier注解搭配使用,设置@Qualifier的参数为获取到的对象中的任意一个对象名即可,@Qualifier表示的意思就是根据参数筛选对象。
3️⃣属性上直接添加@Resource注解,这个注解的参数中存在name属性,我们可以将name的值设置获取到的对象中的某一个对象的名字。
1.1、属性注入的优缺点分析
1️⃣优点
属性注入的优点就是使用简单,直选哟添加一个@Autowired注解,就可以在不new对象的情况下,直接获取注入的对象了。
2️⃣缺点
🍂功能性问题:无法注入一个不可变的对象(被final修饰的对象),因为被final修饰的变量只能有两种初始化的方式,一种是直接复制,一种是通过构造方法赋值。就不能通过属性注入的方式获取到对象了。
🍂通用性问题:属性注入只能在IoC容器的前提下使用,脱离了IoC容器就不能使用了。
🍂设计原则问题:更容易违背单一设计原则,通俗来说就是属性注入的方式简单,滥用的概率就会很大。举个例子比如一个页面中不仅有用户的信息,也有用户请求的资源信息,那么后端写代码的时候在数据持久层的用户类中,本来就是针对用户注入相关的依赖,但是由于为了让程序的效率更高,有可能会在这个类中注入一些其他的信息相关的依赖。
2、setter注入
使用setter注入,在setXXX方法上添加一个@Autowired或者@Resource注解即可,当然setter注入也存在和属性注入一样的容器中相同类型的对象个数问题。这个问题的解决方法也和上述的属性注入时说的方法一样。
package com.java.demo.dao;import org.springframework.stereotype.Repository;@Repository
public class UserRepository {public int add(){System.out.println("hello UserRepository");return 1;}
}package com.java.demo.service;import com.java.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService3 {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}public void sayHi(){System.out.println("hello UserService3 .");userRepository.add();}
}package com.java.demo.test;import com.java.demo.service.UserService3;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService3 userService3 = context.getBean("userService3",UserService3.class);userService3.sayHi();}
}
2.1、setter注入的优缺点分析
1️⃣优点
setter更符合单一设计原则,因为那个setter方法,只是针对一个属性进程赋值。
2️⃣缺点
🍂无法注入一个final修饰的变量,因为final修饰的变量初始化的时候只有两种方式要么直接初始化,要么通过构造方法初始化。
🍂注入的对象可被修改。因为setXXX是一个方法,所以他就可能别调用,这个时候就会导致注入的Bean对象被修改了。
3、构造方法注入
使用构造方法注入,标准的写法在构造方法上添加一个@Autowired注解或者在构造方法上不加注解也可以实现注入效果。当然构造注入也存在和属性注入一样的容器中相同类型的对象个数问题。这个问题的解决方法也和上述的属性注入时说的方法一样。这里构造方法不支持使用@Resource注解。
1️⃣标准的写法构造方法上添加@Autowired注解
package com.java.demo.dao;import org.springframework.stereotype.Repository;@Repository
public class UserRepository {public int add(){System.out.println("hello UserRepository");return 1;}
}package com.java.demo.service;import com.java.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService4 {private UserRepository userRepository;@Autowiredpublic UserService4(UserRepository userRepository) {this.userRepository = userRepository;}public void sayHi(){System.out.println("hello userService4 .");userRepository.add();}
}package com.java.demo.test;import com.java.demo.service.UserService2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserService4 userService4 = context.getBean("userService4",UserService4.class);userService4.sayHi();}
}
2️⃣不太标准的写法,构造方法上不加注解,这种写法是当前类中只有一个构造方法的时候可以使用的,如果有多个构造方法的时候,构造方法上的@Autowired注解是不可以省略的。
3.1、构造方法注入的优缺点
1️⃣优点
🍂可以注入不可变对象(被final修改的变量)
🍂注入的对象不会被修改,因为构造方法会随着JVM的启动而被加载,只会被加载一次。就像上面的例子userRepositoryd对象注入到UserService4这个类中,这个类实例化被存入容器的时候,构造方法只会执行一次。
🍂构造方法注入,可以保证注入对象完全初始化,因为构造方法是在对象创建之前执行的。
🍂构造方法注入的通用性最好的,因为一个类中使用了构造方法注入,当你要使用这个类的对象的时候你就不得不给构造方法中的参数(当前类的属性)注入一个对象。
2️⃣缺点
🍂构造方法注入的写法比属性注入复杂
🍂构造方法注入的写法无法解决循环依赖的问题
二、@Resource注解
@Resource注解和@Autowired注解的用法是相同的,都可以注入对象。
✨@Resource和@Autowired的区别
1️⃣出生不同:@Autowired来自于Spring,而@Resource来自于JDK的注解;
2️⃣支持参数不同:@Autowired的参数只有一个,而@Ressource支持更多的参数设置。
3️⃣使用上的区别:@Autowired可用于Setter注入、构造方法注入和属性注入,但是@Resource只能用于Setter注入和属性注入,不支持使用构造方法注入。
4️⃣idea兼容性支持不同:使用@Autowired在idea专业版下可能出现误报,@Resource不存在误报的问题。
三、综合练习
在 Spring 项⽬中,通过 main ⽅法获取到 Controller 类,调⽤ Controller ⾥⾯通过注⼊的⽅式调⽤ Service 类,Service 再通过注⼊的⽅式获取到 Repository 类,Repository 类⾥⾯有⼀个⽅法构建⼀ 个 User 对象,返回给 main ⽅法。Repository ⽆需连接数据库,使用伪代码即可。
这里需要注意的是,通过main方法获取Controller类,在main方法中不能使用依赖注入的方式获取对象,因为main方法为静态方法,静态方法的执行是在Spring框架之前的,所以我们需要使用依赖查找的方式获取容器对象,然后获取对象。
类的设置路径
package com.java.demo.model;public class User {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}}
package com.java.demo.dao;import com.java.demo.model.User;
import org.springframework.stereotype.Repository;@Repository
public class UserRepository {//伪代码public User getUser(){User user = new User();user.setId(1);user.setName("王五");return user;}}
package com.java.demo.service;import com.java.demo.dao.UserRepository;
import com.java.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;public User getUser(){return userRepository.getUser();}
}
package com.java.demo.controller;import com.java.demo.model.User;
import com.java.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {@Autowiredprivate UserService userService;public User getUser(){return userService.getUser();}
}
package com.java.demo;import com.java.demo.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");UserController userController = context.getBean("userController",UserController.class);System.out.println(userController.getUser());}
}
相关文章:

【Spring】使用注解的方式获取Bean对象(对象装配)
目录 一、了解对象装配 1、属性注入 1.1、属性注入的优缺点分析 2、setter注入 2.1、setter注入的优缺点分析 3、构造方法注入 3.1、构造方法注入的优缺点 二、Resource注解 三、综合练习 上一个博客中,我们了解了使用注解快速的将对象存储到Spring中&#x…...

[webpack] 基本配置 (一)
文章目录 1.基本介绍2.功能介绍3.简单使用3.1 文件目录和内容3.2 下载依赖3.3 启动webpack 4.基本配置4.1 五大核心概念4.2 基本使用 1.基本介绍 Webpack 是一个静态资源打包工具。它会以一个或多个文件作为打包的入口, 将我们整个项目所有文件编译组合成一个或多个文件输出出去…...

模板学堂|SQL数据集动态参数使用场景及功能详解
DataEase开源数据可视化分析平台于2022年6月正式发布模板市场(https://dataease.io/templates/)。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板,方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&a…...

Wlan——射频和天线基础知识
目录 射频的介绍 射频和Wifi 射频的相关基础概念 射频的传输 信号功率的单位 射频信号传输行为 天线的介绍 天线的分类 天线的基本原理 天线的参数 射频的介绍 射频和Wifi 什么是射频 从射频发射器产生一个变化的电流(交流电),通过…...
前端实习周记第三周周记
第二周总结 第二周主要是做了一些PC端细节内容。大的地方改的不多,但是小的细节蛮多。 值得一提的是,第二周做的微信小程序,改了很多逻辑。改逻辑需要与后端进行联调,收获很大,思路也愈发清楚。 记录做了什么是好习…...
Android 13 Launcher界面——移除Launcher的删除和卸载功能
目录 一.背景 二.将卸载功能进行屏蔽 三.将移除功能屏蔽 四.将Remove按钮与Uninstall按钮屏蔽...

深度学习:使用卷积神经网络CNN实现MNIST手写数字识别
引言 本项目基于pytorch构建了一个深度学习神经网络,网络包含卷积层、池化层、全连接层,通过此网络实现对MINST数据集手写数字的识别,通过本项目代码,从原理上理解手写数字识别的全过程,包括反向传播,梯度…...

docker search 镜像报错: connect: no route to host (桥接模式配置静态IP)
如下 原因 可能有多种: ① 没有开放防火墙端口 ② ip地址配置有误 解决 我是因为虚拟机采用了桥接模式,配置静态ip地址有问题。 先确认虚拟机采用的是 桥接模式,然后启动虚拟机。 1、打开命令行,输入下面指令,打开…...
【VUE】[Violation] Added non-passive event listener to a scroll-blocking...
环境 chrome: 115.0.5790.170vue: ^3.3.4element-plus: ^2.3.4vite: ^4.4.7 问题 [Violation] Added non-passive event listener to a scroll-blocking <某些> 事件. Consider marking event handler as passive to make the page more responsive. See <URL> …...
runit-docker中管理多个服务
runit-docker中管理多个服务 介绍Runit, systemctl和supervisor是三种不同的服务管理工具区别runit优点程序构成快速开始runit实现服务退出执行指定操作runit监管服务打印日志到syslogrunit监管服务后台运行runit监管服务一些错误总结 介绍 runit 是一个轻量级的、稳定的、跨平…...

Intune 应用程序管理
由于云服务提供了增强的安全性、稳定性和灵活性,越来越多的组织正在采用基于云的解决方案来满足他们的需求。这正是提出Microsoft Endpoint Manager等解决方案的原因,它结合了SCCM和Microsoft Intune,以满足本地和基于云的端点管理。 与 Int…...

Oracle DB 安全性 : TDE HSM TCPS Wallet Imperva
• 配置口令文件以使用区分大小写的口令 • 对表空间进行加密 • 配置对网络服务的细粒度访问 TCPS 安全口令支持 Oracle Database 11g中的口令: • 区分大小写 • 包含更多的字符 • 使用更安全的散列算法 • 在散列算法中使用salt 用户名仍是Oracle 标识…...

leetcode27—移除元素
思路: 参考26题目双指针的思想,只不过这道题不是快慢指针。 看到示例里面数组是无序的,也就是说后面的元素也是可能跟给定 val值相等的,那么怎么处理呢。就想到了从前往后遍历,如果left对应的元素 val时,…...
flask---》更多查询方式/连表查询/原生sql(django-orm如何执行原生sql)/flask-sqlalchemy
更多查询方式 #1 查询: filer:写条件 filter_by:等于的值 # 查询所有 是list对象 res session.query(User).all() # 是个普通列表 print(type(res)) print(len(res))# 2 只查询某几个字段 # select name as xx,email from user; res session.…...
Chromium内核浏览器编译记(三)116版本内核UI定制
转载请注明出处:https://blog.csdn.net/kong_gu_you_lan/article/details/132180843?spm1001.2014.3001.5501 本文出自 容华谢后的博客 往期回顾: Chromium内核浏览器编译记(一)踩坑实录 Chromium内核浏览器编译记(…...

LoRaWan网关设计架构介绍
LoRa 数据包转发器是在基于 LoRa 的网关(带或不带 GPS)主机上运行的程序。它将集中器(上行链路)接收到的 RF 数据包通过安全的 IP 链路转发到LoRaWAN 网络服务器( LNS )。它还通过相同的安全 IP 将 LNS(下行链路)发送的 RF 数据包传输到一台或多台设备。此外,它还可以传…...
vue 全局状态管理(简单的store模式、使用Pinia)
目录 为什么使用状态管理简单的store模式服务器渲染(SSR) pinia简介示例1. 定义一个index.ts文件2. 在main.ts中引入3. 定义4. 使用 为什么使用状态管理 多个组件可能会依赖同一个状态时,我们有必要抽取出组件内的共同状态集中统一管理&…...

ORACLE和MYSQL区别
1,Oracle没有offet,limit,在mysql中我们用它们来控制显示的行数,最多的是分页了。oracle要分页的话,要换成rownum。 2,oracle建表时,没有auto_increment,所有要想让表的一个字段自增,…...

tensorflow 1.14 的 demo 02 —— tensorboard 远程访问
tensorflow 1.14.0, 提供远程访问 tensorboard 服务的方法 第一步生成 events 文件: 在上一篇demo的基础上加了一句,如下, tf.summary.FileWriter("./tmp/summary", graphsess1.graph) hello_tensorboard_remote.py …...
Spring中Bean的循环依赖问题
1.什么是Bean的循环依赖? 简单来说就是在A类中,初始化A时需要用到B对象,而在B类中,初始化B时需要用到A对象,这种状况下在Spring中,如果A和B同时初始化,A,B同时都需要对方的资源&…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...