[Spring实战系列](13)使用注解自动装配

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50644820 1. 简介从Spring2.5开始,我们就可以使用注解的自动装配方式装配Spring Bean的属性。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/50644820

1. 简介

从Spring2.5开始,我们就可以使用注解的自动装配方式装配Spring Bean的属性。使用注解自动装配方式与在XML中使用autowire属性自动装配没有太大区别。那为啥还要研发出这样一种装配方式?肯定有它独特的地方: 使用注解自动装配方式允许更细粒度的自动装配,我们可以选择性的标注某一个属性对其应用自动装配

2. 启用注解装配


Spring容器 默认禁用注解装配。所以,在使用基于注解的自动装配前,我们需要 在Spring配置中启用它。最简单的启用方式是 使用Spring的context命名空间配置的<context:annotation-config>元素

 
   
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
 
</beans>

<context:annotation-config/>元素告诉Spring我们打算使用基于注解的自动装配。一旦装配完成,我们就可以对代码添加注解,表示Spring应该为属性,方法和构造器进行自动装配。

3. 使用@Autowired


 
   
@Autowired
public void setSchool(School school) {
this.school = school;
}

当我们对setSchool()方法使用 @Autowired注解 时,我们可以移除用来定义Student的school属性所对应的<property>元素了。如下面配置文件中的yoona 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
 
<bean id = "yoona" class = "com.sjf.bean.Student">
<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>
 
</beans>

运行结果:

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

在这个实例中,我们对Student的school属性使用 使用 @Autowired注解 ,name属性和age属性使用setter注入方式。 当Spring发现我们对setSchool()方法使用 @Autowired注解 时,Spring就会尝试对该方法 执行byType自动装配 。查询到只有一个Bean(xidianSchool)满足其条件,自动把xidianSchool Bean注入到Student的school属性中。

注意点:

使用了@Autowired注解时,Spring就会尝试对该方法执行byType自动装配

特别之处(不同XML方式):

使用@Autowired注解不只可以使用它标注setter方法,还可以标注需要自动装配Bean引用的任意方法。甚至是构造器,@Autowired注解表示当创建Bean时,即使Spring XML文件中没有使用<constructor-arg>元素配置Bean,该构造器也需要进行自动装配。Spring会从所有满足装配条件的构造器中选择入参最多的那个构造器。还可以标注属性,并可以删除setter方法

(1) 使用@Autowired注解标注setter方法:
 
   
@Autowired
public void setSchool(School school) {
this.school = school;
}
(2)使用@Autowired注解标注属性(不受限于private关键字):
 
   
@Autowired
private School school;
(3)使用@Autowired注解标注任意方法:
 
   
@Autowired
public void assemblySchool(School school) {
this.school = school;
}
(4)使用@Autowired注解标注构造器:
 
   
@Autowired
public Student(School school) {
this.school = school;
}

局限性(同于XML方式):

应用中必须只能有一个Bean适合装配到@Autowired注解所标注的属性或者参数中。如果没有匹配的Bean,或者存在多个匹配的Bean,@Autowired注解就会遇到一些麻烦。
3.1 没有匹配的Bean

如果没有匹配的Bean,@Autowired注解就会失败,抛出 NoSuchBeanDefinitionException 异常

Caused by:  org.springframework.beans.factory.NoSuchBeanDefinitionException
No qualifying bean of type [com.sjf.bean.School] found for dependency: expected 
at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.
raiseNoSuchBeanDefinitionException( DefaultListableBeanFactory.java:1373 )
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.
doResolveDependency( DefaultListableBeanFactory.java:1119 )
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.
resolveDependency( DefaultListableBeanFactory.java:1014 )
    at org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject( AutowiredAnnotationBeanPostProcessor.java:618 )
    ... 15 more  
属性不一定非要装配,null值也是可以接受的。这种情况下,我们可以设置@Autowired的required 属性为false来装配自动装配的是可选的。
 
   
@Autowired(required = false)
public void setSchool(School school) {
this.school = school;
}

在这里,Spring将尝试装配school属性,但是如果没有查找到与之匹配的类型为School的Bean,不会抛出任何异常,并且Student Bean的school属性会设置为null。

注意点:

required属性可以用于@Autowired注解所使用的任意地方。但是当使用构造器装配时,只有一个构造器可以将@Autowired的required属性设置true其他使用@Autowired注解所标注的构造器只能将required属性设置为false
3.2 多个匹配的Bean

另一个问题是可能会有足够多的(至少2个)都满足装配条件,并且都可以被装配到属性或参数中。假如,我们有两个Bean是School类型的,满足装配条件。这种情况下,@Autowired注解没有办法选择哪一个Bean才是它需要的,会抛出 NoUniqueBeanDefinitionException 异常。

 
   
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
 
<bean id = "yoona" class = "com.sjf.bean.Student">
<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>
抛出异常:
Caused by:  org.springframework.beans.factory.NoUniqueBeanDefinitionException
No qualifying bean of type [com.sjf.bean.School] is defined: expected single matching bean but found 2: xidianSchool,shandaSchool
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency( DefaultListableBeanFactory.java:1126 )
  at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency( DefaultListableBeanFactory.java:1014 )
  at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.
inject( AutowiredAnnotationBeanPostProcessor.java:618 )
  ... 15 more

为了帮助@Autowired鉴别出哪一个Bean才是我们所需要的,我们可以配合使用Spring的 @Qualifier注解。
 
   
@Autowired
@Qualifier("shandaSchool")
public void setSchool(School school) {
this.school = school;
}
这样,我们就使用@Qualifier注解尝试注入ID为"shandaSchool"的Bean。表面上看,把@Autowired的byType自动装配转换为显示的byName装配。实际只是使用 @Qualifier注解缩小了自动装配挑选候选Bean的范围。上例中通过指定Bean 的ID把选择范围缩小到只剩一个Bean。

除了通过Bean的ID缩小选择范围,还可以通过在Bean上直接使用qualifier来缩小范围。
 
   
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
 
<bean id = "yoona" class = "com.sjf.bean.Student">
<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="西安"/>
<qualifier value="ShanXi"/>
</bean>
 
<bean id = "shandaSchool" class = "com.sjf.bean.School">
<property name="name" value="山东大学"/>
<property name="location" value="山东"/>
<qualifier value="ShanDong"/>
</bean>
</beans>
这里,限定shandongSchool Bean是山东地区的大学,xidianSchool Bean是陕西地区的大学。
 
   
@Autowired
@Qualifier("ShanXi")
public void setSchool(School school) {
this.school = school;
}

运行结果:

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

这里通过指定@Qualifier属性为"ShanXi",把选择范围缩小到只剩一个Bean(xidianSchool)。


4. 在注解注入中使用表达式

既然可以使用注解为Spring的Bean自动装配其他Bean的引用,我们同样希望能够 使用注解装配简单的值。Spring3.0 引入了 @Value,它是一个新的装配注解。可以让我们使用注解装配String类型的值和基本类型的值,例如int,boolean。可以 通过@Value直接标注某个属性,方法或者方法参数,并传入一个String类型的表达式来装配属性
 
   
@Value("yoona")
private String name;
在这里,我们为String类型的属性装配了一个String类型的值。但是传入@Value的String类型的参数只是一个表达式,它的计算结果可以是任意类型,因此@Value能够标注任意类型的属性。

实际上,装配简单值,不是@Value的主要作用,它可以借助SEL表达式,作用更加突出。我们知道运行期可以通过 SpEL动态计算复杂表达式的值并把结果装配到Bean的属性中。这一特性也使得 @Value注解成为强大的装配可选方案。

 
   
@Value("#{systemProperties.myFavoriteSong}")
private String song;
在这个例子中,我们使用SpEL从系统属性中获取一个值。



参考:《Spring实战》



目录
相关文章
|
24天前
|
人工智能 搜索推荐 Java
Spring AI与DeepSeek实战三:打造企业知识库
本文基于Spring AI与RAG技术结合,通过构建实时知识库增强大语言模型能力,实现企业级智能搜索场景与个性化推荐,攻克LLM知识滞后与生成幻觉两大核心痛点。
231 7
|
2月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
218 26
|
10天前
|
存储 人工智能 Java
Spring AI与DeepSeek实战四:系统API调用
在AI应用开发中,工具调用是增强大模型能力的核心技术,通过让模型与外部API或工具交互,可实现实时信息检索(如天气查询、新闻获取)、系统操作(如创建任务、发送邮件)等功能;本文结合Spring AI与大模型,演示如何通过Tool Calling实现系统API调用,同时处理多轮对话中的会话记忆。
226 57
|
15天前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
76 5
|
1月前
|
JSON 前端开发 Java
Spring MVC常用的注解
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中 的所有响应请求的方法都是以该地址作为父路径。 @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。 @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。 @Controller:控制器的注解,表示是表现层,不能用用别的注解代替 @RestController : 组合注解 @Conntroller + @ResponseBody @GetMapping , @PostMapping , @Put
|
1月前
|
Java Spring
Spring Boot的核心注解是哪个?他由哪几个注解组成的?
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 : ● @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能; ● @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项 ● @ComponentScan:Spring组件扫描
|
1月前
|
Java 测试技术 Spring
SpringBoot+@Async注解一起用,速度提升
本文介绍了异步调用在高并发Web应用性能优化中的重要性,对比了同步与异步调用的区别。同步调用按顺序执行,每一步需等待上一步完成;而异步调用无需等待,可提升效率。通过Spring Boot示例,使用@Async注解实现异步任务,并借助Future对象处理异步回调,有效减少程序运行时间。
|
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)
212 11
|
21天前
|
人工智能 缓存 自然语言处理
保姆级Spring AI 注解式开发教程,你肯定想不到还能这么玩!
这是一份详尽的 Spring AI 注解式开发教程,涵盖从环境配置到高级功能的全流程。Spring AI 是 Spring 框架中的一个模块,支持 NLP、CV 等 AI 任务。通过注解(如自定义 `@AiPrompt`)与 AOP 切面技术,简化了 AI 服务集成,实现业务逻辑与 AI 基础设施解耦。教程包含创建项目、配置文件、流式响应处理、缓存优化及多任务并行执行等内容,助你快速构建高效、可维护的 AI 应用。
|
1月前
|
人工智能 Java API
Spring AI与DeepSeek实战一:快速打造智能对话应用
在 AI 技术蓬勃发展的今天,国产大模型DeepSeek凭借其低成本高性能的特点,成为企业智能化转型的热门选择。而Spring AI作为 Java 生态的 AI 集成框架,通过统一API、简化配置等特性,让开发者无需深入底层即可快速调用各类 AI 服务。本文将手把手教你通过spring-ai集成DeepSeek接口实现普通对话与流式对话功能,助力你的Java应用轻松接入 AI 能力!虽然通过Spring AI能够快速完成DeepSeek大模型与。
531 11