[Spring实战系列](12)Bean的自动装配

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50642816 Spring提供了4种各具特色的自动装配策略: 类型 说明 no 默认方式,Bean的引用必须通过XML文件中的元素或者ref属性手动设定。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50642816
Spring提供了4种各具特色的自动装配策略:

类型 说明
no 默认方式,Bean的引用必须通过XML文件中的</ref>元素或者ref属性手动设定。
byName 把与Bean的属性具有相同名字(ID)的其他Bean自动装配到Bean对应属性中。如果没有跟属性的名字相匹配的Bean,则该属性不进行匹配。
byType 把与Bean的属性具有相同类型的其他Bean自动装配到Bean对应属性中。如果没有跟属性的类型相匹配的Bean,则该属性不进行匹配。
constructor 把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器对应入中。

 
    
package com.sjf.bean;
/**
* 学生实体类
* @author sjf0115
*
*/
public class Student {
private String name;
private int age;
private School school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("name:" + name + " age:" + age );
if(school != null){
sb.append(" school:" + school.getName() + "[" + school.getLocation() + "]");
}//if
return sb.toString();
}
}

 
    
package com.sjf.bean;
/**
* 学校实体类
* @author sjf0115
*
*/
public class School {
private String name;
private String location;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
@Override
public String toString() {
return "name:" + name + " location:" + location;
}
}

1. no

这是Spring的默认情况,不自动装配。Bean的引用必须通过XML文件中的</ref>元素或者ref属性手动设定。大多数情况下我们推荐使用这种方式,因为这种方式使文档更加明确简洁。

2. byName 


这种情况,Bean 设置 autowire属性为"byName",Spring会自动寻找与属性名字相同的bean(即寻找某些Bean,其id必须同该属性名字相同),找到后,通过调用setXXX方法将其注入属性。

 
   
<?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">
<bean id = "yoona" class = "com.sjf.bean.Student" autowire="byName">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
</bean>
<bean id = "school" class="com.sjf.bean.School">
<property name="name" value="西安电子科技大学"/>
<property name="location" value="西安"/>
</bean>
</beans>

运行:

name:yoona   age:24   school:西安电子科技大学[西安]

在这个实例中yoona Bean的school属性名字 与 School Bean( 西安电子科技大学 )的 id 属性是一样的。通过配置autowire属性,Spring就可以利用此信息自动装配yoona的school属性。

约定:

为属性自动装配ID与该属性的名字相同的Bean。通过设置autowire的属性为"byName",Spring将特殊对待 Bean的所有属性,为这些属性查找与其名字相同的Spring Bean。因为id具有唯一性,所以不可能存在有多个Bean 的id与其属性名字相同而造成冲突的情况。根据byName自动装配结果是要么找到一个Bean,要么一个也找不到。

缺点:

必须假设Bean的名字(ID)与其他Bean的属性的名字一样。


假设我们下面bean名字(id)改成"school1",这样就与yoona Bean的school属性名字不一样,school属性就得不到装配。
 
   
<bean id = "school1" class="com.sjf.bean.School">
<property name="name" value="西安电子科技大学"/>
<property name="location" value="西安"/>
</bean>

3. byType


byType自动装配的工作方式类似于byName自动装配,只不过不再是匹配属性的名字而是检查属性的类型。当我们尝试使用byType自动装配时,Spring会寻找哪一个Bean的类型与属性的类型匹配找到后,通过调用setXXX方法将其注入。

对于上面那个把Bean的名字(id)改成"school1"的情况,byName已经不能寻找到相应的Bean。在这里我们 设置 autowire属性为"byType"。
 
   
<?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">
<bean id = "yoona" class = "com.sjf.bean.Student" autowire="byType">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
</bean>
<bean id = "school1" class="com.sjf.bean.School">
<property name="name" value="西安电子科技大学"/>
<property name="location" value="西安"/>
</bean>
</beans>

运行:

name:yoona   age:24   school:西安电子科技大学[西安]

在这个实例中 我们 设置 autowire属性为"byType",Spring容器会寻找哪一个Bean的类型与school属性的类型匹配。如果匹配就把Bean 装配到yoona的属性中去。school1 Bean(西安电子科技大学)将自动被装配到yoona的school属性中,因为school属性的类型与school1 Bean的类型都是com.sjf.bean.School类型。

局限性:

如果Spring寻找到多个Bean,它们的类型与需要自动装配的属性的类型都能匹配,它不会智能的挑选一个,则会抛出异常。所以,应用中只允许存在一个Bean与需要自动装配的属性类型相匹配。

 
   
<?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">
<bean id = "yoona" class = "com.sjf.bean.Student" autowire="byType">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
</bean>
<bean id = "xidianSchool" class="com.sjf.bean.School">
<property name="name" value="西安电子科技大学"/>
<property name="location" value="西安"/>
</bean>
<bean id = "shandaSchool" class="com.sjf.bean.School">
<property name="name" value="山东大学"/>
<property name="location" value="山东"/>
</bean>
</beans>
假如说,XML中出现了上述情况:有两个Bean与需要自动装配的属性的类型相匹配,则会抛出异常:

No qualifying bean of type [com.sjf.bean.School] is defined: expected single matching bean but found 2: xidianSchool,shandaSchool  

应对措施:

为了避免因为使用byType自动装配而带来的歧义,Spring为我们提供了两种选择:可以为自动装配标示一个首选Bean,或者可以取消某个Bean自动装配的候选资格。
3.1 标示首先Bean

为自动装配标示一个首先Bean,可以使用<bean>元素的 primary属性。如果 只有一个自动装配的候选Bean的primary属性为true,那么该Bean将比其他候选Bean优先被选择。
 
   
<?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">
<bean id = "yoona" class = "com.sjf.bean.Student" autowire="byType">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
</bean>
<bean id = "xidianSchool" class="com.sjf.bean.School" primary="false">
<property name="name" value="西安电子科技大学"/>
<property name="location" value="西安"/>
</bean>
<bean id = "shandaSchool" class="com.sjf.bean.School" primary="true">
<property name="name" value="山东大学"/>
<property name="location" value="山东"/>
</bean>
</beans>

运行结果:

name:yoona   age:24   school:山东大学[山东]

诧异点:

primary属性很怪异的一点是:它的默认设置为true。意思就是说自动装配的所有的候选Bean都是首选Bean。所以,为了使用primary属性,我们不得不把所有的非首选的Bean的primary属性设置为false。
3.2 取消Bean自动装配候选资格

为取消某个Bean的自动装配的候选资格,可以使用<bean>元素的 autowire-candidate属性。如果我们希望排除某些Bean,可以设置这些Bean的autowire-candidate属性为false。
 
   
<?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">
<bean id = "yoona" class = "com.sjf.bean.Student" autowire="byType">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
</bean>
<bean id = "xidianSchool" class="com.sjf.bean.School" >
<property name="name" value="西安电子科技大学"/>
<property name="location" value="西安"/>
</bean>
<bean id = "shandaSchool" class="com.sjf.bean.School" autowire-candidate="false">
<property name="name" value="山东大学"/>
<property name="location" value="山东"/>
</bean>
</beans>

运行结果:

name:yoona   age:24   school:西安电子科技大学[西安]

4. constructor 自动装配


Course实体类:
 
   
package com.sjf.bean;
 
public class Course {
private String name;
private double score;
private Student student;
public Course(Student student) {
this.student = student;
}
public String getName() {
return name;
}
 
public void setName(String name) {
this.name = name;
}
 
public double getScore() {
return score;
}
 
public void setScore(double score) {
this.score = score;
}
 
public Student getStudent() {
return student;
}
 
public void setStudent(Student student) {
this.student = student;
}
 
@Override
public String toString() {
return "courseName:" + name + " score:" + score + " student:" + (student != null ? student.getName() : "null");
}
}

如果通过构造器注入来配置Bean,那么我们可以移除<constructor-arg>元素,由Spring在应用上下文中自动选择Bean注入到构造器入参中。
 
   
<bean id = "course" class = "com.sjf.bean.Course" autowire="constructor">
<property name="name" value="英语"/>
<property name="score" value="91"/>
</bean>
 
<bean id = "yoona" class = "com.sjf.bean.Student">
<property name="name" value="yoona"/>
<property name="age" value="24"/>
</bean>

运行结果:

courseName:英语   score:91.0   student:yoona  

在这个实例中,我们对name属性和score属性通过setter方式注入,student属性通过构造器方式注入。在course Bean的声明中,<constructor-arg>元素不见了(对于student属性),而autowire属性设置为"constructor"。这样的话, Spring会去审视Course的构造器,并尝试在Spring配置中寻找匹配Course 某一构造器所有参数 的Bean。我们定义了一个yoona Bean,它正好与Course 中的一个构造器参数相匹配。因此,当构造 course Bean时,Spring使用这个构造器,并把yoona Bean作为入参传入。

局限性:

和byType自动装配有相同的局限性。当发现多个Bean匹配某个构造器入参时,Spring不会尝试猜测哪一个Bean更适合自动装配。此外,如果一个类有多个构造器,它们都满足自动装配的条件时,Spring也不会尝试哪一个构造器更适合使用

注意:

当使用constructor自动装配策略时,我们必须让Spring自动装配构造器中的所有入参,我们不能混合使用constructor自动装配策略和<constructor-arg>元素

5. 最佳自动装配(Spring3 报错 估计弃用了)


如果想自动装配Bean,但是又不能决定使用哪一种类型的自动装配。我们可以设置autowire属性为autodetect,交由Spring决定。

6. 默认自动装配 default-autowire


如果需要为Spring应用上下文中的每一个Bean(或者其中的大多数)都配置相同的autowire属性,那么就可以要求Spring为它所创建的所有Bean应用相同的自动装配策略来简化配置。只需要在<beans>元素上增加一个default-autowire属性:
 
   
<?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"
default-autowire="byName">
</beans>

默认情况下 default-autowire属性设置为none,表示所有的Bean都不使用自动装配策略,除非Bean自己配置了autowire属性。在这里我们把 default-autowire设置为byName,即希望每一个Bean的所有属性都是用byName的自动装配策略进行自动装配。

注意:

不能因为我们配置了一个默认的自动装配策略,就意味着所有的Bean只能使用这个默认的自动装配策略。我们还可以使用<bean>元素的autowire属性来覆盖<beans>元素所配置的默认自动装配策略。



参考:《Spring实战》


 
    
package com.sjf.bean;
/**
* 学生实体类
* @author sjf0115
*
*/
public class Student {
private String name;
private int age;
private School school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("name:" + name + " age:" + age );
if(school != null){
sb.append(" school:" + school.getName() + "[" + school.getLocation() + "]");
}//if
return sb.toString();
}
}

 
    
package com.sjf.bean;
/**
* 学校实体类
* @author sjf0115
*
*/
public class School {
private String name;
private String location;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
@Override
public String toString() {
return "name:" + name + " location:" + location;
}
}
目录
相关文章
|
29天前
|
人工智能 搜索推荐 Java
Spring AI与DeepSeek实战三:打造企业知识库
本文基于Spring AI与RAG技术结合,通过构建实时知识库增强大语言模型能力,实现企业级智能搜索场景与个性化推荐,攻克LLM知识滞后与生成幻觉两大核心痛点。
256 7
|
19天前
|
安全 Java 数据库
Spring Security 实战指南:从入门到精通
本文详细介绍了Spring Security在Java Web项目中的应用,涵盖登录、权限控制与安全防护等功能。通过Filter Chain过滤器链实现请求拦截与认证授权,核心组件包括AuthenticationProvider和UserDetailsService,负责用户信息加载与密码验证。文章还解析了项目结构,如SecurityConfig配置类、User实体类及自定义登录逻辑,并探讨了Method-Level Security、CSRF防护、Remember-Me等进阶功能。最后总结了Spring Security的核心机制与常见配置,帮助开发者构建健壮的安全系统。
107 0
|
2月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
227 26
|
15天前
|
存储 人工智能 Java
Spring AI与DeepSeek实战四:系统API调用
在AI应用开发中,工具调用是增强大模型能力的核心技术,通过让模型与外部API或工具交互,可实现实时信息检索(如天气查询、新闻获取)、系统操作(如创建任务、发送邮件)等功能;本文结合Spring AI与大模型,演示如何通过Tool Calling实现系统API调用,同时处理多轮对话中的会话记忆。
256 57
|
20天前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
94 5
|
1月前
|
人工智能 自然语言处理 前端开发
Spring AI与DeepSeek实战二:打造企业级智能体
本文介绍如何基于Spring AI与DeepSeek模型构建企业级多语言翻译智能体。通过明确的Prompt设计,该智能体能自主执行复杂任务,如精准翻译32种ISO标准语言,并严格遵循输入格式和行为限制。代码示例展示了如何通过API实现动态Prompt生成和翻译功能,确保服务的安全性和可控性。项目已开源,提供更多细节和完整代码。 [GitHub](https://github.com/zlt2000/zlt-spring-ai-app) | [Gitee](https://gitee.com/zlt2000/zlt-spring-ai-app)
224 11
|
1月前
|
人工智能 Java API
Spring AI与DeepSeek实战一:快速打造智能对话应用
在 AI 技术蓬勃发展的今天,国产大模型DeepSeek凭借其低成本高性能的特点,成为企业智能化转型的热门选择。而Spring AI作为 Java 生态的 AI 集成框架,通过统一API、简化配置等特性,让开发者无需深入底层即可快速调用各类 AI 服务。本文将手把手教你通过spring-ai集成DeepSeek接口实现普通对话与流式对话功能,助力你的Java应用轻松接入 AI 能力!虽然通过Spring AI能够快速完成DeepSeek大模型与。
546 11
|
2月前
|
JavaScript 前端开发 Java
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300%的秘密武器
Jeesite5 是一个基于 Spring Boot 3.3 和 Vue3 的企业级快速开发平台,集成了众多优秀开源项目,如 MyBatis Plus、Bootstrap、JQuery 等。它提供了模块化设计、权限管理、多数据库支持、代码生成器和国际化等功能,极大地提高了企业级项目的开发效率。Jeesite5 广泛应用于企业管理系统、电商平台、客户关系管理和知识管理等领域。通过其强大的功能和灵活性,Jeesite5 成为了企业级开发的首选框架之一。访问 [Gitee 页面](https://gitee.com/thinkgem/jeesite5) 获取更多信息。
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300%的秘密武器
|
4月前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
115 12
|
4月前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
110 12
下一篇
oss创建bucket