当前位置: 首页 > news >正文

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

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

  • 前言
  • 一、什么是Spring自动装配?
    • 1.1 手动注入的痛点
    • 1.2 自动装配的定义
    • 1.3 自动装配的本质
  • 二、自动装配的核心方式
    • 2.1 准备工作
    • 2.2 方式一:byName
      • 2.2.1 核心规则
      • 2.2.2 配置实战
      • 2.2.3 测试代码与结果
      • 2.2.4 关键注意点
    • 2.3 方式二:byType
      • 2.3.1 核心规则
      • 2.3.2 配置实战
      • 2.3.3 测试代码与结果
      • 2.3.4 关键注意点
    • 2.4 byName vs byType 对比
  • 三、alias与import
    • 3.1 alias:给Bean起别名
      • 3.1.1 核心作用
      • 3.1.2 适用场景
    • 3.2 import:拆分与整合XML配置
      • 3.2.1 核心作用
      • 3.2.2 实战场景
      • 3.2.3 注意点
  • 四、自动装配的优缺点与使用建议
    • 4.1 优点
    • 4.2 缺点
    • 4.3 推荐使用原则


前言

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

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

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

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

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

在这里插入图片描述


一、什么是Spring自动装配?

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

1.1 手动注入的痛点

  • 《上一篇地址https://blog.csdn.net/2402_83322742/article/details/151373078》

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

<!-- 手动注入:必须明确写ref指向依赖的Bean -->
<bean id="user" class="org.example.pojo.User"><property name="address" ref="address"></property> <!-- 手动关联 -->
</bean>
<bean id="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类(被依赖方)
public class Dog {public void eat() {System.out.println("狗喜欢吃骨头");}
}// Cat类(被依赖方)
public class Cat {public void eat() {System.out.println("猫喜欢吃小鱼干");}
}// Person类(依赖方:依赖Dog和Cat)
public class Person {private Dog dog;private Cat cat;public Cat getCat() {return cat;}public void setCat(Cat cat) {this.cat = cat;}public Dog getDog() {return dog;}public void setDog(Dog dog) {this.dog = dog;}
}

2.2 方式一:byName

2.2.1 核心规则

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

用我们的Person举例:

// Person类(依赖方:依赖Dog和Cat)
public class Person {private Dog dog;private Cat cat;public Cat getCat() {return cat;}public void setCat(Cat cat) {this.cat = cat;}public Dog getDog() {return dog;}public void setDog(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"?>
<beans xmlns="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的属性名一致 --><bean id="dog" class="org.example.pojo.autowire.Dog"></bean> <!-- id=dog 匹配 Person的dog属性 --><bean id="cat" class="org.example.pojo.autowire.Cat"></bean> <!-- id=cat 匹配 Person的cat属性 --><!-- 2. 配置依赖方Bean:开启byName自动装配 --><bean id="person" class="org.example.pojo.autowire.Person" autowire="byName"><!-- 无需写<property ref="dog"/>和<property ref="cat"/>,容器自动匹配 --></bean></beans>

2.2.3 测试代码与结果

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

     @Testpublic void test2() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("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) -->
<bean id="dog" class="org.example.pojo.autowire.Dog"></bean> <!-- 类型是Dog -->
<bean id="cat" class="org.example.pojo.autowire.Cat"></bean> <!-- 类型是Cat --><!-- 依赖方Bean:开启byType自动装配 -->
<bean id="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必须唯一:这是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. 不依赖Bean的id:即使Bean的id与属性名完全不同(如id=myDog,属性名=dog),只要类型匹配且唯一,就能注入;

  3. 支持父子类/接口:若有Dog的子类BigDog,Person的dog属性是Dog类型,容器中只有BigDog类型Bean,也能匹配(多态支持)。

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的绑定

比如:

<alias name="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。

比如:

<import resource="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 -->
<import resource="dao.xml"/>
<import resource="service.xml"/>
<!-- 本地Bean配置 -->
<bean id="dog" class="org.example.pojo.autowire.Dog"></bean>
<bean id="cat" class="org.example.pojo.autowire.Cat"></bean>
<bean id="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.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Java-Spring入门指南知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_13040333.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述


文章转载自:

http://YkoUzCJt.fkxkk.cn
http://EGTOHiQ9.fkxkk.cn
http://28Qs7Xai.fkxkk.cn
http://mywucnN0.fkxkk.cn
http://OsX86pmr.fkxkk.cn
http://3O0NQfxO.fkxkk.cn
http://8V83Z3h7.fkxkk.cn
http://R7LF0dTs.fkxkk.cn
http://e8dRFe2A.fkxkk.cn
http://MHBJJK6f.fkxkk.cn
http://euN4R6Lw.fkxkk.cn
http://wNTKRaKU.fkxkk.cn
http://NHqq1bsQ.fkxkk.cn
http://8HecsflE.fkxkk.cn
http://1ttVbk8U.fkxkk.cn
http://6W1YH16r.fkxkk.cn
http://8lGBPrcX.fkxkk.cn
http://TzWUd1VA.fkxkk.cn
http://doEtGhxO.fkxkk.cn
http://3sotDOGG.fkxkk.cn
http://Y2Lme9Rv.fkxkk.cn
http://k35vUBCP.fkxkk.cn
http://kFkBFyb4.fkxkk.cn
http://9sm8rIyX.fkxkk.cn
http://uKYgwFaw.fkxkk.cn
http://djBl7Yjc.fkxkk.cn
http://bPKmr7H3.fkxkk.cn
http://elE6Q0eW.fkxkk.cn
http://nJAD5yuf.fkxkk.cn
http://JbnJ0b3k.fkxkk.cn
http://www.dtcms.com/a/376160.html

相关文章:

  • 必知必会:词向量构建方法(Word2Vec、ELMo、BERT)、聚类性质的句子向量构建方法(SBERT、SimCSE )
  • 查找算法(Java)
  • 计算机视觉----opencv高级操作(上采样,下采样,拉普拉斯金字塔,图像数值的统计)
  • 【华为OD】阿里巴巴找黄金宝箱
  • DDR SDRAM要点总结
  • unity以战斗截图并加上微信二维码分享
  • Scikit-learn Python机器学习 - 分类算法 - K-近邻(KNN)算法
  • 主机插入多个usb相机,固定序号
  • 软考中级习题与解答——第四章_软件工程(1)
  • java后端工程师进修ing(研一版‖day42)
  • 详细解读k8s的kind中service与pod的区别
  • RAG 为什么会作为知识库项目的名字
  • 边缘检测算子与Canny边缘检测
  • 数据可视化能帮大忙!一文教会小白怎么做可视化数据图表!
  • MAC 多个版本 JDK进行切换
  • macOS是开发的终极进化版吗?
  • Visual Studio 发布项目 win-86 win-64 win-arm win-arm64 osx-64 osx-64 osx-arm64 ...
  • Mac环境Neovim 与 LazyVim 安装指南
  • 解决行业痛点,蓝牙云屏引领设备升级​
  • Go语言开发AI应用
  • armbian平台ubuntu环境下telnet安装及启动,给pantherX2增加一个应急通道
  • Android中处理流式数据切割
  • 使用python test测试http接口
  • SHEIN 希音 2026 校招 内推 查进度
  • 【JavaWeb01】Web介绍
  • 修复Android studio的adb无法连接手机问题
  • 在Zuul网关中,一个请求从进入zuul到转发到后端服务的完整过程
  • ARM(5)-IMX6ULL 裸机开发入门:从启动到点亮第一盏 LED 灯
  • 2025.9.10总结
  • 第6章串数组:串的定义和存储结构