Spring之Bean的注入
Bean的配置中介绍的是Bean声明问题,在哪声明怎么声明的问题。Bean的注入是怎么实例化,怎么注入的问题。Bean注入的方式有两种,一种是在XML中配置,另一种则是使用注解的方式注入。
一、XML方式注入
XML方式注入一般有三种方式:属性注入、构造函数注入和工厂方法注入。
一、属性注入
在传统的对象实例化时可以通过new class(),然后通过setXXX()方法设置对象的属性值或依赖对象,属性注入也是采用这种方式,只是Spring框架会在内部完成这些操作,它会先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值。它会使用默认的构造函数(无参数构造函数),只需为注入的属性设置set方法,可选择性和灵活性比较高,所以也是比较常用的一种注入方式。这里示例还是在IOC章节使用人和空气的基础上稍作修改来演示。IAir接口和CleanAir、DirtyAir类不变,这里就不贴了。
1.新建XMLInstance类
package com.demo.model; public class XMLInstance { private String name; public void setName(String name) {
this.name = name;
}
private IAir air; public void setAir(IAir air) {
this.air = air;
}
public void Breath()
{
System.out.println("Name:"+this.name+";Air:"+this.air.toString());
} public XMLInstance(String name, IAir air) {
super();
this.name = name;
this.air = air;
}
public XMLInstance() { }
public void DestoryMethod()
{
System.out.println("DestoryMethod");
}
public void InitMethod()
{
System.out.println("InitMethod");
}
}
在XMLInstance类中并未声明构造函数,对于air属性只设置了set方法,get方法也没设置。
<bean id="CleanAir" class="com.demo.model.CleanAir">
<qualifier value="cleanair"/>
</bean>
<bean id="xmlinstance" class="com.demo.model.XMLInstance">
<property name="air" ref="CleanAir"></property>
<property name="name" value="abc"></property>
</bean>
Xml中使用property类配置属性,name是属性名,value用来设置基本数据类型的属性值。Spring配置文件中bean之间可以相互引用,引用时可以用<ref>标签配置bean的id属性使用。<ref>可以用在<property>属性中,也可以用在<construct-arg>构造函数的参数值,还可以用在其他地方,通过引用能减少bean的声明。
二、构造函数注入
在属性注入时先使用默认的构造函数(无参数构造函数)实例化,然后通过set方法注入属性,在传统实例化对象时可以自定义构造函数进行实例化,构造函数注入就是通过自定义构造函数来进行对象的实例化。这里在XMLInstance类的基础上增加了一个构造函数,第一个参数是String类型的name,第二个参数是IAir类型的air。
public XMLInstance(String name, IAir air) {
super();
this.name = name;
this.air = air;
}
Xml中使用使用<construect-arg>来设置构造函数的参数,index属性设置参数的顺序,参数顺序应该与构造函数的一致,ref设置引用bean的id,value设置构造函数参数的值。
<bean id="xmlcontructinstance" class="com.demo.model.XMLInstance">
<constructor-arg index="1" ref="CleanAir"></constructor-arg>
<constructor-arg index="0" value="abc"></constructor-arg>
</bean>
三、工厂方法注入
工厂方法注入参考的是工厂设计模式,通过在工厂类中实现对象的实例化。工厂类负责创建一个或多个目标类实例,工厂类方法一般以接口或抽象类变量的形式返回目标类实例,工厂类对外屏蔽了目标类的实例化步骤,调用者甚至不用知道具体的目标类是什么。工厂方法也分静态工厂方法和非静态工厂方法,静态工厂方式不用实例化工厂类,直接通过类名调用,非静态工厂方法需要先实例化工厂类,然后通过工厂类对象调用获取对象。这里创建了一个工厂类XMLFactory,在类中定义了一个静态方法,和一个实例方法用来实例化bean对象。
package com.demo.model; public class XMLFactory { public XMLInstance CreateInstance()
{
return new XMLInstance("instance",new CleanAir());
} public static XMLInstance CreateStaticInstance()
{
return new XMLInstance("static instance",new CleanAir());
}
}
1.静态工厂方法
只需设置工厂方法对应的类,以及对应的工厂方法。
<bean id="xmlfactorystaticinstance" class="com.demo.model.XMLFactory" factory-method="CreateStaticInstance"></bean>
2.实例工厂方法
需要先实例化工厂类,再通过工厂类对象调用实例方法获取bean对象。
<bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="CreateInstance" destroy-method="DestoryMethod" init-method="InitMethod"></bean>
四、常见数据类型注入
(1)List属性注入
使用<list>配置java.util.List类型的属性。List属性中元素可以是任何数据类型的值,如果是Java对象可以使用ref指定,或使用<bean>定义新实例。如果是基础数据类型可直接用字符串。<list>中的元素会按配置的先后顺序排序。
<property name="lists">
<list>
<value>1</value>
<ref bean="CleanAir" />
<bean class="com.demo.model.CleanAir"/>
</list>
</property>
(2)Set属性注入
使用<set>配置java.util.Set类型的属性。Set属性中元素可以是任何数据类型的值,如果是Java对象可以使用ref指定,或使用<bean>定义新实例。如果是基础数据类型可直接用字符串。<set>中的元素没有先后顺序。
<property name="sets">
<set>
<value>1</value>
<ref bean="CleanAir" />
<bean class="com.demo.model.CleanAir"/>
</set>
</property>
(3)Map属性注入
使用<map>配置java.util.Map类型的属性。<entry>配置Map里的元素,Key指定索引,value指定值。如果是Java对象可以使用ref指定,或使用<bean>定义新实例。
<property name="maps">
<map>
<entry key="key1" value="1"></entry>
<entry key="key2" value-ref="CleanAir"></entry>
<entry key="key3" >
<bean class="com.demo.model.CleanAir"/>
</entry>
</map>
</property>
(4)Properties属性注入
使用<props>配置java.util.Properties类型的属性。<props>配置一个Properties对象,<prop>配置一条属性,属性Key配置索引。
<property name="pros">
<props>
<prop key="prokey1">prokeyA</prop>
<prop key="prokey2">prokeyB</prop>
</props>
</property>
(5)自定义属性编辑器
对于有一些属性是没法注入的,此时就需要自定义,比如日期类型。可以通过继承PropertyEditorSupport的类,重写setAsText方法来实现注入。这里定义了CustomerProperty继承PropertyEditorSupport,重写了setAsText方法,并将该bean配置到xml中。
package com.demo.model; import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat; public class CustomerProperty extends PropertyEditorSupport {
private String format="yyyy-MM-dd";
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
@Override
public void setAsText(String text) throws IllegalArgumentException { SimpleDateFormat sdf=new SimpleDateFormat(format);
//super.setAsText(text);
try {
//转换对象,能过setValue方法重新赋值
this.setValue(sdf.parse(text));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value="com.demo.model.CustomerProperty"/>
</map>
</property>
</bean>
配置之后就可以注入Date类型的属性了。
<property name="date" value="2018-8-20"/>
这里新建了XmlCollectionsDemo类,配置了上面的几个类型的属性来演示。
package com.demo.model; import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set; import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class XmlCollectionsDemo { private List<Object> list; private Properties pros; private Set<Object> sets; private Map<String,Object> maps; private Date date; public Date getDate() {
return date;
} public void setDate(Date date) {
this.date = date;
} public List<Object> list() {
return list;
} public void setLists(List<Object> list) {
this.list = list;
} public Properties getPros() {
return pros;
} public void setPros(Properties pros) {
this.pros = pros;
} public Set<Object> getSets() {
return sets;
} public void setSets(Set<Object> sets) {
this.sets = sets;
} public Map<String, Object> getMaps() {
return maps;
} public void setMaps(Map<String, Object> maps) {
this.maps = maps;
} public static void main( String[] args ) throws Exception
{ ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
BeanFactory factory=context;
XmlCollectionsDemo annontationInstance=(XmlCollectionsDemo)factory.getBean("xmlCollectionsDemo");
System.out.println(annontationInstance.list);
System.out.println(annontationInstance.pros);
System.out.println(annontationInstance.sets);
System.out.println(annontationInstance.maps);
System.out.println(annontationInstance.date);
}
}
<bean id="xmlCollectionsDemo" class="com.demo.model.XmlCollectionsDemo">
<property name="lists">
<list>
<value>1</value>
<ref bean="CleanAir" />
<bean class="com.demo.model.CleanAir"/>
</list>
</property>
<property name="sets">
<set>
<value>1</value>
<ref bean="CleanAir" />
<bean class="com.demo.model.CleanAir"/>
</set>
</property>
<property name="maps">
<map>
<entry key="key1" value="1"></entry>
<entry key="key2" value-ref="CleanAir"></entry>
<entry key="key3" >
<bean class="com.demo.model.CleanAir"/>
</entry>
</map>
</property>
<property name="pros">
<props>
<prop key="prokey1">prokeyA</prop>
<prop key="prokey2">prokeyB</prop>
</props>
</property>
<property name="date" value="2018-8-20"/>
</bean>
通过运行main方法,打印出属性值。
[1, CleanAir, CleanAir]
{prokey2=prokeyB, prokey1=prokeyA}
[1, CleanAir, CleanAir]
{key1=1, key2=CleanAir, key3=CleanAir}
Mon Aug 20 00:00:00 CST 2018
五、初始化函数、销毁函数
通过上面3种注入方式的学习也对通过xml对bean实例化有的了解,有的对象在实例化之后还需要执行某些初始化代码,但这些初始化代码还不能写在构造函数中,此时可以将初始化代码写到某个方法中,将init-method属性值设置为该方法,Spring会强制执行该方法进行初始化。而又的对象在使用完毕之后需要释放,可以使用destroy-method来进行销毁。
public void DestoryMethod()
{
System.out.println("DestoryMethod");
}
public void InitMethod()
{
System.out.println("InitMethod");
}
这里先在XMLInstance类中增加了上面两个方法来模拟销毁和初始化方法。然后在xml配置bean时就可以设置destroy-method、init-method属性的值对应两个方法的方法名。注解中@PostConstruct对应init-method,@PreDestory对应destroy-method。
<bean id="xmlfactoryinstance" factory-bean="xmlfactory" factory-method="CreateInstance" destroy-method="DestoryMethod" init-method="InitMethod"></bean>
二、注解注入方式
一、常用注解介绍
学习完XML注入之后再学习注解方式注入就容易的多,注解方式注入主要涉及到@Autowired,@Resource,@Required,@Qualifier,@Value这几个注解。在第2章节的2.2.4IOC实例中定义Person时就使用过@Autowired、@Qualifier。下面来了解下它们具体用法。
@Autowired:默认是按类型匹配注入bean,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。在使用@Autowired时,首先在容器中查询对应类型的bean,如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据,如果查询的结果不止一个,那么@Autowired会根据名称来查找。如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false。
@Required:适用于bean属性setter方法,并表示受影响的bean属性必须在XML配置文件在配置时进行填充。否则,容器会抛出一个BeanInitializationException异常。
@Qualifier:@Autowired默认是单实例的,但是在面向接口编程中,如果把一个属性设置为接口类型,一个接口可能有多个实现,那到底是注入哪一个呢?为了解决这个问题,就有了@Qualifier。
@Value:在xml配置属性时可以通过property的value设置默认值,@Value也可以为属性设置默认值。
@Resource:默认按名称匹配注入bean。要求提供一个bean名称的属性,如果属性为空,则自动采用标注处的变量名或方法名作为bean的名称。如果我们没有在使用@Resource时指定bean的名字,同时Spring容器中又没有该名字的bean,这时候@Resource就会退化为@Autowired即按照类型注入。
package com.demo.model; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Component
public class AnnontationInstance { @Value("abc")
private String name; public void setName(String name) {
this.name = name;
} //@Resource与@Autowired两者选其一
// @Autowired
// @Qualifier(value="cleanair")
private IAir air;
@Resource(name="CleanAir")
public void setAir(IAir air) {
this.air = air;
} public void Breath()
{
System.out.println("Name:"+this.name+";Air:"+this.air.toString());
}
}
上面代码使用@Value注解为name设置了默认值,使用@Resources设置bean的名称为IAir属性注入bean,也可以使用@Autowired+@Qualifier为IAir注入bean。
二、开启注解
上面配置完注解之后,还要告诉Spring开启注解,这样@Autowired、@Resources这些注解才起作用。开启有两种比较简单的方式。
1.在xml配置文件中使用context:annotation-config
<context:annotation-config />
2.在xml配置文件中使用context:component-scan
<context:component-scan base-package="com.demo.model"/>
Spring之Bean的注入的更多相关文章
- 在Spring的bean中注入HttpServletRequest解密
我们可以在Spring的bean中轻松的注入HttpServletRequest,使用@Autowired HttpServletRequest request;就可以了. 但是,为什么我们可以直接这 ...
- Spring中bean的注入方式
首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入.依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方注入,以此来消除调用类对某一接口实现类的依赖. Spring ...
- spring中Bean的注入参数详解
字面值 一般指可用字符串表示的值,这些值可以通过<value>元素标签进行注入.在默认情况下,基本数据类型及其封装类.String等类型都可以采取字面值注入的方式,Spring容器在 ...
- spring中Bean的注入类型
1.属性注入 即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常采用的注入方式. 属性注入要求Bean提供 ...
- (转载)在spring的bean中注入内部类
原文链接:http://outofmemory.cn/java/spring/spring-DI-inner-class 在spring中注入内部类,有可能会遇到如下异常信息: 2014-5-14 2 ...
- 记一次spring里bean无法注入的历程
应用启动的时候失败,看了下异常,是这个---NoUniqueBeanDefinitionException. 大家都知道,这是因为有俩个类型相同的实例,在被注入的时候,spring不知道该用哪个. 但 ...
- Spring在Bean中注入集合
以下内容引用自http://wiki.jikexueyuan.com/project/spring/injecting-collection.html: 如果你想传递多个值,如Java Collect ...
- spring IOC bean中注入集合
建立一个实体 package com.java.test4; import java.util.*; /** * @author nidegui * @create 2019-06-22 14:45 ...
- spring IOC bean中注入bean
俩个实体 package com.java.test4; /** * @author nidegui * @create 2019-06-22 14:45 */ public class People ...
随机推荐
- docker学习笔记-安装
安装docker Ubuntu Docker 安装 Docker 支持以下的 Ubuntu 版本: Ubuntu Precise 12.04 (LTS) Ubuntu Trusty 14.04 (LT ...
- java易错题
(选择二项) 8 A: B: C: D: (选择一项) 9 A: B: C: D: 正确答案是 A 您回答的是 B 回答错误 正确答案是 B,D 您回答的是 A,C 回答错误 (选择一项) 18 A: ...
- Python开发——1.基础知识
一.开发 开发语言分为高级语言和低级语言 高级语言:Python.Java.PHP.C++.C#.GO.Ruby等:低级语言:C.汇编语言. 高级语言对应的是字节码,是将代码编译成字节码,然后交给机器 ...
- windows server防火墙添加例外的步骤
Windows Server 2012 防火墙如何添加端口例外的方法 在Windows Server 2012系统中,如果用户想在防火墙中开通一个端口,您可以按以下步骤执行: 1. 首先点击桌面左 ...
- 记一次安装VS2015后启动失败的修复过程
安装过程没有提示任何问题,然而启动vs时提示没有安装 .Net Framework 4.6,那就安装吧,但是安装 4.6 时却提示 Windows Moudle Installer 服务没有启动,于是 ...
- 【接口时序】3、UART串口收发的原理与Verilog实现
一.软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:ISE14.7 3.仿真工具:ModelSim-10.4-SE 硬件平台: 1.FPGA型号:XC6SLX45- ...
- AJPFX简述:MetaTrader 4移动交易平台
(AJPFX)移动交易平台可以让客户随时通过客户手中的移动设备例如智能手机.PDA等管理自己帐户和进行交易.移动交易平台提供了完整的交易帐户管理分析选项,当客户无法使用台式计算机的时候,移动交易平台为 ...
- Spring AOP术语:连接点和切点的区别。
定义: 1.连接点(Join point):连接点是在应用执行过程中能够插入切面(Aspect)的一个点.这些点可以是调用方法时.甚至修改一个字段时. 2.切点(Pointcut):切点是指通知(Ad ...
- 一篇入门 -- Scala
整体介绍 Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性. 联邦理工学院洛桑(EPFL)的Martin Odersky于2001 ...
- 文件上传和WAF的攻与防
Author:JoyChouDate:20180613 1. 前言 本文的测试环境均为 nginx/1.10.3 PHP 5.5.34 有些特性和 语言及webserver有关,有问题的地方,欢迎大家 ...