Spring IOC 三种注入方式
2017-04-25 11:10
344 查看
IOC ,全称 (Inverse Of Control) ,中文意思为:控制反转, Spring 框架的核心基于控制反转原理。
什么是控制反转?
控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术。
由容器控制程序之间的关系,而不是由代码直接控制
由于控制权由代码转向了容器,所以称为反转
对象与对象之间的关系可以简单的理解为对象之间的依赖关系:
依赖关系:在 A 类需要类 B 的一个实例来进行某些操作,比如在类 A 的方法中需要调用类 B 的方法来完成功能,叫做 A 类依赖于 B 类。
一个需要特定的依赖的组件一般会涉及一个依赖对象,在 IOC 的概念中叫做目标 (target) 。换句话说, IOC 提供了这样的服务,使一个组件能够在它的整个生命周期中访问它的依赖和服务,用这种方法与它的依赖进行交互。总的来说, IOC 能够被分解为两种子类型:依赖注入和依赖查找。
IoC 在应用开发中是一个非常有力的概念。如 Martin Flower 所述, IoC 的一种表现形式就是依赖性注射。依赖性注射用的是好莱坞原则, ” 不要找我,我会找你的。 ” 。换句来说,你的类不会去查找或是实例化它们所依赖的类。控制恰好是反过来的,某种容器会设置这种依赖关系。使用 IoC 常常使代码更加简洁,并且为相互依赖的类提供一种很好的方法。
Spring 容器
在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
Spring 提供了两种类型的 IOC 容器实现.
BeanFactory: IOC 容器的基本实现.
ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory
在 Spring 的 IOC 容器里配置 Bean(在applicationContext.xml中配置)
id是Bean 的名称,这里我们对其细节归纳为以下三点:
在 IOC 容器中必须是唯一的
若 id 没有指定,Spring 自动将权限定性类名作为 Bean 的名字
id 可以指定多个名字,名字之间可用逗号、分号、或空格分隔
注意:当applicationContext.xml中有多个相同类型的bean时,请不要使用class的这种getBean的方法,而是使用id来getBean。即利用类型返回IOC容器中的bean,但要求IOC容器中只有一个该类型的bean。
依赖注入的方式
Spring 支持 3 种依赖注入的方式
属性注入
构造器注入
工厂方法注入(很少使用,不推荐)
针对如下类讲解注入方式
建立一个Spring项目首先要记得通常引入这三个基础jar包
可以适当选择不同版本
属性注入
属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
属性注入使用 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 子节点指定属性值
属性注入是实际应用中最常用的注入方式
构造方法注入
通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。
构造器注入在 元素里声明属性
我们现在先构造一个Car的bean类
这里有三种方法,来实现构造器注入的bean声明:
第一种方式:利用构造器的参数顺序,依次排列各个construcctor-arg
第二种方式:用index属性指定构造器参数的顺序,从0开始
第三种方式:构造器参数的名字来指定是哪一个参数赋值
测试方法:
运行结果1:
Car [name=BM, price=500000.0]
运行结果2:
Car [name=BM, price=400000.0]
运行结果3:
Car [name=BM, price=300000.0]
注意:方式三的constructor-arg的name属性必须与bean的构造方法的形参名称一样,而不是和bean的属性名一样,需要特别注意!
构造方法的重载问题
好,现在我们还说明一个问题。请看这样一个例子。现在有一个bean, Car2的定义如下:
我们的容器配制如下:applicationContext.xml
现在我们尝试调用测试:使用赋予参数name、price、version的构造器:
但是运行结果却是:
Car2 [name=BM, price=500000.0, version=0, speed=1.0]
getBean返回的使容器中由构造器public Car2(String name, double price, double speed)返回的对象。这就是构造器重载可能带来的问题。
解决方法是:
方法1:利用constructor-arg标签中的type属性,指定参数类型。
将刚才的容器配制改为:
在运行test7测试方法:
Car2 [name=BM, price=500000.0, version=1, speed=0.0]
这样就OK了。
方法2:利用constructor-arg标签中的name属性,指定参数名称。
在运行test7测试方法:
Car2 [name=BM, price=500000.0, version=1, speed=0.0]
大家记住spring的容器对应于applicationContext.xml配制文件,容器构造对象时在加载该配制文件的时候,而不是实际getBean的时候。
感谢博文参考:https://my.oschina.net/happyBKs/blog/477557
什么是控制反转?
控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术。
由容器控制程序之间的关系,而不是由代码直接控制
由于控制权由代码转向了容器,所以称为反转
对象与对象之间的关系可以简单的理解为对象之间的依赖关系:
依赖关系:在 A 类需要类 B 的一个实例来进行某些操作,比如在类 A 的方法中需要调用类 B 的方法来完成功能,叫做 A 类依赖于 B 类。
一个需要特定的依赖的组件一般会涉及一个依赖对象,在 IOC 的概念中叫做目标 (target) 。换句话说, IOC 提供了这样的服务,使一个组件能够在它的整个生命周期中访问它的依赖和服务,用这种方法与它的依赖进行交互。总的来说, IOC 能够被分解为两种子类型:依赖注入和依赖查找。
IoC 在应用开发中是一个非常有力的概念。如 Martin Flower 所述, IoC 的一种表现形式就是依赖性注射。依赖性注射用的是好莱坞原则, ” 不要找我,我会找你的。 ” 。换句来说,你的类不会去查找或是实例化它们所依赖的类。控制恰好是反过来的,某种容器会设置这种依赖关系。使用 IoC 常常使代码更加简洁,并且为相互依赖的类提供一种很好的方法。
Spring 容器
在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
Spring 提供了两种类型的 IOC 容器实现.
BeanFactory: IOC 容器的基本实现.
ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory
在 Spring 的 IOC 容器里配置 Bean(在applicationContext.xml中配置)
id是Bean 的名称,这里我们对其细节归纳为以下三点:
在 IOC 容器中必须是唯一的
若 id 没有指定,Spring 自动将权限定性类名作为 Bean 的名字
id 可以指定多个名字,名字之间可用逗号、分号、或空格分隔
注意:当applicationContext.xml中有多个相同类型的bean时,请不要使用class的这种getBean的方法,而是使用id来getBean。即利用类型返回IOC容器中的bean,但要求IOC容器中只有一个该类型的bean。
依赖注入的方式
Spring 支持 3 种依赖注入的方式
属性注入
构造器注入
工厂方法注入(很少使用,不推荐)
针对如下类讲解注入方式
建立一个Spring项目首先要记得通常引入这三个基础jar包
可以适当选择不同版本
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.7.RELEASE</version> </dependency>
属性注入
属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
属性注入使用 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 子节点指定属性值
属性注入是实际应用中最常用的注入方式
public class Car { public String brand; private String corp; private double price; private int maxSpeed; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getCorp() { return corp; } public void setCorp(String corp) { this.corp = corp; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } public String toString(){ return "brand:"+brand+"corp"+this.corp+"/maxSpeed:"+maxSpeed+"/price:"+price; } }
<!-- 属性方式注入--> <bean id="car" class="com.lyf.ditype.Car"> <property name="maxSpeed"> <value>240</value> </property> <property name="brand"> <value>红旗</value> </property> <property name="price"> <value>200000</value> </property> </bean>
构造方法注入
通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。
构造器注入在 元素里声明属性
我们现在先构造一个Car的bean类
public class Car { String name; double price; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Car() { super(); } public Car(String name1, double price1) { super(); this.name = name1; this.price = price1; } @Override public String toString() { return "Car [name=" + name + ", price=" + price + "]"; } }
这里有三种方法,来实现构造器注入的bean声明:
<bean id="car_id" class="com.lyf.p.Car"> <constructor-arg value="BM"></constructor-arg> <constructor-arg value="500000"></constructor-arg> </bean> <bean id="car_Index_id" class="com.lyf.p.Car"> <constructor-arg value="400000" index="1"></constructor-arg> <constructor-arg value="BM" index="0"></constructor-arg> </bean> <bean id="car_name_id" class="com.lyf.p.Car"> <constructor-arg name="price1" value="300000"></constructor-arg> <constructor-arg name="name1" value="BM"></constructor-arg> </bean>
第一种方式:利用构造器的参数顺序,依次排列各个construcctor-arg
第二种方式:用index属性指定构造器参数的顺序,从0开始
第三种方式:构造器参数的名字来指定是哪一个参数赋值
测试方法:
@Test public void test6_1() { //创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); //从IOC容器中获取Bean实例 Car cBean=(Car)ctx.getBean("car_id"); //调用对象方法 System.out.println(cBean); } @Test public void test6_2() { //创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); //从IOC容器中获取Bean实例 Car cBean=(Car)ctx.getBean("car_Index_id"); //调用对象方法 System.out.println(cBean); } @Test public void test6_3() { //创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); //从IOC容器中获取Bean实例 Car cBean=(Car)ctx.getBean("car_name_id"); //调用对象方法 System.out.println(cBean); }
运行结果1:
Car [name=BM, price=500000.0]
运行结果2:
Car [name=BM, price=400000.0]
运行结果3:
Car [name=BM, price=300000.0]
注意:方式三的constructor-arg的name属性必须与bean的构造方法的形参名称一样,而不是和bean的属性名一样,需要特别注意!
构造方法的重载问题
好,现在我们还说明一个问题。请看这样一个例子。现在有一个bean, Car2的定义如下:
public class Car2 { String name; double price; int version; double speed; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public double getSpeed() { return speed; } public void setSpeed(double speed) { this.speed = speed; } public Car2() { super(); } public Car2(String name, double price, int version) { super(); this.name = name; this.price = price; this.version = version; } public Car2(String name, double price, double speed) { super(); this.name = name; this.price = price; this.speed = speed; } public Car2(String name, double price, int version, double speed) { super(); this.name = name; this.price = price; this.version = version; this.speed = speed; } @Override public String toString() { return "Car2 [name=" + name + ", price=" + price + ", version=" + version + ", speed=" + speed + "]"; } }
我们的容器配制如下:applicationContext.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="car2_id" class="com.lyf.beans.Car2"> <constructor-arg value="BM" index="0"></constructor-arg> <constructor-arg value="500000" index="1"></constructor-arg> <constructor-arg value="1" index="2"></constructor-arg> </bean> </beans>
现在我们尝试调用测试:使用赋予参数name、price、version的构造器:
@Test public void test7() { //创建spring IOC容器对象。ClassPathXmlApplicationContext表示配置文件在类路径下,它是接口ApplicationContext的一个实现类。 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); //从IOC容器中获取Bean实例 Car2 c2Bean=(Car2)ctx.getBean("car2_id"); //调用对象方法 System.out.println(c2Bean); }
但是运行结果却是:
Car2 [name=BM, price=500000.0, version=0, speed=1.0]
getBean返回的使容器中由构造器public Car2(String name, double price, double speed)返回的对象。这就是构造器重载可能带来的问题。
解决方法是:
方法1:利用constructor-arg标签中的type属性,指定参数类型。
将刚才的容器配制改为:
<bean id="car2_id" class="com.lyf.beans.Car2"> <constructor-arg value="BM" index="0"></constructor-arg> <constructor-arg value="500000" index="1"></constructor-arg> <constructor-arg value="1" index="2" type="int"></constructor-arg> </bean>
在运行test7测试方法:
Car2 [name=BM, price=500000.0, version=1, speed=0.0]
这样就OK了。
方法2:利用constructor-arg标签中的name属性,指定参数名称。
<bean id="car2_id" class="com.lyf.beans.Car2"> <constructor-arg value="BM" index="0"></constructor-arg> <constructor-arg value="500000" index="1"></constructor-arg> <constructor-arg value="1" index="2" name="version"></constructor-arg> </bean>
在运行test7测试方法:
Car2 [name=BM, price=500000.0, version=1, speed=0.0]
大家记住spring的容器对应于applicationContext.xml配制文件,容器构造对象时在加载该配制文件的时候,而不是实际getBean的时候。
感谢博文参考:https://my.oschina.net/happyBKs/blog/477557
相关文章推荐
- Spring IOC三种注入方式(接口注入、setter注入、构造器注入)
- Spring IOC三种注入方式比较
- 深入浅出spring IOC中三种依赖注入方式
- Spring IOC三种注入方式(接口注入、setter注入、构造器注入)(摘抄)
- 深入浅出spring IOC中三种依赖注入方式
- Spring三种注入IOC注入方式
- Spring学习笔记(6)——IoC的三种注入方式
- spring IOC(控制反转)和DI(依赖注入)以及三种依赖注入方式的比较
- spring Ioc 依赖注入的三种方式:构造函数注入、setter方法注入和接口注入
- Spring IOC三种注入方式(接口注入、setter注入、构造器注入)
- Spring IOC以及三种注入方式
- Spring三种注入IOC注入方式
- Spring学习(二)spring ioc注入的三种方式
- 深入浅出spring IOC中三种依赖注入方式
- Spring学习(二)spring ioc注入的三种方式
- 深入浅出spring IOC中三种依赖注入方式
- 深入浅出spring IOC中三种依赖注入方式
- 【SSH系列】深入浅出spring IOC中三种依赖注入方式
- spring ioc注入的三种方式
- Spring IOC三种注入方式比较