- 创建xml配置文件
<?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-4.3.xsd">
<context:component-scan base-package="com.zj.ioc.demo"></context:component-scan>
</beans>
- 创建People接口
package com.zj.ioc.demo;
interface People {
}
- 创建Student类
package com.zj.ioc.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Student implements People{
@Value("8888")
private Integer id;
@Value("学生")
private String name;
public Student(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Student() {
super();
}
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 创建Teacher类
package com.zj.ioc.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Teacher implements People{
@Value("1001")
private Integer id;
@Value("李四")
private String name;
public Teacher(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
public Teacher() {
super();
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + "]";
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 创建Clazz类
package com.zj.ioc.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Clazz {
@Autowired
private Teacher student;
@Override
public String toString() {
return "Clazz [person=" + student + "]";
}
}
- 创建测试类
package com.zj.ioc.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Clazz p = ac.getBean("clazz",Clazz.class);
System.out.println(p);
}
}
首先我们完成上述步骤,在这里我首先在Clazz类中使用@Autowired注入一个老师对象,
@Autowired
private Teacher student;
我们注意看一下,这个名为student的对象他是Teacher类的对象,而我们在创建Student类的时候也将Student类生成的bean交给Spring管理(bean的默认名为student),那现在有个问题就是@Autowired
它是先byTarget(bean类型)还是byName(bean名字)完成依赖注入呢?
五月 13, 2020 1:49:05 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7e6cbb7a: startup date [Wed May 13 13:49:05 CST 2020]; root of context hierarchy
五月 13, 2020 1:49:05 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Clazz [person=Teacher [id=1001, name=李四]]
从上面运行结果可以看出它是先寻找到对应类型的bean注入,那又又一个问题了,如果有多个类型满足条件@Autowired
会怎么处理呢?
我们将Clazz代码改一下
@Autowired
private People student;
这里Teacher和Student都实现了People接口,意味着Spring容器中有两个bean,一个名为teacher的Teacher类的bean,还有一个名为student的Student类的bean
五月 13, 2020 2:09:20 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7e6cbb7a: startup date [Wed May 13 14:09:20 CST 2020]; root of context hierarchy
五月 13, 2020 2:09:20 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Clazz [person=Student [id=8888, name=学生]]
从上面结果看出,如果存在多个bean的类型满足条件,那@Autowired
会根据bean的id进行寻找。那如果根据name也没找到,那就会报错了喔!就像下面这样
修改Clazz中的代码
@Autowired
private People people;
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.zj.ioc.demo.People' available: expected single matching bean but found 2: student,teacher
报错为找到的bean不唯一。那这就涉及Bean的歧义性问题。这一篇有写
- 我们可以修改Student或者Teacher中某一个的代码,添加
@Primary
注解
@Component
@Primary
public class Student implements People{...}
修改之后再来看一下运行效果:
五月 13, 2020 2:23:11 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7e6cbb7a: startup date [Wed May 13 14:23:11 CST 2020]; root of context hierarchy
五月 13, 2020 2:23:12 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Clazz [person=Student [id=8888, name=学生]]
可以看到成功运行,它找到的bean是我们加上@Primary
注解的Student的bean。
- 我们可以使用限定注解
@Qualifier
,我们修改Clazz中代码:
@Autowired
@Qualifier("student")
private People people;
运行效果如下:
五月 13, 2020 2:26:58 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7e6cbb7a: startup date [Wed May 13 14:26:57 CST 2020]; root of context hierarchy
五月 13, 2020 2:26:58 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Clazz [person=Student [id=8888, name=学生]]
从上面的运行结果看出,这种方法同样可以解决歧义性。
当然我们也可以自定义限定注解:
package com.zj.ioc.demo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
@Target({ElementType.FIELD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface QualifierStudent {
}
修改Student中的代码
@Component
@QualifierStudent
public class Student implements People{...}
修改Clazz中的代码
@Autowired
@QualifierStudent
private People people;
运行结果如下:
五月 13, 2020 2:40:34 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7e6cbb7a: startup date [Wed May 13 14:40:34 CST 2020]; root of context hierarchy
五月 13, 2020 2:40:34 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Clazz [person=Student [id=8888, name=李四]]
可以看到我们同样可以解决。