关键词:
详细介绍了Spring IoC基于XML的DI详细配置全解。
前面的文章Spring IOC容器的概念以及基于XML的IoC装配中,我们学习了IoC容器的概念以及依赖注入的两种方式,现在我们来看看一些更详细的配置。本文基于Spring5.2.8,案例基于上一篇文章的案例。
文章目录
1 value字面量
对于基本类型、String、包装类类型的属性,我们可以直接使用value属性的字符串值来描述具体的值,这样可读性也更强。在最后注入的时候Spring的转换服务会将这些值从 String 转换为属性或参数的实际类型。
并且Spring支持使用< value >标签表示具体的字面量值:
<bean id="simpleSetterBased" class="com.spring.core.SimpleSetterBased">
<constructor-arg name="property1">
<value>xxx</value>
</constructor-arg>
<constructor-arg name="property2">
<value>yyy</value>
</constructor-arg>
<!--setter方法 name表示属性名 value 表示属性值-->
<property name="property3">
<value>123</value>
</property>
<property name="property4">
<value>false</value>
</property>
</bean>
1.1 Properties快捷转换
Spring容器支持通过PropertyEditor直接解析value中的特定格式的字符串字面量值,并转换为一个Properties集合。后面我们也会学习集合的注入方式,但是这是一个非常好用的快捷方式!
我们来测试一下,首先有一个PropertiesDI类,内部有一个Properties(Hashtable是Properties的父类)属性:
/**
* @author lx
*/
public class PropertiesDI
private Hashtable properties;
/**
* setter
*/
public void setProperties(Properties properties)
this.properties = properties;
@Override
public String toString()
return "PropertiesDI" +
"properties=" + properties +
'';
配置如下:
<!--properties-->
<bean class="com.spring.core.PropertiesDI" id="propertiesDI">
<property name="properties">
<!--直接写配置即可,自动转换为Properties-->
<value>
! 注释
# 注释
# “#”“!”开头的一行被算作注释不会解析。
# key和value可以使用 “=”、“:”、“ ”等符号分割,详见properties说明
key=value
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
ccc:ddd
aaa bbb
eee fff
</value>
</property>
</bean>
测试:
@Test
public void properties()
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("DI.xml");
System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
System.out.println(ac.getBean("propertiesDI", PropertiesDI.class));
结果如下,成功注入:
[propertiesDI]
PropertiesDIproperties=jdbc.url=jdbc:mysql://localhost:3306/mydb, jdbc.driver.className=com.mysql.jdbc.Driver, eee=fff, key=value, aaa=bbb, ccc=ddd
2 引用其他bean
2.1 ref引用
在< constructor-arg >、< property >、< entry >标签中有一个ref属性,用于将bean的指定属性的值设置为对容器管理的另一个bean的引用。这就是引用类型属性依赖的设置方式。被引用的bean是要设置其属性的bean的依赖项,在设置该属性之前,需要对其进行初始化。ref属性的值需要与引用的目标bean的id或者name属性中的一个值相同。
当然还有一个< ref >标签,可以作为< constructor-arg >、< property >以及某些集合标签的子标签,通过< ref >标签的bean属性也可以来指定引用的目标bean。< ref >标签允许在同一容器或父容器中创建对任何bean的引用,而不管它是否在同一XML文件中。bean属性的值需要与引用的目标bean的id或者name属性中的一个值相同。
如下案例,首先有一个RefDI类,用于ref测试:
/**
* @author lx
*/
public class RefDI
private HelloSpring helloSpring1;
private HelloSpring helloSpring2;
public RefDI(HelloSpring helloSpring1, HelloSpring helloSpring2)
this.helloSpring1 = helloSpring1;
this.helloSpring2 = helloSpring2;
@Override
public String toString()
return "RefDI" +
"helloSpring1=" + helloSpring1 +
", helloSpring2=" + helloSpring2 +
'';
配置文件:
<!--ref-->
<!--定义一个Bean-->
<bean name="helloSpring3" class="com.spring.core.HelloSpring"/>
<bean class="com.spring.core.RefDI" id="refDI">
<!--使用ref属性引用helloSpring3的bean-->
<constructor-arg name="helloSpring1" ref="helloSpring3"/>
<!--使用ref标签引用helloSpring3的bean-->
<constructor-arg name="helloSpring2">
<ref bean="helloSpring3"/>
</constructor-arg>
</bean>
测试:
@Test
public void ref()
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("DI.xml");
System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
System.out.println(ac.getBean("refDI", RefDI.class));
成功注入了其他bean:
初始化
[helloSpring3, refDI]
RefDIhelloSpring1=HelloSpringhello='hello', helloSpring2=HelloSpringhello='hello'
2.2 parent继承
< bean >、< ref >等标签中还有一个parent属性,这个属性用于指定目标bean将使用父bean的属性和配置,除了autowire、scope和lazy init属性,parent属性用于相同属性以及值的复用。parent属性的值与目标父bean的id属性或name属性中的一个值相同。
对于parent继承,这里又分几种情况:
- 如果父bean有class属性,而子bean没有class属性,那么子bean就是和父bean同一个class类型,相当于创建两个相同的对象。
- 如果父bean有class属性,而子bean也有class属性,那么允许它们是不同的类型,但是子bean必须含有父bean中定义的所有的注入方式。
- 如果父bean没有class属性,那么子bean必须定义class属性,这个父bean实际上类似于一个属性和值的模版,仅仅被值bean引用,实现配置复用,不能实例化,(这时父bean必须添加abstract="true"属性,表示父bean不会被创建,类似于于抽象类,否则启动容器会尝试父bean,但是由于父bean没有class而抛出异常:No bean class specified on bean definition)。这种情况下,子bean同样必须含有父bean中定义的所有的注入方式。
- 这里的父bean和子bean 以及“继承”,并不是Java中的继承关系,仅仅是复用了注入方式,精简了代码!
- 如果子bean和父bean中注入对相同依赖同时注入的值的话,那么可能会相互覆盖对方的值。这根据依赖注入的先后顺序:父bean的构造器注入->子bean的构造器注入->父bean的setter注入->子bean的setter注入,排序在后面的对相同依赖的注入值将会覆盖之前注入的值!
如下案例,首先有三个类:
/**
* @author lx
*/
public class ParentOne
private String property1;
public void setProperty1(String property1)
this.property1 = property1;
@Override
public String toString()
return "ParentOne" +
"property1='" + property1 + '\\'' +
'';
一个有意思的地方是,虽然ParentTwo继承了ParentOne,但是并没有继承私有属性property1,不过由于继承了setProperty1方法,因此仍然能够正常工作,这就是前面说的“子bean必须含有父bean中定义的所有的注入方式”的含义,对于setter方法注入来说,你没这个属性没关系,只要有个同名方法,参数类型能够兼容(从String转为参数类型)就不会报错,与返回值无关(见ParentThree)!
3 idref引用校验值
< idref >标签通常可以作为< constructor-arg >、< property >以及某些集合标签的子标签,用于将容器中另一个 bean的id或者name的字符串值(并不是引用)传递给< constructor-arg >、< property >以及某些集合标签,同时使用idref容器在部署的时候还会验证这个名称的bean是否真实存在(被定义了),这是一种防止错误的方法。该标签目前用的比较少。
如下案例,首先有一个IdrefCheck类,用于校验bean是否被定义了:
public class IdrefCheck
private String targetName;
public void setTargetName(String targetName)
this.targetName = targetName;
@Override
public String toString()
return "IdrefDI" +
"targetName='" + targetName + '\\'' +
'';
配置文件:
<!--idref-->
<!--定义一个Bean-->
<bean name="helloSpring3" class="com.spring.core.HelloSpring" />
<!--idrefCheck校验bean-->
<bean class="com.spring.core.IdrefCheck" name="idrefCheck">
<!--实际上就等于<property name="targetName" value="helloSpring3">-->
<!--但是多了bean校验的功能-->
<property name="targetName">
<idref bean="helloSpring3"/>
</property>
</bean>
实际上< idref >的bean属性引用的值就是等于一个String类型的值,都是字符串,但是< idref >多了一个校验对应名称的bean是否存在的功能!
在idea中,如果idref的bean属性指定的bean名字不存在容器中,那么直接报红,如果运行,那么会抛出:Invalid bean name 'helloSpring3' in bean reference for bean property 'targetName'
。
@Test
public void idref()
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("DI.xml");
System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
System.out.println(ac.getBean("idrefDI", IdrefCheck.class));
结果如下:
org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'idrefDI' defined in class path resource [DI.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean name 'helloSpring3' in bean reference for bean property 'targetName'
在很久之前(Spring2.0之前的版本中),< idref >标签的一个常用的作用是在用在ProxyFactoryBean中定义的AOP拦截器里。指定拦截器名称时使用< idref >元素可防止你拼写错误拦截器ID。但是目前用的比较少了!
4 内部bean
< bean >标签的内部可以使用< constructor-arg >、< property >以及某些集合标签,表示依赖注入。同样,在< constructor-arg >、< property >以及某些集合标签中也可以使用< bean >子标签,表示一个内部bean。原因很简单,如果我们注入的是一个对象,并且我们不想要通过ref引用其他已存在的bean,那么只有定义自己的内部的bean。
和“外部”bean的区别是,内部bean不需要定义id或者name属性,因为这个对象就相当于一个外部bean自己的对象。就算指定了,容器也不会使用这些值作为bean的名字,我们也不能通过IoC容器获取。容器在创建时也会忽略内部bean的scope作用域属性(后面会讲),因为内部 bean 始终是匿名的,并且始终使用外 bean 创建。无法独立访问内部bean,也无法将它们注入其他外部bean中。
如下案例,首先有一个InnerBean类,用于内部bean测试:
/**
* 内部bean
*
* @author lx
*/
public class InnerBean
private InnerBeanInner innerBeanInner1;
private InnerBeanInner innerBeanInner2;
public void setInnerBeanInner1(InnerBeanInner innerBeanInner1)
this.innerBeanInner1 = innerBeanInner1;
public void setInnerBeanInner2(InnerBeanInner innerBeanInner2)
this.innerBeanInner2 = innerBeanInner2;
@Override
public String toString()
return "InnerBean" +
"innerBeanInner1=" + innerBeanInner1 +
", innerBeanInner2=" + innerBeanInner2 +
'';
public static class InnerBeanInner
private String property1;
private int property2;
public void setProperty1(String property1)
this.property1 = property1;
public void setProperty2(int property2)
this.property2 = property2;
@Override
public String toString()
return "InnerBeanInner" +
"property1='" + property1 + '\\'' +
", property2=" + property2 +
'';
配置文件:
<!--内部bean-->
<bean id="innerBean" class="com.spring.core.InnerBean">
<property name="innerBeanInner1">
<!--内部bean 不需要指定id或者name-->
<bean class="com.spring.core.InnerBean.InnerBeanInner">
<property name="property1" value="aaa"/>
<property name="property2" value="111"/>
</bean>
</property>
<property name="innerBeanInner2">
<!--内部bean 指定id或者name也没用,不能通过容器获取到-->
<bean id="innerBeanInner" class="com.spring.core.InnerBean.InnerBeanInner">
<property name="property1" value="bbb"/>
<property name="property2" value="222"/>
</bean>
</property>
</bean>
测试:
@Test
public void innerBean()
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("DI.xml");
System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
InnerBean innerBean = ac.getBean("innerBean", InnerBean.class);
System.out.println(innerBean);
结果:
[innerBean]
InnerBeaninnerBeanInner1=InnerBeanInnerproperty1='aaa', property2=111, innerBeanInner2=InnerBeanInnerproperty1='bbb', property2=222
5 集合注入
5.1 注入方式
Spring提供了详细的集合注入方式。< list >、< set >、< map >、< props >、< array >标签分别用来注入Java中的List、Set、Map、Properties、array类型的集合,主要是用于集合类型的依赖项的注入。因为集合的元素既可以是基本类型也可以是对象甚至集合,因此集合注入非常灵活。另外集合注入支持泛型转换,注入的时候会自动将value的字符串值转换为对应泛型类型!
如下案例,首先有一个CollectionDI类,用于集合注入测试:
/**
* 集合注入
*
* @author lx
*/
public class CollectionDI
//集合属性注入
private List list;
private Set set;
private Map map;
private Properties properties;
private Object[] array;
public CollectionDI(List list, Set set, Map map, Properties properties, Object[] array)
this.list = list;
this.set = set;
this.map = map;
this.properties = properties;
this.array = array;
static class CollectionInner
private String property1;
private int property2;
public void setProperty1(String property1)
this.property1 = property1;
public void setProperty2(int property2)
this.property2 = property2;
@Override
public String toString()
return "CollectionInner" +
"property1='" + property1 + '\\'' +
", property2=" + property2 +
'';
@Override
public String toString()
return "CollectionDI" +
"\\n" + "list=" + list +
"\\n" + ", set=" + set +
"\\n" + ", map=" + map +
"\\n" + ", properties=" + properties +
查看详情
springioc—基于注解的di(总结)(代码片段)
基于注解的DI使用spring提供的注解,完成java对象创建,属性赋值。先总结:1.创建对象的注解@Component:普通java对象@Respository:dao对象,持久层对象,表示对象能访问数据库。@Service:service... 查看详情
spring的学习二(springioc和di,aop简介)
一:SpringIoc,DI,AOP简介IOC控制反转:将原本在程序中手动创建对象的控制权,交由Spring框架来管理 原理:读取标注或者配置文件,看看Shoe依赖的是哪个Source,拿到类名使用反射的API,基于类... 查看详情
基于 Spring 注释的 DI 与 xml 配置?
】基于Spring注释的DI与xml配置?【英文标题】:Springannotation-basedDIvsxmlconfiguration?【发布时间】:2012-01-1517:44:07【问题描述】:最近在我们的团队中,我们开始讨论在代码中使用spring注释来定义spring依赖项。目前我们正在使用contex... 查看详情
springioc和di
(1)什么是IOC(InversionOfControl控制反转)?对象之间的依赖关系应该由容器来建立。 (2)什么是DI(DependencyInjection依赖注入)?容器可以通过调用set方法或者构造器来建立对象之间的依赖关系。 注:IOC是目标,DI是手段。 (3)... 查看详情
springioc容器(代码片段)
IoC容器Spring容器是Spring框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为SpringBeans。通过阅... 查看详情
基于xml的di
三、集合属性注入(包含:为数组注入值、为List注入值、为Set注入值、为Map注入值、为Properties注入值)集合类定义如下: xml定义如下:仔细看下面是执行代码: 四、对于域属性的自动注入(包括:byName方式自动注... 查看详情
springioc容器初始化源码—容器初始化入口以及setconfiglocations设置容器配置信息一万字
基于最新Spring5.x,对于基于XML的SpringIoC容器初始化过程中的setConfigLocations设置容器配置信息方法的源码进行了详细分析,最后给出了比较详细的方法调用时序图! Spring5.x源码解析系列的第一篇文章,主要... 查看详情
springioc官方文档学习笔记之基于注解的容器配置(代码片段)
1.基于注解的配置与基于xml的配置(1)在xml配置文件中,使用context:annotation-config</context:annotation-config>标签即可开启基于注解的配置,如下所示,该标签会隐式的向容器中添加ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcess... 查看详情
springioc官方文档学习笔记之基于java的容器配置(代码片段)
1.@Bean与@Configuration(1)标注于类之上的@Configuration注解与标注于方法之上的@Bean注解是支持基于Java的容器配置的核心,被@Bean注解标注的方法用于实例化bean并将其注入至容器中,它与基于xml配置中的<bean/>标签起着相同的作用,@Bean... 查看详情
spring依赖注入基于xml的di(代码片段)
DI:给属性赋值spring调用类的无参数构造方法,创建对象。对象创建后给属性赋值。给属性赋值可以使用:xml配置文件中的标签和属性使用注解DI分类:set注入,也叫做设值注入构造注入set注入publicclassStudent //... 查看详情
java--spring之ioc控制反转;基于xml配置文件的di(代码片段)
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架控制反转(InversionofControl,缩写IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。依赖:classA类中含有classB的... 查看详情
spring基于xml配置的aop框架详细讲解(代码片段)
学习Spring中的AOP,就是通过配置的方式(有基于XML配置的,以及基于注解配置的),来实现相关的拦截切入功能。对原有的操作进行加强,但不影响原本的操作。目录学习Spring中的AOP,就是通过配置的... 查看详情
spring基于xml配置的aop框架详细讲解(代码片段)
学习Spring中的AOP,就是通过配置的方式(有基于XML配置的,以及基于注解配置的),来实现相关的拦截切入功能。对原有的操作进行加强,但不影响原本的操作。目录学习Spring中的AOP,就是通过配置的... 查看详情
springioc(di)
软件152刘昊翰一、IOC(DI) 概念IOC(InversionofControl,控制倒转)Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。 DI—DependencyInjection,即“依赖注入”:组件之间依赖关系由容器在... 查看详情
spring事务控制--基于xml的声明式事务控制:详细配置(代码片段)
...控制–编程式事务控制相关对象02:Spring事务控制–基于XML的声明式事务控制:环境搭建03:Spring事务控制–基于XML的声明式事务控制:详细配置04:Spring事务控制–基于注解的声明式事务控制1.基于XML的声明式... 查看详情
springioc(di)
1什么是IOCIOC—InversionofControl,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。2IOC和DIDI—DependencyInjection,即&ld... 查看详情
springioc
控制反转IOC*把创建对象的权力交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入DI和依赖查找DL+目的是削减程序之间的耦合Application常用的三个实现类:用来读取配置文件*ClassPathXmlApplicationContext:加... 查看详情