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开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/27196d04d28779f5da4dbbab10bfcef3.jpeg)
最后
现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
UZNiick-1713543179085)]
[外链图片转存中…(img-KFCfRySb-1713543179089)]
[外链图片转存中…(img-GQqXmWCI-1713543179092)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/27196d04d28779f5da4dbbab10bfcef3.jpeg)
最后
现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**
[外链图片转存中…(img-70j1zXwv-1713543179093)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!