Java-Spring入门指南(五)Spring自动装配

Java-Spring入门指南(五)Spring自动装配

Java-Spring入门指南(五)Spring自动装配


前言

在上一篇博客中,我们掌握了Spring依赖注入的两种核心手动方式——构造器注入与setter注入,但也留下了一个明显的“痛点”:当Bean的依赖关系复杂(比如一个Service依赖多个Dao)时,我们需要在XML中反复编写<property ref="..."/>,配置繁琐且容易出错。

有没有办法让容器“主动找”依赖,而不是我们“手动指”依赖?

  • 答案就是这篇要讲的Spring自动装配(Autowire)。它是Spring在手动注入基础上的优化,核心是“容器根据预设规则自动匹配并注入依赖”,能大幅减少XML配置冗余。

本文将从“自动装配的本质”切入,手把手实战两种核心自动装配方式(byNamebyType),再详解alias(Bean别名)和import(XML整合)这两个辅助配置。

我的个人主页,欢迎来阅读我的其他文章
https://blog.ZEEKLOG.net/2402_83322742?spm=1011.2415.3001.5343
我的Java-Spring入门指南知识文章专栏
欢迎来阅读指出不足
https://blog.ZEEKLOG.net/2402_83322742/category_13040333.html?spm=1001.2014.3001.5482
在这里插入图片描述

一、什么是Spring自动装配?

在讲实战前,我们先搞懂“自动装配”到底解决了什么问题——它不是替代手动注入,而是对setter注入的“简化”

1.1 手动注入的痛点

回顾上一篇的User依赖Address,我们需要在XML中手动配置<property ref="address"/>

<!-- 手动注入:必须明确写ref指向依赖的Bean --><beanid="user"class="org.example.pojo.User"><propertyname="address"ref="address"></property><!-- 手动关联 --></bean><beanid="address"class="org.example.pojo.Address"></bean>

如果一个OrderService依赖OrderDaoUserDaoLogDao三个Bean,就需要写3个<property>标签——依赖越多,配置越繁琐

1.2 自动装配的定义

自动装配(Autowire)的核心是:容器根据预设的“匹配规则”,自动在IoC容器中查找当前Bean的依赖(如Person依赖的Dog、Cat),并完成注入,无需手动编写<property ref="..."/>

1.3 自动装配的本质

  1. 容器先通过无参构造器创建当前Bean(如Person);
  2. 按规则(byName/byType)在容器中找依赖的Bean;
  3. 找到后,自动调用当前Bean的setter方法完成注入。
关键前提:自动装配仅支持setter注入不支持构造器注入!所以Bean必须有依赖属性的setter方法。

二、自动装配的核心方式

Spring提供多种自动装配方式,最常用、最核心的是byName(按名称匹配)byType(按类型匹配)

2.1 准备工作

首先编写我们的核心Bean类:

// Dog类(被依赖方)publicclassDog{publicvoideat(){System.out.println("狗喜欢吃骨头");}}// Cat类(被依赖方)publicclassCat{publicvoideat(){System.out.println("猫喜欢吃小鱼干");}}// Person类(依赖方:依赖Dog和Cat)publicclassPerson{privateDog dog;privateCat cat;publicCatgetCat(){return cat;}publicvoidsetCat(Cat cat){this.cat = cat;}publicDoggetDog(){return dog;}publicvoidsetDog(Dog dog){this.dog = dog;}}

2.2 方式一:byName

2.2.1 核心规则

容器会根据当前Bean的“属性名”,去匹配IoC容器中其他Bean的“id属性”——属性名与Bean的id完全一致时,自动注入

用我们的Person举例:

// Person类(依赖方:依赖Dog和Cat)publicclassPerson{privateDog dog;privateCat cat;publicCatgetCat(){return cat;}publicvoidsetCat(Cat cat){this.cat = cat;}publicDoggetDog(){return dog;}publicvoidsetDog(Dog dog){this.dog = dog;}}
  • Person有两个属性:dog(属性名)、cat(属性名);
  • 容器中需有id="dog"的Dog类Bean、id="cat"的Cat类Bean;
  • 配置autowire="byName"后,容器自动匹配并注入。

2.2.2 配置实战

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 1. 配置被依赖方Bean:id必须与Person的属性名一致 --><beanid="dog"class="org.example.pojo.autowire.Dog"></bean><!-- id=dog 匹配 Person的dog属性 --><beanid="cat"class="org.example.pojo.autowire.Cat"></bean><!-- id=cat 匹配 Person的cat属性 --><!-- 2. 配置依赖方Bean:开启byName自动装配 --><beanid="person"class="org.example.pojo.autowire.Person"autowire="byName"><!-- 无需写<property ref="dog"/>和<property ref="cat"/>,容器自动匹配 --></bean></beans>

2.2.3 测试代码与结果

编写测试类,验证自动装配是否成功:

@Testpublicvoidtest2(){ClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext("autowire.xml");Person person = applicationContext.getBean("person",Person.class); person.getCat().eat(); person.getDog().eat();}

预期结果

在这里插入图片描述

2.2.4 关键注意点

  1. 属性名与Bean的id必须完全一致:若Person的dog属性改名为doggy,而Bean的id还是dog,容器找不到匹配的Bean,会注入null
  2. 允许同类型多Bean:如你代码中注释的cat1,即使开启,只要Person没有cat1属性,就不影响cat属性的匹配(byName只看名称,不看类型);
  3. 必须有setter方法:容器通过setter方法注入,若删除setDog(),会注入null

2.3 方式二:byType

2.3.1 核心规则

容器会根据当前Bean的“属性类型”,去匹配IoC容器中其他Bean的“class类型”——属性类型与Bean的class完全一致,且容器中该类型Bean唯一时,自动注入

2.3.2 配置实战

只需将person Bean的autowire改为byType,其他不变:

<!-- 被依赖方Bean:id可任意(byType不依赖id) --><beanid="dog"class="org.example.pojo.autowire.Dog"></bean><!-- 类型是Dog --><beanid="cat"class="org.example.pojo.autowire.Cat"></bean><!-- 类型是Cat --><!-- 依赖方Bean:开启byType自动装配 --><beanid="person"class="org.example.pojo.autowire.Person"autowire="byType"><!-- 同样无需手动配置property --></bean>

2.3.3 测试代码与结果

复用上面的test方法(只需保证XML配置是byType),预期结果与byName完全一致

在这里插入图片描述
  • 关键区别:此时即使把dog Bean的id改为myDogcat Bean的id改为myCat,依然能注入成功(byType不看id)。

2.3.4 关键注意点

  1. 不依赖Bean的id:即使Bean的id与属性名完全不同(如id=myDog,属性名=dog),只要类型匹配且唯一,就能注入;
  2. 支持父子类/接口:若有Dog的子类BigDog,Person的dog属性是Dog类型,容器中只有BigDog类型Bean,也能匹配(多态支持)。

容器中该类型Bean必须唯一:这是byType的核心限制!若此时容器有两个Cat类型Bean,启动容器会直接报错:

在这里插入图片描述
NoUniqueBeanDefinitionException: No qualifying bean of type 'org.example.pojo.autowire.Cat' available: expected single matching bean but found 2: cat,cat1 

2.4 byName vs byType 对比

两种自动装配方式各有适用场景,用表格对比更清晰:

对比维度byName(按名称)byType(按类型)
匹配规则属性名 ≡ Bean的id属性类型 ≡ Bean的class(且唯一)
依赖条件必须保证属性名与Bean的id一致必须保证容器中该类型Bean唯一
灵活性依赖命名规范,改id需同步改属性名不依赖id,改id不影响注入
容错性同类型多Bean不报错(只看名称)同类型多Bean直接报错
适用场景命名规范明确(如属性名=Bean id)类型唯一且稳定(如工具类Bean)

三、alias与import

3.1 alias:给Bean起别名

3.1.1 核心作用

给IoC容器中的Bean分配多个“别名”,后续通过“原id”或“任意别名”都能获取该Bean,解耦Bean的引用与id的绑定

比如:

<aliasname="person"alias="person_name_1"/>
  • 原id:person
  • 别名:person_name_1
  • 获取Bean时,ac.getBean("person")ac.getBean("person_name_1")得到的是同一个对象。

3.1.2 适用场景

  1. 多模块引用同一Bean:A模块习惯用personA称呼,B模块习惯用personB,给Bean起两个别名,无需修改原id;
  2. 避免id冲突:若导入的第三方XML中已有user Bean,你本地的user Bean可起别名myUser,避免冲突。

3.2 import:拆分与整合XML配置

3.2.1 核心作用

当项目中Bean数量庞大时,将所有Bean写在一个XML中会非常臃肿。import可以将多个分散的XML配置文件导入到一个“主配置文件”,只需加载主配置,就能加载所有XML中的Bean。

比如:

<importresource="beans.xml"/>
  • 主配置文件:autowire.xml(当前配置文件);
  • 导入的子配置:beans.xml(可存放其他Bean,如上一篇的Student、User);
  • 加载主配置时,autowire.xmlbeans.xml中的Bean都会被加载到容器。

3.2.2 实战场景

假设项目分3个模块,每个模块的Bean存放在独立XML中:

  • dao.xml:存放Dao层Bean(如UserDao、OrderDao);
  • service.xml:存放Service层Bean(如UserService、OrderService);
  • autowire.xml:存放Person、Dog、Cat等Bean(主配置);

通过import整合主配置:

<!-- 主配置文件:autowire.xml --><importresource="dao.xml"/><importresource="service.xml"/><!-- 本地Bean配置 --><beanid="dog"class="org.example.pojo.autowire.Dog"></bean><beanid="cat"class="org.example.pojo.autowire.Cat"></bean><beanid="person"class="org.example.pojo.autowire.Person"autowire="byName"></bean>
  • 加载时只需加载autowire.xml,就能获取所有模块的Bean,大幅提升可维护性。

3.2.3 注意点

  1. 路径问题resource属性写XML的“相对路径”,若子XML在config目录下,需写resource="config/dao.xml"
  2. 顺序无关import的顺序不影响Bean的加载(Spring会处理依赖关系);
  3. 重复导入不报错:同一XML被多次导入,Spring只会加载一次。

四、自动装配的优缺点与使用建议

4.1 优点

  1. 简化配置:无需手动写大量<property ref="..."/>,减少XML冗余;
  2. 降低维护成本:依赖关系变更时,只需修改Bean的id或类型,无需修改注入配置;
  3. 支持模块化:结合importalias,适合大型项目拆分配置。

4.2 缺点

  1. 可读性下降:无法直观看到Bean的依赖来源(手动注入能明确看到ref指向);
  2. 排错难度高:注入null时,需排查命名、类型、Bean唯一性等多个维度;
  3. 功能局限:仅支持setter注入,不支持构造器注入;不支持复杂依赖(如集合类型)。

4.3 推荐使用原则

  1. 简单场景用自动装配:如工具类、单一依赖的Bean(如Person依赖Dog/Cat),优先用byName(命名规范明确时)或byType(类型唯一时);
  2. 复杂场景用手动注入:如多依赖、构造器注入、集合类型注入,手动配置更明确,排错更简单;
  3. 大型项目结合注解:XML自动装配是基础,后续我们会讲注解驱动的自动装配(@Autowired@Qualifier),比XML更灵活、更简洁。

我的个人主页,欢迎来阅读我的其他文章
https://blog.ZEEKLOG.net/2402_83322742?spm=1011.2415.3001.5343
我的Java-Spring入门指南知识文章专栏
欢迎来阅读指出不足
https://blog.ZEEKLOG.net/2402_83322742/category_13040333.html?spm=1001.2014.3001.5482
非常感谢您的阅读,喜欢的话记得三连哦
在这里插入图片描述

Read more

sftpgo汉化处理

问题描述 官方提供的sftpgo webui的默认语言为英文, 没有待中文的语言包。实际上中文语言包已经翻译完毕,本文介绍一种在不重新编译的情况下为sftpgo的webui增加中文包的方法。 准备 1. (已完成安装的跳过) 安装sftpgo的官方安装包, 这里例子中使用的是: sftpgo_v2.6.6_windows_portable.zip 具体下载地址: https://github.com/drakkan/sftpgo/releases 2. 下载已经汉化的中文资源,其实际上是一个json文件, 可以参考这个:https://gitee.com/chenbichao/sftpgo-ryan/blob/master/static/locales/zh/translation.json 3. sftpgo服务已可以正常使用 原理 webui的前端资源都已经在sftpgo的可执行文件的同级目录下存在,分别是template文件夹下的页面展示信息 和 static文件夹下的资源。通过直接修改template中的js代码可以增加页面中的语言选项,并在用户点击是自动下

By Ne0inhk
Y20030009基于Java+springboot+MySQL+uniapp框架的待办事项提醒微信小程序的设计与实现 源码 文档 PPT

Y20030009基于Java+springboot+MySQL+uniapp框架的待办事项提醒微信小程序的设计与实现 源码 文档 PPT

待办事项提醒小程序 * 1.摘要 * 2.开发目的和意义 * 3.系统功能设计 * 4.系统界面截图 * 5.源码获取 1.摘要 随着现代人的工作和生活压力越来越大,人们的精力和时间也越来越有限。在这样的情况下,很容易忘记一些很重要的行程,有时会导致严重的后果,如何处理好自己的待办事项,便成为了一个需要特别关注的重要问题,因为只有处理好待办事项,才能让我们的工作和生活更加有序、轻松和高效。因此可以设计一个操作简单的,功能齐全的待办事项管理系统,让用户能够按照优先级、时间、标签等方式对任务进行分类,方便用户管理任务,提高效率。同时还需要提供任务的添加、修改、删除等操作,方便用户随时调整任务。在此基础上添加待办事项提醒功能,来为用户提供一个高效率软件 基于微信的待办事项管理系统小程序主要以Uni-App用为前端框架,利用Uni-App的基础组件库和API、以及UniUI扩展实现基本的小程序功能。采用Springboot作为后端框架。通过MyBatis用为持久层来进行MySQL数据库操作。采用前后端分离的设计原则,前端负责展示和用户交互,后端负责数据处理和业务逻辑实现。

By Ne0inhk
【工具使用】IDEA 社区版如何创建 Spring Boot 项目(详细教程)

【工具使用】IDEA 社区版如何创建 Spring Boot 项目(详细教程)

IDEA 社区版如何创建 Spring Boot 项目(详细教程) Spring Boot 以其简洁、高效的特性,成为 Java 开发的主流框架之一。虽然 IntelliJ IDEA 专业版提供了Spring Boot 项目向导,但 社区版(Community Edition) 并不自带 Spring Boot 项目创建功能。 那么,如何在 IDEA 社区版中创建一个 Spring Boot 项目呢?本篇文章将手把手教你 使用 IDEA 社区版 + Maven 快速创建 Spring Boot 项目,并成功运行第一个 Spring Boot 应用!🚀 1. 前置准备 在创建

By Ne0inhk
深入解析 Rust + LLM 开发:手把手教你写一个 AI 运维助手

深入解析 Rust + LLM 开发:手把手教你写一个 AI 运维助手

目录 * 摘要 * 第一章:Linux 环境下的 Rust 开发生态构建 * 1.1 构建工具链与系统依赖安装 * 1.2 Rust 工具链(Toolchain)的部署 * 1.3 环境变量配置与验证 * 第二章:蓝耘 MAAS 平台接入与资源配置 * 2.1 获取 API 凭证 * 2.2 模型选型与端点配置 * 第三章:Rust 项目架构设计与依赖管理 * 3.1 依赖库(Crates)深度解析 * 第四章:核心模块实现原理 * 4.1 AI 客户端模块 (ai_client.rs) * 4.2

By Ne0inhk