4. 依赖查找依赖注入

news2024/11/26 17:31:49

本小节源码:Spring-DI

1. 依赖查找

前面两个小节我们学习了如何将 Bean 对象分别以配置文件与注解的方式存入 Spring 中,然而通过 Bean 从 Spring 容器中取出的过程其实就是依赖查找,这里我简单归纳一下各种依赖查找的方式。

1.1 通过beanId查找

ByName类配置进xml文件以存入Spring容器:

<bean id="test1" class="com.chenshu.beans.ByName"></bean>

测试代码:

BeanFactory factory = new ClassPathXmlApplicationContext("spring-conf.xml");
ByName test1 = (ByName) factory.getBean("test1");
System.out.println(test1);

成功打印出全限定类名:

com.chenshu.beans.ByName@548e7350

1.2 通过beanClass查找

这次我们直接通过class存入Spring容器,不再声明Bean的id

<bean class="com.chenshu.beans.ByType"></bean>

由于我们通过传类型来查找 Bean 因此不需要强转:

ByType byType = factory.getBean(ByType.class);
System.out.println(byType);

成功打印出全限定类名:

com.chenshu.beans.ByType@754ba872

1.3 通过interface查找

创建下面的DemoDao接口和DemoDaoImpl实现类:

image.png

DemoDaoImpl实现类配置入Spring的xml文件

<bean class="com.chenshu.dao.impl.DemoDaoImpl"></bean>

测试代码:

DemoDao demoDao = factory.getBean(DemoDao.class);
System.out.println(demoDao);

通过传接口的class对象,发现可以成功取出它的实例(前提是该接口只有一个对应的bean实例):

com.chenshu.dao.impl.DemoDaoImpl@6eebc39e

2. 依赖注入

前面创建的 Bean 都是没有预设属性的,如果需要预设的属性就得运用到 IOC 的实现方式——“依赖注入”了。这里我将使用xml文件配置以及注解配置两种方式分别演示一遍如何依赖注入,xml文件配置的方式作为简单的了解即可,注解的方式需要掌握。

2.1 xml文件配置

在xml文件配置的依赖注入方式有以下两种:

  • Setter注入
  • Constructor注入

2.1.1 Setter注入

Setter注入,简单来说就是Spring通过Setter方法将属性值注入,因此Bean对象必须实现Setter()方法:

public class User {
    private int age;
    private String name;

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + ''' +
                '}';
    }
}
简单类型

在bean的配置中新增property标签,name的值对应的就是需要引入依赖的字段名,value的值对应的就是字段值:

<bean id="user" class="com.chenshu.beans.User">
    <property name="age" value="19"></property>
    <property name="name" value="zhangsan"></property>
</bean>

测试代码:

User user = (User) factory.getBean("user");
System.out.println(user);

成功打印出刚刚我们所配置的字段值:

User{age=19, name='zhangsan'}
引用类型

在Spring框架中,如果一个Bean需要依赖另一个对象(即引用另一个对象),那么被引用的对象通常也应该是一个Spring容器管理的Bean。这是因为Spring的依赖注入机制是基于容器的,它负责创建、配置和管理Bean的生命周期。

新建一个service包,并在包中创建一个UserService的类:

public class UserService {
    private DemoDao demoDao;

    public void setDemoDao(DemoDao demoDao) {
        this.demoDao = demoDao;
    }

    public DemoDao getDemoDao() {
        return demoDao;
    }
}

并且该类想要依赖下面这个前面已经配置过的Bean:

<bean class="com.chenshu.dao.impl.DemoDaoImpl"></bean>

由于前面给大家演示的时候并没有给这个 Bean 取一个name,因此我们这里修改一下配置:

<bean id="demoDaoImpl" class="com.chenshu.dao.impl.DemoDaoImpl"></bean>

将UserService添加至xml文件,并添加property标签,其中name的值就是UserService需要依赖注入的字段名,ref的值对应的是需要引入的依赖的beanId,这就是为什么要给需要依赖的Bean取name的原因

<bean class="com.chenshu.service.UserService">
    <property name="demoDao" ref="demoDaoImpl"></property>
</bean>

测试代码:

UserService userService = factory.getBean(UserService.class);
System.out.println(userService.getDemoDao());

成功打印出我们所配置的值的全限定类名:

com.chenshu.dao.impl.DemoDaoImpl@67784306

2.1.2 Constructor注入

既然是构造器注入,那自然免不了编写它的构造器,你需要注入几个字段就编写其对应的构造器就好,我这里选择把两个字段都注入:

public User(int age, String name) {
    this.age = age;
    this.name = name;
}
简单类型

除了标签名,其他都和Setter大体一致,这里直接给出代码:

<bean id="user" class="com.chenshu.beans.User">
    <constructor-arg name="age" value="20"></constructor-arg>
    <constructor-arg name="name" value="lisi"></constructor-arg>
</bean>

运行结果:

User{age=20, name='lisi'}
引用类型

编写UserService的构造器:

public UserService(DemoDao demoDao) {
    this.demoDao = demoDao;
}

配置文件:

<bean class="com.chenshu.service.UserService">
    <constructor-arg name="demoDao" ref="demoDaoImpl"></constructor-arg>
</bean>

运行结果:

com.chenshu.dao.impl.DemoDaoImpl@65e2dbf3

2.2 注解配置

注解配置更加简单、方便。人总是趋利的,在企业开发的时候绝大多数还是使用注解的方式进行配置,注解配置实现依赖注入的方式有以下三种:

  • Field注入
  • Setter注入
  • Construcor注入

依赖注入需要使用@Autowired@Resource注解,这里我先演示前者,下一节会讲它们的区别。

这里我将使用纯注解的方式注册和动态注入Bean。

前置操作:

  1. 在xml文件中添加扫描路径
<content:component-scan base-package="com.chenshu"></content:component-scan>
  1. 通过@Controller、@Service、@Repository这三个注解分别将UserController、UserService、UserDaoImpl存入 IOC 容器。

image.png


2.2.1 Field(属性)注入

所谓field注入就是属性注入,这种方式很简单,直接在需要依赖注入的属性上加上@Autowired注解就好了,它也是日常开发中最常使用的一种注入方式

UserController需要依赖UserSerice

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void doController() {
        userService.doService();
        System.out.println("Do User Controller.");
    }
}

UserService需要依赖UserDaoImpl,由于UserDaoUserDaoImpl的接口,我们直接使用UserDao来接收:

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public void doService() {
        userDao.selectAll();
        System.out.println("Do User Service");
    }
}

UserDaoImpl没有需要依赖的对象:

@Repository
public class UserDaoImpl implements DemoDao {
    @Override
    public void selectAll() {
        System.out.println("select * from user");
    }
}

通过依赖查找找到UserController,并调用doController()

public static void main(String[] args) {
        BeanFactory factory = new ClassPathXmlApplicationContext("spring-conf.xml");
        UserController userController = factory.getBean("userController", UserController.class);
        userController.doController();
    }

依赖成功注入,并分别成功调用了三个 Bean 的方法:

select * from user
Do User Service
Do User Controller.

看到这里是否觉得很眼熟,我们可以回顾一下前面所学章节:1.Spring的核心思想 —— IOC和DI,再次理解一下何为IOC和DI

Field注入优缺点总结

优点:写法简单

缺点:

  1. 不能注入final修饰的属性:final修饰的变量只能在使用时直接赋值或者在构造方法赋值,而属性注入的方式,是在构造出对象之后Spring帮你赋值,不符合jdk的规范;
  2. 通用性问题:只能适用于IOC容器;
  3. 更容易违背单一设计原则:单一设计原则指的是一个类应只负责一项职责,由于这种写法过于简单,违背单一设计原则的概率就提升了;

2.2.2 Setter注入

所谓Setter注入,就是Spring通过setter方法来注入依赖的Bean,这种方式需要构造一个Setter方法,再在Setter上面加上一个@Autowired注解:

@Controller
public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void doController() {
        userService.doService();
        System.out.println("Do User Controller.");
    }
}

依赖成功注入,并分别成功调用了三个 Bean 的方法:

select * from user
Do User Service
Do User Controller.
Setter注入优缺点总结

优点: 符合单一设计原则

缺点:

  1. 不能注入final修饰的属性,原因同属性注入
  2. 【重要】注入对象可能被改变:由于setter方法可能会被多次调用,所以就有被修改的风险;

2.2.3 Constructor注入

Constructor注入(Spring官方推荐的依赖注入方式),也就是Spring通过Bean提供的构造器,将依赖注入Bean,跟Setter大同小异,只要在构造方法中将需要添加的依赖作为构造器的参数,再在构造器上添加一个@Autowired注解就可以了:

@Controller
public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void doController() {
        userService.doService();
        System.out.println("Do User Controller.");
    }
}

依赖成功注入,并分别成功调用了三个 Bean 的方法:

select * from user
Do User Service
Do User Controller.

与Setter的小区别: 当这个Bean的构造方法只有一个时,可以省略@Autowired参数


Constructor注入优点总结
  1. 可以注入final修饰的对象;
  2. 注入对象不会被修改:不像setter注入那样,构造方法在对象创建时只会执行一次,因此不存在依赖Bean被修改的情况;
  3. 完全初始化:因为依赖在类的构造方法中执行的,而构造方法是在对象创建之初执行的方法;
  4. 通用性更好,因为构造方法是 JDK 支持,所以更换任何框架,它都是适用的。

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

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

相关文章

【MySQL】索引篇

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f8;友情提供 目录 本系列传送门 1. 什么是索引 2. 索引的特性 3. 索引的分类 4. 索引的优点及缺点 优点 缺点 5.…

FPGA基于VCU的H265视频压缩,HDMI2.0输入,支持4K60帧,提供工程源码+开发板+技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的视频图像编解码方案 3、详细设计方案设计框图FPGA开发板视频输入Video PHY ControllerHDMI 1.4/2.0 Receiver SubsystemVideo Processing SubsystemVideo Frame Buffer WriteZynq UltraScale VCUPetaLinux 系统制作VLC播放器工…

ElasticSearch的数据同步【Java实现】

文章目录 1、思路分析1.1、同步调用1.2、异步通知1.3、监听binlog1.4、如何选择 2、实现数据同步2.1、思路2.2、demo2.3、声明交换机、队列1&#xff09;引入依赖2&#xff09;声明队列交换机名称3&#xff09;声明队列交换机 2.4、发送MQ消息2.5、接收MQ消息 3、代码链接分享 …

Quartz + SpringBoot 实现分布式定时任务

文章目录 前言一、分布式定时任务解决方案二、Quartz是什么&#xff1f;1.quartz简介2.quartz的优缺点 二、Quartz分布式部署总结 前言 因为应用升级&#xff0c;由之前的单节点微服务应用升级为集群微服务应用&#xff0c;所以之前的定时任务Spring Scheduled不再适用了&…

蓝桥备赛——组合数、其他技巧

对字符串进行permutations排列组合 from itertools import permutations a abc #对字符串进行permutations排列组合 for i in permutations(a,3):x .join(i)print (x,end ) print (\n------------------------------------) permutations后面的参数&#xff0c;第一个表示…

Canal 扩展篇

1.Canal介绍 GitHub - alibaba/canal: 阿里巴巴 MySQL binlog 增量订阅&消费组件 Canal 主要用途是基于 MySQL 数据库增量日志解析&#xff0c;提供增量数据订阅和消费&#xff0c;工作原理如下&#xff1a; Canal 模拟 MySQL slave 的交互协议&#xff0c;伪装自己为 M…

【原创】springboot+mysql宠物管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

Redis(二十)五大经典类型源码

文章目录 面试题源码核心Redis基本的数据结构(骨架)Redis数据库的实现Redis服务端和客户端实现其他 K-V实现怎样实现键值对(key-value)数据库的传统五大基本数据类型和新五大数据类型 5大数据结构底层C语言源码分析示例redisObject五大数据结构解析定义Debug Object keyString …

01 SQL基础 -- 初识数据库与安装

一、初识数据库 数据库是将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合。该数据集合称为数据库(Database, DB)。用来管理数据库的计算机系统称为数据库管理系统(Database Management System, DBMS) 1.1 DBMS 的种类 DBMS 主要通过数据的保存格式…

【WEEK7】 【DAY3】JDBC—数据库驱动【中文版】

2024.4.10 Wednesday 目录 10.JDBC10.1.数据库驱动10.1.1.驱动10.1.2.JDBC10.1.3.第一个JDBC程序10.1.3.1.创建一个普通项目10.1.3.2.导入数据库驱动10.1.3.3.编写测试代码10.1.3.4.DriverManager10.1.3.5.URL10.1.3.6.Connection10.1.3.7.Statement执行SQL的对象10.1.3.8.Res…

[大模型]Atom-7B-chat网页例子

# Atom-7B-chat## 环境准备在[autodl](https://www.autodl.com/)平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch-->2.0.0-->3.8(ubuntu20.04)-->11.8![Alt text](images/image-1.png)接下来打开刚刚租用服务器的JupyterLab&#xff0c;并…

Codeforces Round 937 (Div. 4)(A~E)

A. Stair, Peak, or Neither? 根据题意来就可以了 #include <bits/stdc.h> using namespace std;void solve(){int a,b,c;cin>>a>>b>>c;if(a<b and b<c){cout<<"STAIR"<<endl;}else if(a<b and b>c){cout<<…

Docker部署SpringBoot+Vue前后端分离项目

文章目录 1. 安装Docker1. 1 卸载旧版Docker1.2 配置yum仓库1.3 安装Docker1.4 添加自启动配置1.5 配置阿里云镜像加速1.6 测试 2. 安装Nginx2.1 拉取镜像2.2 安装Nginx2.3 测试 3. 安装MySQL3.1 拉取镜像3.2 安装MySQL3.3 连接MySQL 4. 部署SpringBoot项目4.1 Maven打包4.2 编…

算法——栈

. - 力扣&#xff08;LeetCode&#xff09; 给你一个以字符串表示的非负整数 num 和一个整数 k &#xff0c;移除这个数中的 k 位数字&#xff0c;使得剩下的数字最小。请你以字符串形式返回这个最小的数字。 class Solution { public:string removeKdigits(string num, int k…

LeetCode-热题100:64. 最小路径和

题目描述 给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 **说明&#xff1a;**每次只能向下或者向右移动一步。 示例 1&#xff1a; 输入&#xff1a; grid [[1,3,1],[1,5,1],[4,2,1]]…

二叉树:小红的完全二叉树构造

题目描述 小红想构造一个总共 n 个节点完全二叉树&#xff0c;该二叉树满足以下两个性质&#xff1a; 1. 所有节点的权值值为 1 ~ n 的一个排列。 2. 除了根节点以外&#xff0c;每个节点的权值和它父亲的权值的乘积为偶数。 请你帮小红构造出这个二叉树&#xff0c;并按层序遍…

Handler——小白能懂的原理,老鸟需要的面经

1.机制学习 1.1Handler定义 发送并处理 与线程的消息队列关联的Message和Runnable 1.2基本用法 1、Message.obtain() 从消息池取得Message 2、Handler().sendMessage(msg) 发送消息 3、Handler().post 将Runnable包装成Message发送 以下提供一个结构代码 import android.os.H…

嵌入式linux系统链接腾讯云的方法

各位开发者大家好,今天主要给大家分享一个,如何使用linux系统链接腾讯云的方法,因为微信小程序越来越普遍,链接腾讯云也是日常必须掌握的一个技能。 第一:【实验目的】 1、linux 系统连接腾讯云的方法 第二:【实验原理】 涉及到原理图添加原理图 2、linux开发板 …

AI 助力问题驱动式学习

文章概括&#xff1a; AI 已经带来学习方式的改变&#xff0c;降低了我们学习知识的难度&#xff0c;加快了我们解决问题的速度。 本文介绍如何通过 AI 工具&#xff0c;通过直接对大模型、对 Agent、对文档、对知识库提问的方式&#xff0c;快速学习知识快速解决问题等。 本…

Vue3学习03 pinia

Vue3学习 pinia pinia一个简单效果搭建 pinia 环境存储读取数据示例 修改数据 (三种方式)storeToRefsgetters$subscribestore组合式写法 pinia 在vue2中使用vuex&#xff0c;在vue3中使用pinia。 集中式状态管理&#xff0c;&#xff08;状态数据&#xff09;。多个组件共享数…