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

什么是Agentic AI?Agentic AI 与传统 AIGC 有什么区别?

什么是Agentic AI?Agentic AI 与传统 AIGC 有什么区别?

什么是 Agentic AI?Agentic AI 与传统 AIGC 有什么区别? 1. 引言 近年来,人工智能(AI)技术飞速发展,其中以生成式 AI(AIGC,Artificial Intelligence Generated Content)和 Agentic AI(智能代理 AI)最为热门。AIGC 通过深度学习模型生成文本、图像、视频等内容,而 Agentic AI 则更进一步,能够自主感知、决策并执行任务。那么,Agentic AI 究竟是什么?它与传统的 AIGC 有何不同?在本文中,我们将深入探讨 Agentic AI 的概念、技术原理、

By Ne0inhk
Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测

Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测

1.引言 随着大模型在各类智能应用中的广泛应用,高效的推理硬件成为关键瓶颈。昇腾 NPU(Ascend Neural Processing Unit)凭借其高算力、低能耗以及对 SGLang 的深度优化,能够显著提升大模型推理性能。本文以 Llama 3-8B-Instruct 为例,通过在昇腾 NPU 上的实测,展示其在吞吐量、延迟和资源利用方面的优势,并探索可行的优化策略,为开发者在今后的开发中提供可参考的案例。 在本篇文章中我们会使用到Gitcode的Notebook来进行实战,GitCode Notebook 提供了开箱即用的云端开发环境,支持 Python、SGLang 及昇腾 NPU 相关依赖,无需本地复杂环境配置即可直接运行代码和进行实验。对于没有硬件平台的小伙伴来说是非常便利的。 GitCode Notebook使用链接:https://gitcode.com/user/m0_49476241/notebook。 2.实验环境与准备 2.

By Ne0inhk

Llama-3.2-3B开源部署:ollama部署本地大模型+Grafana实时指标看板

Llama-3.2-3B开源部署:ollama部署本地大模型+Grafana实时指标看板 1. 为什么选Llama-3.2-3B?轻量、多语言、开箱即用的对话专家 你有没有试过在自己电脑上跑一个真正能聊、能写、还能理解多语言的大模型?不是云服务,不是API调用,就是本地运行——不联网、不依赖服务器、响应快、隐私强。Llama-3.2-3B正是这样一款“刚刚好”的模型:它不像70B模型那样吃光显存,也不像百M级小模型那样答非所问。3B参数规模让它能在普通笔记本(甚至MacBook M1/M2)上流畅运行,同时保持对中、英、法、西、德、日等十余种语言的理解与生成能力。 它不是实验室里的玩具。Meta官方明确将Llama 3.2系列定位为“面向真实对话场景优化的指令微调模型”,特别强化了代理式任务(比如帮你查资料再总结)、长文本摘要、多轮上下文理解这些日常高频需求。我们在实测中发现,它对中文技术文档的摘要准确率明显高于同级别开源模型,对带专业术语的提问(如“

By Ne0inhk

零基础指南:学生如何申请和使用GitHub Copilot

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 输入框内输入如下内容: 创建一个面向编程新手的Jupyter Notebook教程,内容包含:1. GitHub Copilot学生认证申请步骤截图;2. 基础Python语法练习(变量、循环、函数);3. 使用Copilot完成简单计算器项目。要求每个步骤都有详细说明和Copilot使用技巧提示。 1. 点击'项目生成'按钮,等待项目生成完整后预览效果 零基础指南:学生如何申请和使用GitHub Copilot 作为一名计算机专业的学生,最近在同学的推荐下尝试了GitHub Copilot这个AI编程助手,发现它真的能大幅提升学习效率。今天就把我的完整使用经验整理出来,特别适合刚接触编程的新手参考。 一、GitHub学生认证申请 1. 首先需要注册GitHub账号,这个步骤很简单,在官网填写基本信息就能完成。记得使用学校邮箱注册,后续认证会更容易通过。

By Ne0inhk