Spring4-容器4-依赖注入

    依赖注入有两种方式:构造器注入和Setter注入。

1 构造器注入

1.1 构造器参数解析

1.1.1 按照定义顺序解析

    如果构造器参数的类型定义没有潜在的歧义,那么构造器会按照bean定义中构造器参数的定义顺序依次进行匹配。看下面的代码:

package x.y;

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }

}

    上述代码中参数类型定义不存在潜在的歧义,我们假设BarBaz之间不存在继承关系。因此,下面代码中在元素<constructor-arg/>的配置即使没有明确指定构造参数顺序或者类型也会起作用。

<beans>
    <bean id="foo" class="x.y.Foo">
        <constructor-arg ref="bar"/>
        <constructor-arg ref="baz"/>
    </bean>

    <bean id="bar" class="x.y.Bar"/>

    <bean id="baz" class="x.y.Baz"/>
</beans>

1.1.2 使用type属性来显式指定构造参数类型

    当我们使用简单类型,比如<value>true</value>。Spring并不能知道该值的类型,不借助其他帮助Spring将不能通过类型进行匹配。看下面的类:

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}

    针对上面的场景可以使用type属性来显式指定那些简单类型那个的构造参数类型,比如:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

1.1.3 使用index属性来显式指定构造参数的索引

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

    使用索引可以解决多个简单值的混淆,还能解决构造方法有两个相同类型的参数的混淆问题,注意index是从0开始的

1.1.4 使用构造器参数命名来指定值的类型

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

    请记住为了使这个起作用,你的代码编译时要打开编译模式,这样Spring可以检查构造方法的参数。如果你不打开调试模式(或者不想打开),也可以使用@ConstructorProperties JDK注解明确指出构造函数的参数。下面是简单的例子:

package examples;

public class ExampleBean {

    // Fields omitted

    @ConstructorProperties({"years", "ultimateAnswer"})
    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}

1.2 代码示例

1.2.1 准备Bean类

package com.ws.edu.spring;

public class Food {

}
package com.ws.edu.spring;

public class Game {

}
package com.ws.edu.spring;

public class Person {
	private int id;
	private String name;
	private Food food;
	private Game game;
	
	public Person() {
		super();
	}
	
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	
	public Person(Food food, Game game) {
		super();
		this.food = food;
		this.game = game;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Food getFood() {
		return food;
	}
	public void setFood(Food food) {
		this.food = food;
	}
	public Game getGame() {
		return game;
	}
	public void setGame(Game game) {
		this.game = game;
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", food=" + food
				+ ", game=" + game + "]";
	}
}

1.2.2 配置xml

<?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">
	
	<bean id="food" class="com.ws.edu.spring.Food"/>
	<bean id="game" class="com.ws.edu.spring.Game"/>
	<!-- 按照定义顺序解析 -->
	<bean id="person1" class="com.ws.edu.spring.Person">
		<constructor-arg ref="food"/>
		<constructor-arg ref="game"/>
	</bean>
	<!-- 使用type属性来显式指定构造参数类型 -->
	<bean id="person2" class="com.ws.edu.spring.Person">
		<constructor-arg type="int" value="2"/>
		<constructor-arg type="java.lang.String" value="小明"/>
	</bean>
	<!-- 使用index属性来显式指定构造参数的索引  -->
	<bean id="person3" class="com.ws.edu.spring.Person">
		<constructor-arg index="0" value="3"/>
		<constructor-arg index="1" value="小明"/>
	</bean>
	<!-- 使用构造器参数命名来指定值的类型 -->
	<bean id="person4" class="com.ws.edu.spring.Person">
		<constructor-arg name="id" value="4"/>
		<constructor-arg name="name" value="小明"/>
	</bean>
</beans>

1.2.3 编写启动类

package com.ws.edu.spring;

import org.springframework.context.support.ClassPathXmlApplicationContext;


public class App {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		System.out.println(context.getBean("person1",Person.class));
		System.out.println(context.getBean("person2",Person.class));
		System.out.println(context.getBean("person3",Person.class));
		System.out.println(context.getBean("person4",Person.class));
	}
}

1.2.4 运行结果

212406_GNTc_3145136.png

2 Setter注入

    示例如下:

<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested ref element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

循环依赖

    如果你主要使用构造器注入,很有可能会产生无法解决的循环依赖问题。 举个例子:A类需要通过构造器注入B类的实例,并且B类又需要通过构造器注入A类的实例。如果为类A和类B配置的bean被相互注入的话,Spring IoC容器在运行时会检测到这个循环依赖并且抛出一个BeanCurrentlyInCreationException异常。

    一个可能的解决方法是修改类的源代码,将构造器注入改为setter注入。或者只使用setter注入避免使用构造器注入。换句话说,虽然这并不被推荐使用,你可以使用setter注入配置循环依赖。 和通常的情况不同(没有循环依赖),bean A 和bean B之间的循环依赖将会导致其中一个bean在被完全初始化的之前被注入到另一个bean里(先有鸡先有蛋的问题)

 

 

 

转载于:https://my.oschina.net/u/3145136/blog/866308

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值