【Spring注解驱动开发】使用@Autowired@Qualifier@Primary三大注解自动装配组件,你会了吗?

本文详细介绍了Spring框架中@Autowired注解的使用,包括在Service和Controller中注入依赖,以及如何控制自动装配的行为,如优先级和特定组件的选择。作者还展示了如何处理多实例组件和使用@Qualifier注解进行精确装配。
摘要由CSDN通过智能技术生成

package io.mykit.spring.plugins.register.service;

import io.mykit.spring.plugins.register.dao.PersonDao;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试的Service

*/

@Service

public class PersonService {

@Autowired

private PersonDao personDao;

}

  • controller

package io.mykit.spring.plugins.register.controller;

import org.springframework.stereotype.Controller;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试的controller

*/

@Controller

public class PersonController {

@Autowired

private PersonService personService;

}

可以看到,我们在Service中使用@Autowired注解注入了Dao,在Controller中使用@Autowired注解注入了Service。为了方便测试,我们在PersonService类中生成一个toString()方法,如下所示。

package io.mykit.spring.plugins.register.service;

import io.mykit.spring.plugins.register.dao.PersonDao;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试的Service

*/

@Service

public class PersonService {

@Autowired

private PersonDao personDao;

@Override

public String toString() {

return personDao.toString();

}

}

这里,我们在PersonService类的toString()方法中直接调用personDao的toString()方法并返回。为了更好的演示效果,我们在项目的 io.mykit.spring.plugins.register.config 包下创建AutowiredConfig类,如下所示。

package io.mykit.spring.plugins.register.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试自动装配组件的Config配置类

*/

@Configuration

@ComponentScan(value = {

“io.mykit.spring.plugins.register.dao”,

“io.mykit.spring.plugins.register.service”,

“io.mykit.spring.plugins.register.controller”})

public class AutowiredConfig {

}

接下来,我们来测试一下上面的程序,我们在项目的src/test/java目录下的 io.mykit.spring.test 包下创建AutowiredTest类,如下所示。

package io.mykit.spring.test;

import io.mykit.spring.plugins.register.config.AutowiredConfig;

import io.mykit.spring.plugins.register.service.PersonService;

import org.junit.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试自动装配

*/

public class AutowiredTest {

@Test

public void testAutowired01(){

//创建IOC容器

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);

PersonService personService = context.getBean(PersonService.class);

System.out.println(personService);

context.close();

}

}

测试方法比较简单,这里,我就不做过多说明了。接下来,我们运行AutowiredTest类的testAutowired01()方法,得出的输出结果信息如下所示。

io.mykit.spring.plugins.register.dao.PersonDao@10e92f8f

可以看到,输出了PersonDao信息。

那么问题来了:我们在PersonService类中输出的PersonDao,和我们直接在Spring IOC容器中获取的PersonDao是不是同一个对象呢?

我们可以在AutowiredTest类的testAutowired01()方法中添加获取PersonDao对象的方法,并输出获取到的PersonDao对象,如下所示。

@Test

public void testAutowired01(){

//创建IOC容器

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);

PersonService personService = context.getBean(PersonService.class);

System.out.println(personService);

PersonDao personDao = context.getBean(PersonDao.class);

System.out.println(personDao);

context.close();

}

我们再次运行AutowiredTest类的testAutowired01()方法,输出的结果信息如下所示。

io.mykit.spring.plugins.register.dao.PersonDao@10e92f8f

io.mykit.spring.plugins.register.dao.PersonDao@10e92f8f

可以看到,我们在PersonService类中输出的PersonDao对象和直接从IOC容器中获取的PersonDao对象是同一个对象。

如果在Spring容器中存在对多个PersonDao对象该如何处理呢?

首先,为了更加直观的看到我们使用@Autowired注解装配的是哪个PersonDao对象,我们对PersonDao类进行改造,为其加上一个remark字段,为其赋一个默认值,如下所示。

package io.mykit.spring.plugins.register.dao;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import org.springframework.stereotype.Repository;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试的dao

*/

@Data

@NoArgsConstructor

@AllArgsConstructor

@Repository

public class PersonDao {

private String remark = “1”;

}

接下来,我们就在AutowiredConfig类中注入一个PersonDao对象,并且显示指定PersonDao对象在IOC容器中的bean的名称为personDao2,并为PersonDao对象的remark字段赋值为2,如下所示。

@Bean(“personDao2”)

public PersonDao personDao(){

return new PersonDao(“2”);

}

目前,在我们的IOC容器中就会注入两个PersonDao对象。那此时,@Autowired注解装配的是哪个PersonDao对象呢?

接下来,我们运行AutowiredTest类的testAutowired01()方法,输出的结果信息如下所示。

PersonDao{remark=‘1’}

可以看到,结果信息输出了1,说明:@Autowired注解默认优先按照类型去容器中找对应的组件,找到就赋值;如果找到多个相同类型的组件,再将属性名称作为组件的id,到 IOC 容器中进行查找。

那我们如何让@Autowired装配personDao2呢? 这个问题问的好,其实很简单,我们将PersonService类中的personDao全部修改为personDao2,如下所示。

package io.mykit.spring.plugins.register.service;

import io.mykit.spring.plugins.register.dao.PersonDao;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试的Service

*/

@Service

public class PersonService {

@Autowired

private PersonDao personDao2;

@Override

public String toString() {

return personDao2.toString();

}

}

此时,我们再次运行AutowiredTest类的testAutowired01()方法,输出的结果信息如下所示。

PersonDao{remark=‘2’}

可以看到,此时命令行输出了personDao2的信息。

测试@Qualifier注解

从测试@Autowired注解的结果来看:@Autowired注解默认优先按照类型去容器中找对应的组件,找到就赋值;如果找到多个相同类型的组件,再将属性名称作为组件的id,到 IOC 容器中进行查找。

如果IOC容器中存在多个相同类型的组件时,我们可不可以显示指定@Autowired注解装配哪个组件呢?有些小伙伴肯定会说:废话!你都这么问了,那肯定可以啊!没错,确实可以啊!此时,@Qualifier注解就派上用场了!

在之前的测试案例中,命令行输出了 PersonDao{remark='2'} 说明@Autowired注解装配了personDao2,那我们如何显示的让@Autowired注解装配personDao呢?

比较简单,我们只需要在PersonService类上personDao2字段上添加@Qualifier注解,显示指定@Autowired注解装配personDao,如下所示。

@Qualifier(“personDao”)

@Autowired

private PersonDao personDao2;

此时,我们再次运行AutowiredTest类的testAutowired01()方法,输出的结果信息如下所示。

PersonDao{remark=‘1’}

可以看到,此时尽管字段的名称为personDao2,但是我们使用了@Qualifier注解显示指定@Autowired注解装配personDao对象,所以,最终的结果输出了personDao对象的信息。

测试容器中无组件的情况

如果IOC容器中无相应的组件,会发生什么情况呢?此时,我们删除PersonDao类上的@Repository注解,并且删除AutowiredConfig类中的personDao()方法上的@Bean注解,如下所示。

package io.mykit.spring.plugins.register.dao;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试的dao

*/

public class PersonDao {

private String remark = “1”;

public String getRemark() {

return remark;

}

public void setRemark(String remark) {

this.remark = remark;

}

@Override

public String toString() {

return “PersonDao{” +

“remark='” + remark + ‘’’ +

‘}’;

}

}

package io.mykit.spring.plugins.register.config;

import io.mykit.spring.plugins.register.dao.PersonDao;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

/**

  • @author binghe

  • @version 1.0.0

  • @description 测试自动装配组件的Config配置类

*/

@Configuration

@ComponentScan(value = {

“io.mykit.spring.plugins.register.dao”,

“io.mykit.spring.plugins.register.service”,

“io.mykit.spring.plugins.register.controller”})

public class AutowiredConfig {

public PersonDao personDao(){

PersonDao personDao = new PersonDao();

personDao.setRemark(“2”);

return personDao;

}

}

此时IOC容器中不再有personDao,我们再次运行AutowiredTest类的testAutowired01()方法,输出的结果信息如下所示。

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘io.mykit.spring.plugins.register.dao.PersonDao’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=personDao), @org.springframework.beans.factory.annotation.Autowired(required=true)}

可以看到,Spring抛出了异常,未找到相应的bean对象,我们能不能让Spring不报错呢? 那肯定可以啊!Spring的异常信息中都给出了相应的提示。

{@org.springframework.beans.factory.annotation.Qualifier(value=personDao), @org.springframework.beans.factory.annotation.Autowired(required=true)}

解决方案就是在PersonService类的@Autowired添加一个属性required=false,如下所示。

@Qualifier(“personDao”)

@Autowired(required = false)

private PersonDao personDao2;

并且我们修改下PersonService的toString()方法,如下所示。

@Override

public String toString() {

return “PersonService{” +

“personDao2=” + personDao2 +

‘}’;

}

此时,还需要将AutowiredTest类的testAutowired01()方法中直接从IOC容器中获取personDao的代码删除,如下所示。

@Test

public void testAutowired01(){

//创建IOC容器

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);

PersonService personService = context.getBean(PersonService.class);

System.out.println(personService);

context.close();

}

此时,我们再次运行AutowiredTest类的testAutowired01()方法,输出的结果信息如下所示。

PersonService{personDao2=null}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**

image
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
UZNiick-1713543179085)]

[外链图片转存中…(img-KFCfRySb-1713543179089)]

[外链图片转存中…(img-GQqXmWCI-1713543179092)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**

[外链图片转存中…(img-70j1zXwv-1713543179093)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值