Spring框架之自动装配

Spring的IoC容器通过Java反射机制了解了容器中所存在Bean的配置信息,这包括构造方法的结构,属性的信息,而正是由于这个原因,Spring容器才能通过某种规则来对Bean进行自动装配,而无须通过显式的方法进行配置。

一.自动装配类型:Spring IoC容器可以自动装配相互协作Bean之间的关联关系。因此,可以自动使Spring通过检查BeanFactory中的内容,来指定Bean协作(其它被依赖的Bean),,下面来介绍这4种类型:

1.byName类型:根据属性名自动装配。此类型将检查容器并根据名字查找与属性完全一样的bean,并将其与属性自动装配。

注:使用byName自动装配类型时,对于设置的属性名字必须提供set()方法,否则在启动Spring时,将会报出异常。

下面附上一个例子:

(1).第一步,新建一个Java项目,项目名为spring_byName,然后配置好spring环境即可。

(2).第二步,新建一个People类,放在com.bean包下,声明三个属性,分别为name,age,sex,并生成其setXxx()和getXxx()方法,在写一个方法get(),用于输出People各个属性值,具体看代码,如下:

<pre class="java" name="code">package com.bean;

public class People {
	private String name;
	private int age;
	private String sex;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public void get() {
		System.out.print("姓名为:" + name);
		System.out.print(",年龄为:" + age);
		System.out.print(",性别为:" + sex);
	}
}

(3).第三步,新建一个Student类,也放在com.bean包下,声明course课程这个属性以及上面People类的对象属性,并生成属性的setXxx()和getXxx()方法,在写一个get()方法,输出course这个属性值和调用People类中的get()方法,具体代码如下:

package com.bean;

public class Student {
	private String course;
	private People people;

	public String getCourse() {
		return course;
	}

	public void setCourse(String course) {
		this.course = course;
	}

	public People getPeople() {
		return people;
	}

	public void setPeople(People people) {
		this.people = people;
	}

	public void get() {
		System.out.println("学生的课程为:" + course);
		people.get();
	}

}

(4).第四步,打开配置文件applicationContext.xml文件,只需要在<bean>标签中通过autowire属性设置为byName来启动自动装配,如下代码所示:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="people" class="com.bean.People">
		<property name="name" value="张三"></property>
		<property name="age" value="23"></property>
		<property name="sex" value="男"></property>
	</bean>

	<bean id="student" class="com.bean.Student" autowire="byName">
		<property name="course" value="Java程序设计"></property>
	</bean>

</beans>

其中使用<property>标签中的所指定的name要与类中的属性名一一对应起来,然后在student这个bean里使用了byName自动装配类型,那么在peoplebean里的id属性值必须与Student类中所声明的People对象属性名一致!

(5).第五步,编写一个测试类Test,也放在com.bean包下,其中获取加载配置文件,然后通过ApplicationContext对象获取Student这个Bean,再调用这个Bean对象的get()方法,具体代码如下:

package com.bean;

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

public class Test {

	public static void main(String[] args){
		ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
		Student stu=(Student) ac.getBean("student");
		stu.get();
	}
}

(6).第六步,运行效果如下:

这样便把People这个Bean的三个属性值自动装配进去了Student这个Bean中去了,所以调用get()方法也把People类的属性值也输出来了!

(7).如果我们把配置文件中的People这个Bean改成下面所示,即把id属性改成people1,如下:

<bean id="people1" class="com.bean.People">
	<property name="name" value="张三"></property>
	<property name="age" value="23"></property>
	<property name="sex" value="男"></property>
</bean>

其它代码不变,运行测试类Test之后,如下图所示:

这样就报空指针异常了,获取不到People类的属性名,所以使用byName自动装配类型的话,一个Bean中的id要与另一个Bean的对象属性名一一对应!

注:如果上面这个例子把自动装配类型改为byType的话,也是可以的,就算你People类在配置文件里配置bean的id属性任意都行,因为此时就是按照类型装配了!

2.byType类型:如果容器存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型的bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没找到相匹配的bean,则什么事都不发生。

(1).这里就不附上例子了,我们通过上面这个例子把autowire属性设置为byType,也可以运行成功,因为是按照类型匹配的,我们可以把配置文件改成如下所示,其它都不改:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="p" class="com.bean.People">
		<property name="name" value="张三"></property>
		<property name="age" value="23"></property>
		<property name="sex" value="男"></property>
	</bean>

	<bean id="student" class="com.bean.Student" autowire="byType">
		<property name="course" value="Java程序设计"></property>
	</bean>

</beans>

运行之后效果与byName一样。

(2).如果我们把配置文件改成如下所示,我们配置两个People类,如下图所示:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="p" class="com.bean.People">
		<property name="name" value="张三"></property>
		<property name="age" value="23"></property>
		<property name="sex" value="男"></property>
	</bean>

	<bean id="p1" class="com.bean.People">
		<property name="name" value="李红"></property>
		<property name="age" value="18"></property>
		<property name="sex" value="女"></property>
	</bean>

	<bean id="student" class="com.bean.Student" autowire="byType">
		<property name="course" value="Java程序设计"></property>
	</bean>

</beans>

则会报一个错误,因为我们定义了两个类型都为People的bean,所以不能匹配到是哪一个bean,报错信息如下图所示:

即如果Bean采用byType进行自动装配,当IoC容器中存在多个类型匹配的Bean时,就无法判断究竟该选择哪个Bean作为自动装配的目标,所以就抛出上面的异常信息了!

(3).这里简单讲述一下Spring如何进行匹配入参,如果A类和B类,两者满足以下三种情况中的任何一种,可以称之A按类型匹配于B:

~A和B是相同的类型。 ~A是B的子类。 ~A实现了B的接口。

3.constructor类型:与byType类型相似,不同在于constructor类型应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常。

(1).其实使用constructor自动装配时,只不过是通过构造方法而进行自动装配的。

(2).下面附上一个例子:

第一步,首先创建一个Java项目,项目名称为spring_constructor,配置好Spring环境。

第二步,新建一个Man类,具体代码如下,就不做分析了,很简单:

package com.bean;

public class Man {
	private String name;
	private String sex;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void out(){
		System.out.println(name);
		System.out.println(sex);
		System.out.println(age);
	}
}

第三步,新建一个Building类,代码如下:

package com.bean;

public class Building {
	private String name;
	private int floors;
	private Man m;

	public Building(String name,int floors,Man m){
		this.name=name;
		this.floors=floors;
		this.m=m;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getFloors() {
		return floors;
	}

	public void setFloors(int floors) {
		this.floors = floors;
	}

	public Man getPerson() {
		return m;
	}

	public void setPerson(Man man) {
		this.m = man;
	}

	public void out(){
		System.out.println(name);
		System.out.println(floors);
		m.out();
	}
}

Building类里有一个带三个参数的构造方法。

第四步,打开配置文件进行配置,配置如下:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="man" class="com.bean.Man">
		<property name="name" value="A-Lc"></property>
		<property name="sex" value="男"></property>
		<property name="age" value="23"></property>
	</bean>

	<bean id="building" class="com.bean.Building" autowire="constructor">
		<constructor-arg index="0" value="金大福"></constructor-arg>
		<constructor-arg index="1" value="88"></constructor-arg>
	</bean>

</beans>

在配置文件中,把autowire属性设置为constructor来启动自动装配,然后再用<constructor-arg>标签把带的参数传进去,这里只传了两个,其中最后一个Man的对象属性参数通过匹配有Man类型的bean传进去。

第五步,新建Test测试类,代码如下:

package com.bean;

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

import com.bean.Building;

public class Test {
	public static void main(String[] args){
		ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
		Building b=(Building) ac.getBean("building");
		b.out();
	}
}

第六步,运行后效果如下:

二.自动装配控制

1.在一个Spring应用中,Bean的数量很多,因此在使用自动装配时,如果容器中多个匹配项,Spring会抛出异常,不能正常工作。针对这种问题,可以对那些不需要匹配的Bean进行设置,设定这个Bean是否为被自动装配对象。当采用XML格式配置Bean时,可将<bean>元素的autowire-candidate属性设置为false,这样容器在查找自动装配对象时将不考虑该Bean,也就是这个Bean将不会被作为自动装配对象。

2.如果我们把上面constructor类型的自动装配例子的配置文件修改为下面所示,其它代码不改:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="man" class="com.bean.Man">
		<property name="name" value="A-Lc"></property>
		<property name="sex" value="男"></property>
		<property name="age" value="23"></property>
	</bean>

	<bean id="man1" class="com.bean.Man">
		<property name="name" value="A-Xg"></property>
		<property name="sex" value="男"></property>
		<property name="age" value="23"></property>
	</bean>

	<bean id="building" class="com.bean.Building" autowire="constructor">
		<constructor-arg index="0" value="金大福"></constructor-arg>
		<constructor-arg index="1" value="88"></constructor-arg>
	</bean>

</beans>

定义两个类型相同的bean,此时IoC容器不知道匹配哪一个 ,所以会报下图的错:

3.我们可以将上面的代码的一个不需要匹配的bean的autowire-candidate属性设置为false,如下代码所示:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="man" class="com.bean.Man" autowire-candidate="false">
		<property name="name" value="A-Lc"></property>
		<property name="sex" value="男"></property>
		<property name="age" value="23"></property>
	</bean>

	<bean id="man1" class="com.bean.Man">
		<property name="name" value="A-Xg"></property>
		<property name="sex" value="男"></property>
		<property name="age" value="23"></property>
	</bean>

	<bean id="building" class="com.bean.Building" autowire="constructor">
		<constructor-arg index="0" value="金大福"></constructor-arg>
		<constructor-arg index="1" value="88"></constructor-arg>
	</bean>

</beans>

4.此时运行效果就输出姓名为A-Xg的信息了,如下图所示:

三.使用自动装配的前提:使用自动装配,主要是为了方便,提高工作效率,但是要正确并合理地使用自动装配,必须先理解自动装配的优缺点,才能正确判断何时需要使用自动装配。

1.自动装配的优点如下:

(1).自动装配能显著减少装配的数量,因此在配置数量相当多时采用自动装配,可以减少工作量。

(2).自动装配可以使配置与Java代码同步更新。例如:如果需要给一个Java类增加一个依赖,那么该依赖将自动实现而不需要修改配置。因此强烈在开发过程中采用自动装配,而在系统趋于稳定的时候改为显式装配的方式。

2.虽然自动装配具有上面这些优点,但不是说什么时候都可以使用它,因为它还有如下一些缺点:

(1).尽管自动装配比显式装配更神奇,但是,Spring会尽量避免在装配不明确时进行猜测,因为装配不明确可能出现难以预料的结果,而Spring所管理的对象之间的关联关系也不再能清晰地进行文档化。

(2).对于那些根据Spring配置文件生成文档的工具来说,自动装配将会使这些工具无法生成依赖信息。

3.决定是否使用自动装配方式时,没有绝对的对错。考虑项目的实际是最好的方法,例如对于大型的应用,不建议使用自动装配。虽然自动装配可以减少配置文件的工作量,但是大大降低了依赖关系的清晰度和透明度。由于依赖关系的配置基于源文件的属性名,这就导致Bean与Bean之间的耦合降低到代码层次,不利于高层次解耦。

以上内容仅供大家学习参考,写得不好,请见谅,如有错误,请指出,谢谢!



时间: 2025-01-02 15:34:27

Spring框架之自动装配的相关文章

Spring IOC容器-自动装配

1 autowire="byName" 根据名称自动装配,自动去IOC容器中找与属性名同名的引用的对象,并自动注入. <!-- ###############自动装配############### --> <bean id="userDao" class="d_auto.UserDao"></bean> <bean id="userService" class="d_auto

Spring(六)之自动装配

一.自动装配模型 下面是自动连接模式,可以用来指示Spring容器使用自动连接进行依赖注入.您可以使用元素的autowire属性为bean定义指定autowire模式. 可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合. 自动装配的局限性 当自动装配始终在同一个项目中使用时,它的效果最好.如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义.不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之

Spring 源码(九)@Autowired注解实现原理(Spring Bean的自动装配

@Autowired注解的实现过程,其实就是Spring Bean的自动装配过程.通过看@Autowired源码注释部分我们可以看到@Autowired的实现是通过AutowiredAnnotationBeanPostProcessor后置处理器中实现的. AutowiredAnnotationBeanPostProcessor 类图 PriorityOrdered:确认 AutowiredAnnotationBeanPostProcessor 后置处理器的执行优先级 BeanFactoryAw

Spring 源码(九)@Autowired注解实现原理(Spring Bean的自动装配)

@Autowired注解的实现过程,其实就是Spring Bean的自动装配过程.通过看@Autowired源码注释部分我们可以看到@Autowired的实现是通过AutowiredAnnotationBeanPostProcessor后置处理器中实现的. AutowiredAnnotationBeanPostProcessor 类图 PriorityOrdered:确认 AutowiredAnnotationBeanPostProcessor 后置处理器的执行优先级BeanFactoryAwa

Spring框架学习(五):Spring @Autowired实现自动装配

学习自动装配之前,讲一个概念:Component,即组件.组件你也可以理解为bean对象,只不过通常Component的组成会稍微复杂一些,比如,一个组件里面会引用一个或多个别的bean对象,组件的定义方式也不一样.自动装配貌似就是为组件而生的. 自动装配(Autowired)这个概念,如果你已经使用过SpringMVC或者SpringBoot做开发,你会发现@Autowired注解是特别经常使用到的.比如你的Controller.Service相关的类里面就会经常用到.如果你看过@Contro

Spring中类型自动装配--byType

在Spring中,"类型自动装配"的意思是如果一个bean的数据类型与其它bean属性的数据类型相同,将自动兼容装配它. 例如,一个"persion" bean 公开以"ability"类数据类型作为属性,Spring会找到ability类相同的数据类型,并自动装配它的Bean.如果没有匹配找到,它什么也不做. package auto_w; /** * Created by luozhitao on 2017/8/8. */ public cl

Spring中的自动装配案例分析

Spring_Autowiring collaborators 在Spring3.2.2中自动装配类型,分别为:no(default)(不采用自动装配).byName,byType,constructor下面来分别介绍一下这些是如何自动装配的 <bean id="foo" class="...Foo" autowire="autowire type"> Mode Explanation no (Default) No autowiri

Spring抛出异常_自动装配

Spring自动装配(autowire)出错 报错如下: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person' defined in class path resource [appContext.xml]: Unsatisfied dependency expressed through bean property 'axe': : No

Spring bean的自动装配属性

bean的自动装配属性能简化xml文件配置. bean 的自动装配属性分为四种: 1.byName 2.byTyoe 3.constructor 4. autodetect byName: 它查找配置文件中的的bean的id 或者name 和本bean中的成员属性名相同的bean 自动装配 所以不用再给本bean添加peoperty标签 例:有两个类 public Class  Person{ } public Class Customer{ private Person p; public s