import com.javacode2018.lesson001.demo5.IocUtils;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class DiAutowireTest {
/**
- 按照名称进行注入
*/
@Test
public void diAutowireByName() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByName.xml”;
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean(“diAutowireByName”));
}
}
效果
运行diAutowireByName输出:
setService1->Service1{desc=‘service1’}
setService2->Service2{desc=‘service2’}
setService2->Service2{desc=‘service2-1’}
setService1->Service1{desc=‘service1’}
DiAutowireByName{service1=Service1{desc=‘service1’}, service2=Service2{desc=‘service2’}}
DiAutowireByName{service1=Service1{desc=‘service1’}, service2=Service2{desc=‘service2-1’}}
优缺点
按名称进行注入的时候,要求名称和set属性的名称必须同名,相对于硬编码的方式注入,确实节省了不少代码。
按照类型进行自动注入
用法
autowire设置为byType
spring容器会遍历x类中所有的set方法,会在容器中查找和set参数类型相同的bean对象,将其通过set方法进行注入,未找到对应类型的bean对象则set方法不进行注入。
需要注入的set属性的类型和被注入的bean的类型需要满足isAssignableFrom关系。
按照类型自动装配的时候,如果按照类型找到了多个符合条件的bean,系统会报错。
set方法的参数如果是下面的类型或者下面类型的数组的时候,这个set方法会被跳过注入:
Object,Boolean,boolean,Byte,byte,Character,char,Double,double,Float,float,Integer,int,Long,Short,shot,Enum,CharSequence,Number,Date,java.time.temporal.Temporal,java.net.URI,java.net.URI,java.util.Locale,java.lang.Class
来看看案例吧。
案例
DiByType.java
package com.javacode2018.lesson001.demo6;
/**
- 按照类型自动注入
*/
public class DiAutowireByType {
public static class Service1 {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return “Service1{” +
“desc='” + desc + ‘’’ +
‘}’;
}
}
public static class Service2 {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return “Service2{” +
“desc='” + desc + ‘’’ +
‘}’;
}
}
private Service1 service1;
private Service2 service2;
public Service1 getService1() {
return service1;
}
public void setService1(Service1 service1) {
System.out.println(“setService1->” + service1); //@1
this.service1 = service1;
}
public Service2 getService2() {
return service2;
}
public void setService2(Service2 service2) {
System.out.println(“setService2->” + service2); //@2
this.service2 = service2;
}
@Override
public String toString() {
return “DiByType{” +
“service1=” + service1 +
“, service2=” + service2 +
‘}’;
}
}
DiAutowireByType类中有2个set方法分别来注入Service1和Service2,两个set方法中都输出了一行文字,一会执行的时候可以通过这个输出可以看出set方法是否被调用了。
diAutowireByName.xml
<?xml version="1.0" encoding="UTF-8"?>上面注释认真看一下。
@1:定义了一个名称为service1的bean
@2:定义了一个名称为service2的bean
@3:定义diAutowireByName需要将autowire的值置为byName,表示按名称进行自动注入。
spring容器创建diAutowireByName对应的bean时,会遍历DiAutowireByName类中的所有set方法,然后得到set对应的属性名称列表:{“service1”,“service2”},然后遍历这属性列表,在容器中查找和属性同名的bean对象,然后调用属性对应的set方法,将bean对象注入进去
测试用例
DiAutowireTest类中添加一个方法
/**
- 按照set方法参数类型进行注入
*/
@Test
public void diAutowireByType() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByType.xml”;
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean(“diAutowireByType1”));
}
效果
运行diAutowireByType输出:
setService1->Service1{desc=‘service1’}
setService2->Service2{desc=‘service2’}
DiByType{service1=Service1{desc=‘service1’}, service2=Service2{desc=‘service2’}}
优缺点
相对于手动注入,节省了不少代码,新增或者删除属性,只需要增减对应的set方法就可以了,更容易扩展了。
注入类型匹配的所有bean(重点)
按照类型注入还有2中比较牛逼的用法:
一个容器中满足某种类型的bean可以有很多个,将容器中某种类型中的所有bean,通过set方法注入给一个java.util.List<需要注入的Bean的类型或者其父类型或者其接口>对象
将容器中某种类型中的所有bean,通过set方法注入给一个java.util.Map<String,需要注入的Bean的类型或者其父类型或者其接口>对象
来看个案例就懂了。
DiAutowireByTypeExtend.java
package com.javacode2018.lesson001.demo6;
import java.util.List;
import java.util.Map;
/**
- 满足条件的bean注入到集合中(重点)
*/
public class DiAutowireByTypeExtend {
//定义了一个接口
public interface IService1 {
}
public static class BaseServie {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return “BaseServie{” +
“desc='” + desc + ‘’’ +
‘}’;
}
}
//Service1实现了IService1接口
public static class Service1 extends BaseServie implements IService1 {
}
//Service1实现了IService1接口
public static class Service2 extends BaseServie implements IService1 {
}
private List serviceList;//@1
private List baseServieList;//@2
private Map<String, IService1> service1Map;//@3
private Map<String, BaseServie> baseServieMap;//@4
public List getServiceList() {
return serviceList;
}
public void setServiceList(List serviceList) {//@5
this.serviceList = serviceList;
}
public List getBaseServieList() {
return baseServieList;
}
public void setBaseServieList(List baseServieList) {//@6
this.baseServieList = baseServieList;
}
public Map<String, IService1> getService1Map() {
return service1Map;
}
public void setService1Map(Map<String, IService1> service1Map) {//@7
this.service1Map = service1Map;
}
public Map<String, BaseServie> getBaseServieMap() {
return baseServieMap;
}
public void setBaseServieMap(Map<String, BaseServie> baseServieMap) {//@8
this.baseServieMap = baseServieMap;
}
@Override
public String toString() { //9
return “DiAutowireByTypeExtend{” +
“serviceList=” + serviceList +
“, baseServieList=” + baseServieList +
“, service1Map=” + service1Map +
“, baseServieMap=” + baseServieMap +
‘}’;
}
}
@1,@2,@3,@4:定义了4个属性,都是泛型类型的,都有对应的set方法。
@5:参数类型是List,这个集合集合中元素的类型是BaseServie,spring会找到容器中所有满足BaseServie.isAssignableFrom(bean的类型)的bean列表,将其通过@5的set方法进行注入。
@6:同@5的代码
@7:这个参数类型是一个map了,map的key是string类型,value是IService1类型,spring容器会将所有满足IService1类型的bean找到,按照name->bean对象这种方式丢到一个map中,然后调用@7的set方法进行注入,最后注入的这个map就是bean的名称和bean对象进行映射的一个map对象。
@8:同@7的代码
@9:重写了toString方法,输出的时候好看一些
测试用例
DiAutowireTest新增一个方法:
/**
- 按照类型注入集合
*/
@Test
public void diAutowireByTypeExtend() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByTypeExtend.xml”;
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
//从容器中获取DiAutowireByTypeExtend
DiAutowireByTypeExtend diAutowireByTypeExtend = context.getBean(DiAutowireByTypeExtend.class);
//输出diAutowireByTypeExtend中的属性看一下
System.out.println(“serviceList:” + diAutowireByTypeExtend.getServiceList());
System.out.println(“baseServieList:” + diAutowireByTypeExtend.getBaseServieList());
System.out.println(“service1Map:” + diAutowireByTypeExtend.getService1Map());
System.out.println(“baseServieMap:” + diAutowireByTypeExtend.getBaseServieMap());
}
效果
运行diAutowireByTypeExtend输出:
serviceList:[BaseServie{desc=‘service1-1’}, BaseServie{desc=‘service1-2’}, BaseServie{desc=‘service2-1’}]
baseServieList:[BaseServie{desc=‘service1-1’}, BaseServie{desc=‘service1-2’}, BaseServie{desc=‘service2-1’}]
service1Map:{service1-1=BaseServie{desc=‘service1-1’}, service1-2=BaseServie{desc=‘service1-2’}, service2-1=BaseServie{desc=‘service2-1’}}
baseServieMap:{service1-1=BaseServie{desc=‘service1-1’}, service1-2=BaseServie{desc=‘service1-2’}, service2-1=BaseServie{desc=‘service2-1’}}
下面我们来介绍另外一种自动注入方式。
按照构造函数进行自动注入
用法
autowire设置为constructor
spring会找到x类中所有的构造方法(一个类可能有多个构造方法),然后将这些构造方法进行排序(先按修饰符进行排序,public的在前面,其他的在后面,如果修饰符一样的,会按照构造函数参数数量倒叙,也就是采用贪婪的模式进行匹配,spring容器会尽量多注入一些需要的对象)得到一个构造函数列表,会轮询这个构造器列表,判断当前构造器所有参数是否在容器中都可以找到匹配的bean对象,如果可以找到就使用这个构造器进行注入,如果不能找到,那么就会跳过这个构造器,继续采用同样的方式匹配下一个构造器,直到找到一个合适的为止。
来看看案例吧。
案例
DiAutowireByConstructor.java
package com.javacode2018.lesson001.demo6;
/**
- 构造函数的方式进行自动注入
*/
public class DiAutowireByConstructor {
public static class BaseServie {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return “BaseServie{” +
“desc='” + desc + ‘’’ +
‘}’;
}
}
//Service1实现了IService1接口
public static class Service1 extends BaseServie {
}
//Service1实现了IService1接口
public static class Service2 extends BaseServie {
}
private Service1 service1;
private Service2 service2;
public DiAutowireByConstructor() { //@0
}
public DiAutowireByConstructor(Service1 service1) { //@1
System.out.println(“DiAutowireByConstructor(Service1 service1)”);
this.service1 = service1;
}
public DiAutowireByConstructor(Service1 service1, Service2 service2) { //@2
System.out.println(“DiAutowireByConstructor(Service1 service1, Service2 service2)”);
this.service1 = service1;
this.service2 = service2;
}
public Service1 getService1() {
return service1;
}
public void setService1(Service1 service1) {
this.service1 = service1;
}
public Service2 getService2() {
return service2;
}
public void setService2(Service2 service2) {
this.service2 = service2;
}
@Override
public String toString() {
return “DiAutowireByConstructor{” +
“service1=” + service1 +
“, service2=” + service2 +
‘}’;
}
}
@1:1个参数的构造函数
@2:2个参数的构造函数
2个有参构造函数第一行都打印了一段文字,一会在输出中可以看到代码是调用了那个构造函数创建对象。
diAutowireByConstructor.xml
<?xml version="1.0" encoding="UTF-8"?>测试用例
DiAutowireTest新增一个方法
/**
- 构造函数的方式进行自动注入
*/
@Test
public void diAutowireByConstructor() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByConstructor.xml”;
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
System.out.println(context.getBean(“diAutowireByConstructor”));
}
效果
运行diAutowireByConstructor输出:
DiAutowireByConstructor(Service1 service1)
DiAutowireByConstructor{service1=BaseServie{desc=‘service1’}, service2=null}
从输出中可以看到调用的是DiAutowireByConstructor类中的第一个构造函数注入了service1 bean。
构造函数匹配采用贪婪匹配,多个构造函数结合容器找到一个合适的构造函数,最匹配的就是第一个有参构造函数,而第二个有参构造函数的第二个参数在spring容器中找不到匹配的bean对象,所以被跳过了。
我们在diAutowireByConstructor.xml加入Service2的配置:
再来运行一下diAutowireByConstructor输出:
DiAutowireByConstructor(Service1 service1, Service2 service2)
DiAutowireByConstructor{service1=BaseServie{desc=‘service1’}, service2=BaseServie{desc=‘service2’}}
此时可以看到第二个有参构造函数被调用了,满足了贪婪方式的注入原则,最大限度的注入所有依赖的对象。
autowire=default
用法
bean xml的根元素为beans,注意根元素有个default-autowire属性,这个属性可选值有(no|byName|byType|constructor|default),这个属性可以批量设置当前文件中所有bean的自动注入的方式,bean元素中如果省略了autowire属性,那么会取default-autowire的值作为其autowire的值,而每个bean元素还可以单独设置自己的autowire覆盖default-autowire的配置,如下:
<?xml version="1.0" encoding="UTF-8"?>案例
diAutowireByDefault.xml
<?xml version="1.0" encoding="UTF-8"?>//@1
//@2
//@3
注意上面的@1配置的default-autowire=“byName”,表示全局默认的自动注入方式是:按名称注入
@2和@3的autowire=default,那么注入方式会取default-autowire的值。
测试用例
DiAutowireTest中新增一个方法
/**
- autowire=default
*/
@Test
public void diAutowireByDefault() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByDefault.xml”;
ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
xt(beanXml);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-0xERd2b1-1715094462507)]
[外链图片转存中…(img-X1EKZCCR-1715094462507)]
[外链图片转存中…(img-Gu9CGZmH-1715094462508)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!