Spring中bean的注入方式
首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入。依赖注入是指:让调用类对某一接口的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖。
Spring容器中支持的依赖注入方式主要有属性注入、构造函数注入、工厂方法注入。接下来将为大家详细介绍这三种依赖注入的方式以及它们的具体配置方法。
1.属性注入
属性注入即通过setXXX( )方法注入bean的属性值或依赖对象。由于属性注入方式具有可选择性和灵活性高的特点,因此它也是实际开发中最常用的注入方式。
Spring首先会调用bean的默认构造函数实例化bean对象,然后再通过反射的方法调用set方法来注入属性值。
属性注入要求bean提供一个默认的构造函数,并且得为需要注入的属性提供set方法。
TIps:所谓默认的构造函数,即不带参数的构造函数。如果类中没有自定义任何构造函数,则系统(JVM)会自动生成一个不带参的默认构造函数,如果类中显式的自定义了有参数的构造函数,则系统就不会在自动生成默认构造函数,需要自己手动再加一个无参的构造函数。
下面通过一个实例来演示Spring中bean的属性注入方式:
编写一个user类:
package com.Kevin.bean;
/**
* 创建一个类测试bean的属性注入方式
* @author Kevin
*
*/
public class User { private String username; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} }
配置文件:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="user" class="com.Kevin.bean.User">
<property name="username">
<value>Kevin</value>
</property>
</bean> </beans>
其中,每个属性值对应一个property标签,name属性值为类中属性的名称。在bean实现类中拥有与其对应的实现方法setUsername( )。
Tips:Spring只会检查bean中是否含有setter方法,而对是否有对应的属性变量则不作具体要求,但按照约定俗成的规则我们最好为其设定相应的属性变量。
Spring中<property>标签的命名规范:
● Spring的<property>标签所指定的属性名称和bean实现类的setter方法满足Sun JavaBean的属性命名规范,即XXX的属性对应setXXX( )的方法。
一般情况下,java的属性变量名都以小写字母开头,但考虑到一些特殊意义的英文缩略词,java bean也允许一些大写字母开头的变量名。但必须满足以下两点:
● 变量的前两个字母要么全部大写,要么全部小写;
● 但以一般编程习惯来说,属性名最好全部使用小写字母,方便编程和阅读。
对于属性注入方式来说,只能人为的在配置文件中提供保证,而无法在语法级别提供保证。此时就需要使用构造函数注入这种方式,以此来更好的满足要求。
2.构造函数注入
构造函数注入是除属性注入之外的另一种常用的注入方式,它可以保证一些必要的属性在bean实例化时就得到了设置,并在实例化后就可以使用。
使用构造函数注入的前提是:bean必须提供带参的构造函数。
对于构造函数的注入,配置文件可以有以下几种方式:
● 按类型匹配入参
● 按索引匹配入参
● 联合使用类型和索引匹配入参
● 通过自身类型反射匹配入参
【按类型匹配入参方式】
编写bean代码:
package com.Kevin.bean;
/**
* 编写bean测试按类型匹配入参方式
* @author Kevin
*
*/ public class Person { private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
} }
编写配置文件:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="person" class="com.Kevin.bean.Person">
<constructor-arg type="String">
<value>Kevin</value>
</constructor-arg>
<constructor-arg type="Integer">
<value>20</value>
</constructor-arg>
</bean> </beans>
Spring的配置文件采用和元素标签顺序无关的配置策略,因此可以在一定程度上保证配置信息的确定性。
那么当bean中的构造函数的多个类型参数一样时,按照类型匹配入参的这种方式容易产生混淆,此时就需要使用另一种方式:按照索引匹配入参。
【按照索引匹配入参】
编写bean代码:
package com.Kevin.bean;
/**
* 编写bean测试按照索引方式入参
* @author Kevin
*
*/ public class Student {
private String name;
private String gender;
private Double score;
public Student(String name, String gender, Double score) {
super();
this.name = name;
this.gender = gender;
this.score = score;
} }
配置文件编写如下:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="student" class="com.Kevin.bean.Student">
<constructor-arg index="0" value="Kevin"></constructor-arg>
<constructor-arg index="1" value="Male"></constructor-arg>
<constructor-arg index="2" value="66"></constructor-arg>
</bean> </beans>
Tips:在属性注入时,Spring按java bean的规范确定配置属性和对应的setter方法,并使用java反射机制调用属性的setter方法完成属性注入。但java反射机制并不会记住构造函数的入参名,因此我们不能通过制定构造函数的入参名称来进行构造函数的配置,所以我们只能通过入参的类型及索引来间接完成构造函数的属性注入。
【联合使用类型和索引匹配入参】
在某些复杂的配置文件当中,需要使用type和index同时出马才能完成构造函数的参数注入。下面使用一个实例来演示。
编写bean:
package com.Kevin.bean;
/**
* 编写bean测试联合使用类型和索引匹配入参
* @author Kevin
*
*/ public class Teacher {
private String name;
private String address;
private double salary;
private int age;
public Teacher(String name, String address, double salary) {
super();
this.name = name;
this.address = address;
this.salary = salary;
}
public Teacher(String name, String address, int age) {
super();
this.name = name;
this.address = address;
this.age = age;
} }
在这个类中,有两个重载的构造函数,他们都有三个参数,在这种情况下使用type和index的方法都不能完成要求,这时候就需要他们两个属性同时使用了。
配置文件:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="teacher" class="com.Kevin.bean.Teacher">
<constructor-arg index="0" type="String">
<value>Kevin</value>
</constructor-arg>
<constructor-arg index="1" type="String">
<value>China</value>
</constructor-arg>
<constructor-arg index="2" type="int">
<value>20</value>
</constructor-arg>
</bean> </beans>
可以看到其实重点在于第三个入参的类型,所以我们在配置文件中指定了索引和类型,这样便可以使得Spring知道对哪个构造函数进行参数注入了。
Tips:加入我们得配置文件中存在歧义问题,Spring容器是可以正常启动的,并不会报错,它将随机采用一个匹配的构造函数实例化bean。而随机选择的构造函数可能并不是用户所需要的,所以我们在编程时要小心避免出现这种歧义情况。
【通过自身类型反射匹配入参】
如果bean构造函数入参的类型是可辨别的,由于java反射机制可以获取构造函数入参的类型,即使构造函数的注入不提供类型和索引的信息,Spring依旧可以完成构造函数信息的注入。例如下面实例中Manager类的构造函数的入参类型就是可以辨别的。
编写Manager类:
package com.Kevin.bean;
/**
* 编写Bean测试通过自身类型反射匹配入参方式
* @author Kevin
*
*/ public class Manager {
private String name;
private Double salary;
private Person person;
public Manager(String name, Double salary, Person person) {
super();
this.name = name;
this.salary = salary;
this.person = person;
} }
编写配置文件:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="manager" class="com.Kevin.bean.Manager">
<constructor-arg>
<value>Kevin</value>
</constructor-arg>
<constructor-arg>
<ref bean="user"/>
</constructor-arg>
<constructor-arg>
<ref bean="person"/>
</constructor-arg>
</bean> </beans>
以上几种方法都可以实现构造函数参数的注入,但是为了避免问题的发生,还是建议使用显式的index和type来配置构造函数的入参信息。
3.工厂方法注入
工厂方法是应用中被经常使用的设计模式,也是控制反转和单实例设计思想的主要实现方法。工厂类负责创建一个或多个工厂类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类实例。
工厂类对外屏蔽了目标类的实例化步骤,调用者甚至根本不用指定具体的目标类是什么。由于Spring容器以框架的方法提供工厂方法的功能,并以透明的方式开放给开发者。因此很少需要手工编写工程方法。但在一些遗留系统或第三方类库中还是会碰到工程方法,此时便可以使用Spring工厂注入的方法来进行Spring的注入。
Spring工厂注入的方法可以分为静态和非静态两种。
【非静态工厂方法】
有些工厂方法是非静态的,必须实例化工厂类之后才能调用工厂方法。下面通过一个实例来演示。
编写工厂类:
package com.Kevin.factorybean;
/**
* 编写工厂类测试非静态工厂方法注入
* @author Kevin
*
*/ public class BookFactory {
public Book buyBook(){
Book book = new Book();
book.setName("Think in Java");
return book;
} }
配置文件编写:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="bookFactory" class="com.Kevin.factorybean.BookFactory"></bean>
<bean id="book" factory-bean="bookFactory" factory-method="buyBook"></bean> </beans>
由于bookFactory的工厂方法不是静态的,因此需要先定义一个工厂类的bean,然后通过factory-bean属性来引用工厂bean实例。再通过属性factory-method来指定对应的工厂方法。
【静态工厂方法】
很多工厂类方法都是静态的,这意味着无需创建工厂类实例的情况下就可以调用工厂类方法。因此静态工程方法比非静态工厂方法的调用更加方便简洁。下面通过一个实例来演示静态工厂方法。
编写factory类:
package com.Kevin.factorybean;
/**
* 编写工厂类测试静态工厂方法注入
* @author Kevin
*
*/ public class CarFactory {
public static Car createCar(){
Car car = new Car();
car.setBrand("Lamborghini");
return car;
} }
编写配置文件:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here --> <!-- 配置对象 -->
<bean id="car" class="com.Kevin.factorybean.Car" factory-method="createCar"></bean> </beans>
总结
Spring提供了三种可供选择的注入方式,但在实际应用中,我们究竟该选择哪种注入方式,并没有统一的标准,如下是一些可以参考的理由:
构造函数注入理由:
● 构造函数保证重要属性预先设置;
● 无需提供每个属性的setter方法,减少类的方法个数;
● 可以更好地封装类变量,避免外部错误调用。
属性注入理由:
● 属性过多时,构造函数变的臃肿;
● 构造函数注入灵活性不强,有时需要为属性注入null值;
● 多个构造函数时,配置上产生歧义,复杂度升高;
● 构造函数不利于类的继承和扩展;
● 构造函数注入会引起循环依赖的问题。
其实Spring为我们注入参数提供了这么多方法,那么这些方法必然有他们存在的道理,每个方法在某一问题上会有独特的优势,我们只需要按照我们具体的使用需求选择适合的方法来使用就好了,但一般不太推荐工厂方法注入。
Spring中bean的注入方式的更多相关文章
- spring中Bean的注入类型
1.属性注入 即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常采用的注入方式. 属性注入要求Bean提供 ...
- spring中对象的注入方式
平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...
- Spring 中Bean的装配方式
最近又买了一本介绍SSM框架的书,是由黑马程序员编写的,书上讲的很好理解,边看边总结一下.主要总结一下bean的装配方式. Bean的装配可以理解为依赖系统注入,Bean的装配方式即Bean依赖注入的 ...
- spring中Bean的注入参数详解
字面值 一般指可用字符串表示的值,这些值可以通过<value>元素标签进行注入.在默认情况下,基本数据类型及其封装类.String等类型都可以采取字面值注入的方式,Spring容器在 ...
- Spring中Bean的装配方式
一.基于xml的装配 Student.java package com.yh; public class Student implements People { public void breath( ...
- Spring中bean的配置
先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对象的时候,一般都是直接使用关键字类new一个对象,那这样有什么坏处呢?其实很显然的,使用new那么就表示当前模块已经 ...
- Spring学习(三)——Spring中的依赖注入的方式
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...
- spring中bean实例化时机以及整个运转方式
接上一篇文章,一般在servlet获取到请求之后 在service方法中就可以完成所有的请求处理以及返回,但是我们会采用更高级的MVC框架来做.也就是说所有的MVC框架入口就是serlvet中的ser ...
- spring 学习之 bean 的注入方式 property和constructor-arg的使用方式
spring 学习之 bean 的注入方式 property和constructor-arg的使用方式. bean的注入方式: property 注入是: 通过setxx方法注入. construct ...
随机推荐
- CSS 文章链接
文本溢出显示为省略号 Ellipsis for text overflow in table cell?
- Math类的方法应用
class Mortgage { public static void main(String[]args) { double P=Double.parseDouble(args[0]); doubl ...
- Windows ML,系统内置的机器学习平台初探
人工智能现在很火,虽然最近风头隐隐有被区块链盖过,但仍是未来技术转型的首选方向之一.作为AI核心的机器学习,目前也进化到了可以基于平台自动训练模型的地步,例如Azure Machine Learnin ...
- Hadoop的Python框架指南
http://www.oschina.NET/translate/a-guide-to-Python-frameworks-for-Hadoop 最近,我加入了Cloudera,在这之前,我在计算生物 ...
- Ocelot中文文档-不支持
Ocelot不支持一下几点... 分块编码 - Ocelot将始终获取body大小并返回Content-Length头. 如果这不适合你的场景,只能表示抱歉! 转发host头 - 您发给Ocelot的 ...
- XAMPP重置MySQL密码
找到XAMPP的安装位置,这里以我的为例:C:\xampp 那么MySQL的路径:C:\xampp\mysql phpMyAdmin的路径:C:\xampp\phpMyAdmin 修改MySQL密码 ...
- Search in rotated array two
description: Follow up for "Search in Rotated Sorted Array":What if duplicates are allowed ...
- 面向对象的WebAPI框架XXL-HEX
<面向对象的WebAPI框架XXL-HEX> 一.简介 1.1 概述 XXL-HEX 是一个简单易用的WebAPI框架, 拥有 "面向对象.数据加密.跨语言" 的 ...
- lintcode 链表求和
题目要求 你有两个用链表代表的整数,其中每个节点包含一个数字.数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头.写出一个函数将两个整数相加,用链表形式返回和. 样例 给出两个链表 3- ...
- 关于引用(python中的伪指针)的理解
# 总结:个人理解,引用不可变的的变量时,随着改变会指向新的地址 # 引用可变的变量时,位置不会随着变量改变而改变 a = 1 b = a print(b) a = 2 # 指向了新的内存地址 pri ...