上篇文章我们已经学习了1.4小结中关于依赖注入跟方法注入的内容。这篇文章我们继续学习这结中的其他内容,顺便解决下我们上篇文章留下来的一个问题-----注入模型。
[TOC]
在看下面的内容之前,我们先要对自动注入及精确注入有一个大概的了解,所谓精确注入就是指,我们通过构造函数或者setter方法指定了我们对象之间的依赖,也就是我们上篇文章中讲到的依赖注入,然后Spring根据我们指定的依赖关系,精确的给我们完成了注入。那么自动注入是什么?我们看下面一段代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/dbeans/spring-beans.xsd"
>
<bean id="auto" class="com.dmz.official.service.AutoService" autowire="byType"/>
<bean id="dmzService" class="com.dmz.official.service.DmzService"/>
</beans>
public class AutoService {
DmzService service;
public void setService(DmzService dmzService){
System.out.println("注入dmzService"+dmzService);
service = dmzService;
}
}
public class DmzService {
}
public class Main03 {
public static void main(String[] args) {
ClassPathXmlApplicationContext cc =
new ClassPathXmlApplicationContext("application.xml");
System.out.println(cc.getBean("auto"));
}
}
在上面的例子中我们可以看到
但是,打印结果如下:
注入dmzServicecom.dmz.official.service.DmzService@73a8dfcc // 这里完成了注入
com.dmz.official.service.AutoService@1963006a
可能细心的同学已经发现了,在AutoService的标签中我们新增了一个属性autowire="byType",那么这个属性是什么意思呢?为什么加这个属性就能帮我们完成注入呢?不要急,我们带着问题继续往下看。
这部分内容主要涉及官网中的1.4.5小结。
我们先看官网上怎么说的:
大概翻译如下:
Spring可以自动注入互相协作的bean之间的依赖。自动注入有以下两个好处:
接下来,官网给我们介绍了自动注入的四种模型,如图:
我们一一进行解析并测试:
这是目前Spring默认的注入模型,也可以说默认情况下Spring是关闭自动注入,必须要我们通过setter方法或者构造函数完成依赖注入,并且Spring也不推荐修改默认配置。我们使用IDEA时也可以看到
用红线框出来的部分建议我们使用精确的方式注入依赖。
从上面来说,Spring自动注入这种方式在我们实际开发中基本上用不到,但是为了更好的理解跟学习Spring源码,我们也是需要好好学习这部分知识的。
这种方式,我们为了让Spring完成自动注入需要提供两个条件
在找不到对应名称的bean的情况下,Spring也不会报错,只是不会给我们完成注入。
测试代码:
//记得需要将配置信息修改为:<bean id="auto" class="com.dmz.official.service.AutoService" autowire="byName"/>
public class AutoService {
DmzService dmzService;
/**
* setXXX,Spring会根据XXX到容器中找对应名称的bean,找到了就完成注入
*/
public void setDmzService(DmzService dmzService){
System.out.println("注入dmzService"+dmzService);
service = dmzService;
}
}
另外我在测试的时候发现,这种情况下,如果我们提供的参数不规范也不会完成注入的,如下:
public class AutoService {
DmzService dmzService;
// indexService也被Spring所管理
IndexService indexService;
/**
* setXXX,Spring会根据XXX到容器中找对应名称的bean,找到了就完成注入
*/
public void setDmzService(DmzService dmzService,IndexService indexService) {
System.out.println("注入dmzService" + dmzService);
this.dmzService = dmzService;
}
}
本以为这种情况Spring会注入dmzService,indexService为null,实际测试过程中发现这个set方法根本不会被调用,说明Spring在选择方法时,还对参数进行了校验,byName这种注入模型下,参数只能是我们待注入的类型且只能有一个
测试代码跟之前唯一不同的就是修改配置autowire="byType",这里我们测试以下三种异常情况
另外需要说明的是,我在测试的过程,将set方法仅仅命名为set,像这样public void set(DmzService dmzService),这种情况下Spring也不会进行注入
我们可以发现,对于这两种注入模型都是依赖setter方法完成注入的,并且对setter方法命名有一定要求(只要我们平常遵从代码书写规范,一般也不会踩到这些坑)。第一,不能有多个参数;第二,不能仅仅命名为set
当我们使用这种注入模型时,Spring会根据构造函数查找有没有对应参数名称的bean,有的话完成注入(跟前文的byName差不多),如果根据名称没找到,那么它会再根据类型进行查找,如果根据类型还是没找到,就会报错。
这里不得不说一句,Spring官网在这一章节有三分之二的内容是在说自定注入的缺陷以及如何将一个类从自动注入中排除,结合默认情况下自动注入是关闭的(默认注入模型为no),可以说明,在实际使用情况中,Spring是非常不推荐我们开启自动注入这种模型的。从官网中我们总结自动注入有以下几个缺陷:
这里主要用到autowire-candidate这个属性,我们要将其设置为false,这里需要注意以下几点:
<bean id="auto" class="com.dmz.official.service.AutoService" autowire="byType" autowire-candidate="false"/>
代表的是这个bean不会被注入到别的bean中,但是dmzService任何会被注入到AutoService中
另外需要说明的是,对于自动注入,一般我们直接在顶级的标签中进行全局设置,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
<!--在这里进行配置-->
default-autowire="byName">
连同上篇文章依赖注入,我画了下面一个图:
这部分比较简单,也是1.4小节中剩余的两个小知识,在这篇文章我们也一并学习了~
我们首先要知道,默认情况下,Spring在实例化容器中的对象时是按名称进行自然排序进行实例化的。比如我们现在有A,B,C三个对象,那么Spring在实例化时会按照A,B,C这样的顺序进行实例化。但是在某些情况下我们可能需要让B在A之前完成实例化,这个时候我们就需要使用depends-on这个属性了。我们可以通过形如下面的配置完成:
<bean id="a" class="xx.xx.A" depends-on="b"/>
<bean id="b" class="xx.xx.B" />
或者:
@Component
@DependsOn("b")
public class A {
}
默认情况下,Spring会在容器启动阶段完成所有bean的实例化,以及一系列的生命周期回调。某些情况下,我们
可能需要让某一个bean延迟实例化。这种情况下,我们需要用到lazy属性,有以下两种方式:
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
@Component
// 懒加载
@Lazy
public class A {
}
到此为止,官网中1.4小节中的内容我们就全学习完啦!最核心的部分应该就是上文中的这个图了。我们主要总结了Spring让对象产生依赖的方式,同时对各个方式进行了对比。通过这部分的学习,我觉得大家应该对Spring的依赖相关知识会更加系统,这样我们之后学习源码时碰到疑惑也会少很多。
下面我们还要继续学习Spring的官网,比如前面文章提到的Beandefinition到底是什么东西?Spring中的Bean的生命周期回调又是什么?这些在官网中都能找到答案。
这篇文章到这里就结束了,看完记得点个关注+分享,我们下篇文章再见!