Spring学习记录(三)——Bean的自动装配

2018.4.13

仅为个人理解 不足之处欢迎指正~

什么是自动装配?

自动装配即(Autowire) 是Spring中引入的一个机制

它的作用是:

解决<bean>标签下<property>标签过多的问题

在上一篇文章中 我们举了一个汽车——车身——底盘——轮胎的例子

在这个例子中每一层的类仅需要注入一个类

所以我们可以看到 一个Bean中仅需要注入一个类:



但是在实际项目中 一个Bean中要注入的对象可能远不止一个

如果一个Bean中要注入的对象过多 会导致可读性与维护性降低

同时繁琐的配置过程也容易引起疏漏


因此,为了解决使用<property>标签注入对象过多的问题 

Spring引入了自动装配机制

简化配置过程与难度


自动装配有几种?

Spring中提供了五种自动装配模式

本文将依次介绍


方式1:默认方式(no)

这种方式是默认设置 意味着并没有使用自动装配模式

这种情况下每一个对象的注入都必须依赖一个<property>标签

由于上一篇文章中采用的就是这种方式 

所以本文对这种方式不做更多介绍


方式2:byName

采用这种方式时 Spring会自动寻找属性名字相同的Bean

即寻找某些Bean 其id必须与该属性名字相同

找到后 通过调用Setter方法将其注入属性

所以需要Setter方法

下面看一下这种方式的实现:

采用的例子仍是上一篇文章中的汽车例子 代码请参考上一篇文章

我们对Car类的bean进行修改:


在默认方法中我们可以看到 Car类需要Framework类的注入

现在我们使用byName的方式:


其他的类不进行改动:


运行测试类TestSpring

package com.tzy.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tzy.pojo.*;

public class TestSpring 
{
	public static void main(String args[])
	{
		ApplicationContext context=new ClassPathXmlApplicationContext
				(new String[]{"applicationContext.xml"});
		Car mycar=(Car)context.getBean("car");
		mycar.run();
		System.out.println("轮胎的尺寸为:"+mycar.getFramework().getBottom().getTire().getSize());
		System.out.println("车身的名字为:"+mycar.getFramework().getFrameworkname());
	}
}

可以看到Framework类被注入了Car

我们现在将Framework的bean id改为


再次运行测试类


现在将framework的bean id改回framework 但是在Car的POJO中 将


改为:


程序可以成功运行

由此我们可以看到 Bean的名字(id)需要与Bean的属性的名字相同


此时我们为Car类增加一个需要注入的类:power

同时新建Power的POJO 且不写入Setter方法



此时我们先用默认方式装配Bean


添加一行测试代码:

System.out.println("动力为   "+mycar.gerPower().getPowernum());

运行时报错:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'car' defined in class path resource [applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'power' of bean class [com.tzy.pojo.Car]: Bean property 'power' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?


我们现在将Setter方法的注释取消掉重新运行


我们看到 Setter方法在默认的装配方法中是必要的

下面使用byName方法进行装配


运行:


现在我们再次将Setter方法注释:




byName方式总结:

byName方式为属性自动装配ID与该属性名字相同的Bean

通过设置autowire为“byName” Spring将自动装配该Bean中的所有属性

在上一个例子中我们看到 car需要注入framework和power

在默认方式中 需要2个ref

而byName方式中不需要ref

这种优势在car需要注入更多的类时会更加明显


两个注意点:

1.需要Setter方法

2.建议使用bean id 而不是bean name 因为id具有唯一性 不会出现有多个Bean的id与其属性名相同而冲突的情况


方式3:byType

byType的作用方式与byName相似

不同点在于 byName是匹配属性的名字 而byName是匹配属性的类型

当我们使用byTypy方式后 Spring会寻找与所需注入的类相同的Bean来注入

我们在上一个例子中:


改为:


由上面的测试我们已经知道这样的情况会报错

此时

我们将autowire属性改为"byType"


运行成功:


由此我们又引出新的问题:

既然byType是按照类型寻找的 那么如果出现了有两个Bean都与需要自动装配的属性类型相匹配的情况怎么办?

我们看一个例子:


添加了一个power2 它同样是Power类

此时再次运行测试代码 则报错:

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'car' defined in class path resource [applicationContext.xml]: Unsatisfied dependency expressed through bean property 'power': : No unique bean of type [com.tzy.pojo.Power] is defined: expected single matching bean but found 2: [power1, power2]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.tzy.pojo.Power] is defined: expected single matching bean but found 2: [power1, power2]


为了解决这一情况我提供三种办法:

1.避免出现多个Bean与所需Bean相匹配的情况(雾)

2.声明一个首选Bean

3.排除其它不想要选择的Bean


既然Spring不会智能挑选所寻找到的多个Bean 我们只能给它指定一个


利用primary="ture"指定首选项

运行:



利用autuwire-candidate="false" 是这种思路的反向思路

即排除其他干扰项——那么剩下的自然是首选项


这样设置的结果与上一种方式相同

byType方式总结:

byType方式与byName方式类似

但是需要注意的是避免出现多个满足需求的Bean 

或者为它们配置候选关系

byType也需要Setter方法


方式4:constructor方式

constructor方式是通过构造器来配置Bean

我们修改Car的POJO类

将Setter方法改为构造器方法:


修改xml文档:


运行:


constructor方式总结:

选择constructor方式时 必须让所需的所有类进入构造器

不能混合使用Setter方法与构造器方法

同时与byType方式有相同的局限性:若一个类有多个构造器 且都满足自动装配条件 Spring无法挑选出合适的那个


方式5:autodetect方式

这种方式会自动检测是否有默认的构造方法

若有 则通过constructor装配

若没有 则使用byType 方式进行装配

这一个方法比较容易出现错误 不做详细示范


谢谢~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值