Spring学习之路——自动装配
一、Bean的自动装配简介
在Spring中通常有三种装配机制,他们分别是:
- 在xml中显式配置
- 在java中显式配置
- 隐式的bean发现机制和自动装配
我们之前一直在使用第一种xml装配的方式,第二种在之后的我的博客中会提到。
在这里我们主要来聊一聊第三种,自动化的装配bean。
其自动装配要实现两个操作:
- 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
- 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
下面我们通过一个例子来康康吧!!!
二、真实案例
这里我们先写三个类,人,猫,狗三个类。猫和狗都有一个叫(Bark)的方法。人类拥有猫和狗,并写好其中的getter和setter方法
public class Cat {
public void Bark(){
System.out.println("miao");
}
}
public class Dog {
public void Bark(){
System.out.println("wang");
}
}
public class people {
private Dog dog;
private Cat cat;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public people(){
}
public people(Dog dog, Cat cat) {
this.dog = dog;
this.cat = cat;
}
}
首先我们还是通过最最最原始的xml方式注入属性。
<bean class="Cat" id="cat"></bean>
<bean class="Dog" id="dog"></bean>
<bean class="people" id="people">
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
这种方式想必大家已经非常熟悉了,我们测试一下。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
people lili = (people) context.getBean("people");
lili.getCat().Bark();
lili.getDog().Bark();
}
}
最后结果也没有问题!
三、通过ByName、ByType装配
1、autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
而且实现起来也非常简单。
我们先把之前的bean修改一下.
<bean class="Cat" id="cat"></bean>
<bean class="Dog" id="dog"></bean>
<bean class="people" id="people" autowire="byName">
</bean>
将人类下面的People下面猫狗的注入删掉,增加一个autowire字段,里面填入byName,我们运行一下康康。
依然没有任何问题,而如果我们将bean中猫和狗的ID改为cat555这种,程序就会报空指针异常。
这是因为因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。
2、autowire byType (按类型自动装配)
我们其他代码不变,只是把byName变成byType,程序便能正常运行。
这是因为按类型装配与其名字没有关系,容器自动将对应类型的bean装配到people中,但是如果我们有两个猫类型的Bean,程序就会报错,因为使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
四、使用注解
jdk1.5开始支持注解,spring2.5开始全面支持注解。
准备工作: 利用注解的方式注入属性。
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
然后开启注解支持
<context:annotation-config/>
这里主要来看一看@Autowired和@Resource两大注解。
-
@Autowired是按类型自动转配的,不支持id匹配。
-
需要导入 spring-aop的包!
这里我们将people方法的set方法注释掉,使用@Autowired注解.
import org.springframework.beans.factory.annotation.Autowired;
public class people {
@Autowired
private Dog dog;
@Autowired
private Cat cat;
public Dog getDog() {
return dog;
}
// public void setDog(Dog dog) {
// this.dog = dog;
// }
public Cat getCat() {
return cat;
}
// public void setCat(Cat cat) {
// this.cat = cat;
// }
public people(){
}
public people(Dog dog, Cat cat) {
this.dog = dog;
this.cat = cat;
}
}
发现输出完全没有问题。
之后我们再来看看@Resource
@Resource如有指定的name属性,先按该属性进行byName方式查找装配;
其次再进行默认的byName方式进行装配;
如果以上都不成功,则按byType的方式自动装配。
都不成功,则报异常。
还是原来这个例子,我们把上面的@Autowired改成@Resource,发现运行还是没有问题.
最后我们引用狂言老师对两者区别的总结。
@Autowired与@Resource异同:
-
@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
-
@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false.如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用
-
@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。
当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配
。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
具体大家可以去查看狂言老师的博客
https://blog.kuangstudy.com/index.php/archives/523/