Spring详解(六)----SpringBean的装配(基于XML的⽅式)
1、回顾依赖注⼊的三种⽅式
在前⾯第三章中()介绍了什么是依赖注⼊和它们的简单应⽤,它有3种⽅式:
构造器注⼊
setter⽅法注⼊
接⼝注⼊
其中构造器注⼊和setter注⼊是最主要的⽅式,下⾯进⾏简单回顾⼀下。
①、构造器注⼊:顾名思义就是被注⼊对象可以通过在其构造⽅法中声明依赖对象的参数列表,让外部(通常是IoC容器)知道它需要哪些依赖对象。
在⼤部分的情况下,我们都是通过类的构造⽅法来创建类对象,Spring 也可以采⽤反射的⽅式,通过使⽤构造⽅法来完成注⼊,这就是构造器注⼊的原理。
⾸先要创建⼀个具体的类、构造⽅法并设置对应的参数,这⾥以User为例:
/**
* ⽤户实体类
*/
public class User {
private int userId;
private String userName;
private int userAge;
private String userPwd;
private String userAddress;
//getter、setter、toString⽅法省略......
//有参构造器
public User(int userId, String userName, int userAge,
String userPwd, String userAddress) {
this.userId = userId;
this.userName = userName;
this.userAge = userAge;
this.userPwd = userPwd;
this.userAddress = userAddress;
}
}
如果我们在实体类中创建了有参的构造器,⽽没有显⽰的创建⽆参构造器,那么是不能再通过⽆参的构造器创建对象了,为了使Spring 能够正确创建这个对象,可以像如下Spring配置去做。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd">
<!--将指定类都配置给Spring,让Spring创建其对象的实例,⼀个bean对应⼀个对象
如果类中创建了有参构造器,必须完成初始化-->
<bean id="user" class="com.thr.pojo.User">
<constructor-arg index="0" value="2020"/>
<constructor-arg index="1" value="菜逼唐"/>
<constructor-arg index="2" value="18"/>
<constructor-arg index="3" value="123456"/>
<constructor-arg index="4" value="地球中国"/>
</bean>
</beans>
constructor-arg元素⽤于定义类构造⽅法的参数,其中index ⽤于定义参数的位置(从0开始),⽽value 则是设置值,通过这样的定义Spring 便知道使⽤哪个构造⽅法去创建对象了。虽然这样注⼊还是⽐较简单的,但是缺点也很明显,由于这⾥的参数⽐较少,所以可读性还是不错的,但是如果参数很多,那么这种构造⽅法就⽐较复杂了,这个时候应该考虑setter 注⼊。
②、setter⽅法注⼊:setter 注⼊是Spring 中最主流的注⼊⽅式,它利⽤Java Bean 规范所定义的setter ⽅法来完成注⼊,灵活且可读性⾼。它消除了使⽤构造器注⼊时出现多个参数的可能性,⾸先可以把构造⽅法声明为⽆参数的,然后使⽤setter 注⼊为其设置对应的值,其实也是通过Java 反射技术得以现实的。这⾥去掉上⾯User类中的有参数的构造⽅法,然后做如下的Spring配置。
<bean id="user1" class="com.thr.pojo.User">
<property name="userId" value="2020"/>
<property name="userName" value="菜逼唐"/>
<property name="userAge" value="18"/>
<property name="userPwd" value="123456"/>
<property name="userAddress" value="地球中国"/>
</bean>
这样Spring就会通过反射调⽤没有参数的构造⽅法⽣成对象,同时通过反射对应的setter注⼊配置的值了。这种⽅式是Spring最主要的⽅式,在实际的⼯作中是最常⽤的,所以下⾯都是基于setter⽅法注⼊的举例。
③、接⼝注⼊:接⼝注⼊是现在⾮常不提倡的⼀种⽅式,这种⽅式基本处于“退役状态”。因为它强制被注⼊对象实现不必要的接⼝,带有侵⼊性。⽽构造⽅法注⼊和setter⽅法注⼊则不需要如此,所以现在我们⼀般推荐使⽤构造器注⼊和setter注⼊。
2、装配 Bean 概述
说简单点就是将⾃⼰开发的Bean 装配到Spring IoC 容器中。在Spring 中提供了3种⽅法进⾏配置:
1. XML 中显⽰配置(Spring的XML配置⽂件)
2. Java 的接⼝和类中实现配置(⽐如:@Configuration+@Bean)这种⽅式在后⾯的SpringBoot中会经常使⽤,所以推荐使⽤这种⽅式,主要是这种⽅式不⽤去写配置⽂
件了
3. 隐式Bean 的发现机制和⾃动装配原则(⽐如:@Component+@Autowired)
在现实的⼯作中,这3 种⽅式都会被⽤到,并且在学习和⼯作中常常混合使⽤,所以我们需要明确3种⽅式的优先级,也就是我们应该怎么选择使⽤哪种⽅式去把Bean 发布到Spring IoC 容器中。所以这⾥给出关于这3 种⽅法优先级的建议(优先级从⾼到低):
基于约定优于配置的原则,最优先的应该是通过隐式Bean 发现机制和⾃动装配的原则。这样的好处是减少程序开发者的决定权,简单⼜不失灵活,所以这种⽅式在我们的实际开发中⽤的最多。
在没有办法使⽤⾃动装配原则的情况下应该优先考虑Java 接⼝和类中实现配置,这样的好处是避免XML 置的泛滥,也更为容易。这种场景典型的例⼦是⼀个⽗类有多个⼦类,⽐如学⽣类有两个⼦类,⼀个男学⽣类和⼥学⽣类,通过IoC 容器初始化⼀个学⽣类,容器将⽆法知道使⽤哪个⼦类去初始化,这个时候可以使⽤Java 的注解配置去指定。
如果上述的两种⽅法都⽆法使⽤的情况下,那么只能选择XML 去配置Spring IoC 容器。这种⽅式的好处
就是简单易懂,对于初学者⾮常友好。这种场景的例⼦是由于现实⼯作中常常⽤到第三⽅的类库,有些类并不是我们开发的,我们⽆法修改⾥⾯的代码,这个时候就通过XML ⽅式配置使⽤了。
通俗来讲,当配置的类是你⾃⾝正在开发的⼯程,那么应该考虑Java 配置为主,⽽Java 配置⼜分为⾃动装配和Bean 名称配置。在没有歧义的基础上,优先使⽤⾃动装配,这样就可以减少⼤量的XML 置。如果所需配置的类并不是你的⼯程开发的,那么建议使⽤XML 的⽅式。
本章都是通过XML 的⽅式来配置Bean,这样会更好的理解。使⽤XML 装配Bean 需要定义对应的XML,这⾥需要引⼊对应的XML 模式(XSD)⽂件,这些⽂件会定义配置Spring Bean 的⼀些元素。
这样我们就可以在⾥⾯定义对应的Spring Bean了。
3、Bean 装配简单值
这⾥先来讨论最简单的装配,⽐如基本的属性和对象,代码如下:
/
**
* ⽤户实体类
*/
public class User {
private int userId;
private String userName;
private int userAge;
private String userPwd;
private String userAddress;
//⼥朋友
private GirlFriend girlFriend;
/
/getter、setter、toString⽅法省略......
}
GirlFriend实体:
/**
* GirlFriend实体
*/
public class GirlFriend {
private String girlName;
private int girlAge;
private String girlHeight;
//getter、setter、toString⽅法省略......
}
Spring的xml配置⽂件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd">
<!--实例化GirlFriend-->
<bean id="girlFriend" class="com.thr.pojo.GirlFriend">
<property name="girlName" value="王美丽"/>
<property name="girlAge" value="18"/>
<property name="girlHeight" value="170"/>
</bean>
<!--实例化User-->
<bean id="user1" class="com.thr.pojo.User">
<!--注⼊普通值:使⽤ value 属性-->
<property name="userId" value="2020"/>
<property name="userName" value="菜逼唐"/>
<property name="userAge" value="18"/>
<property name="userPwd" value="123456"/>
<property name="userAddress" value="地球中国"/>
<!--注⼊对象:使⽤ ref 属性-->
<property name="girlFriend" ref="girlFriend"/>
</bean>
</beans>
上⾯就是⼀个最简单最基本的配置Bean了,这⾥简单来解释⼀下:
id 属性是标识符(别名),⽤来让Spring到这个Bean,id属性不是⼀个必须的属性,如果我们没有声明它,那么Spring 将会采⽤“全限定名#{number}“的格式⽣成编号。例如这⾥,如果没有声明“id="user"的话,那么Spring 为其⽣成的编号就是"com.thr.pojo.User#0”,当它第⼆次声明没有id 属性的Bean 时,编号就是"com.thr.pojo.User#1",后⾯以此类推。但是我们⼀般都会显⽰声明⾃定义的id,因为⾃动⽣成的id⽐较繁琐,不便于维护。
class 属性显然就是⼀个类的全限定名。
property 元素是定义类的属性,其中的name 属性定义的是属性的名称,⽽value 是它的值,ref 是⽤来引⼊对象的。
简单来测试⼀下,测试代码如下:
public class SpringTest {
public static void main(String[] args) {
//1.初始化Spring容器,加载配置⽂件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("l");
//2.通过容器获取实例,getBean()⽅法中的参数是bean标签中的id
User user = Bean("user1", User.class);
//3.调⽤实例中的属性
System.out.UserName()+"------"+GirlFriend());
}
}
运⾏结果:
最后注意:注⼊基本值使⽤value 属性,注⼊对象使⽤ref 属性。
4、Bean 装配集合
有些时候我们需要装配⼀些复杂的Bean,⽐如Set、Map、List、Array 和Properties 等,所以我们将上⾯的User改⼀下,假如这个User是个“海王”呢?他有好⼏个GirlFriend。我们对User类添加了⼀些属性(记得更改setter、getter和tostring⽅法):
/**
* ⽤户实体类
*/
public class User {
private int userId;
private String userName;
private int userAge;
private String userPwd;
private String userAddress;
//⼥朋友
private GirlFriend girlFriend;
private List<GirlFriend> lists;
private Set<GirlFriend> sets;
private Map<String, GirlFriend> maps;
private Properties properties;
private String[] array;
//getter、setter、toString⽅法省略......
}
Spring的xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd">
<!--实例化GirlFriend-->
<bean id="girlFriend1" class="com.thr.pojo.GirlFriend">
<property name="girlName" value="王美丽"/>
<property name="girlAge" value="18"/>
<property name="girlHeight" value="170"/>
</bean>
<bean id="girlFriend2" class="com.thr.pojo.GirlFriend">
<property name="girlName" value="杨美丽"/>
<property name="girlAge" value="19"/>
<property name="girlHeight" value="171"/>
</bean>
<bean id="girlFriend3" class="com.thr.pojo.GirlFriend">
<property name="girlName" value="李美丽"/>
<property name="girlAge" value="20"/>
<property name="girlHeight" value="172"/>
</bean>
<!--实例化User-->
<bean id="user2" class="com.thr.pojo.User">
<!--注⼊普通值:使⽤ value 属性-->
<property name="userId" value="2020"/>
<property name="userName" value="菜逼唐"/>
<property name="userAge" value="18"/>
<property name="userPwd" value="123456"/>
<property name="userAddress" value="地球中国"/>
<!--注⼊对象:使⽤ ref 属性-->
<property name="girlFriend" ref="girlFriend1"/>
<!--注⼊List集合-->
<property name="lists">
<list>
<ref bean="girlFriend1"/>
<ref bean="girlFriend2"/>
<ref bean="girlFriend3"/>
</list>
</property>
<!--注⼊Set集合-->
<property name="sets">
<set>
<ref bean="girlFriend1"/>
<ref bean="girlFriend2"/>
<ref bean="girlFriend3"/>
</set>
</property>
<!--注⼊Map集合-->
<property name="maps">
<map>
<entry key="正牌⼥友" value-ref="girlFriend1"/>
<entry key="备胎1" value-ref="girlFriend2"/>
<entry key="备胎2" value-ref="girlFriend3"/>
</map>
</property>
<!--注⼊Properties-->
<property name="properties">
<props>
<prop key="k1">v1</prop>
<prop key="k2">v2</prop>
</props>
</property>
<!--注⼊数组-->
<property name="array">
<array>
<value>value1</value>
<value>value2</value>
<value>value3</value>
</array>
</property>
</bean>
</beans>
对集合的装配进⾏总结:
List 属性使⽤对应的<list> 元素进⾏装配,然后通过多个<value> 元素设值,如果是bean则通过<ref>元素设值。
Set 属性使⽤对应的<set> 元素进⾏装配,然后通过多个<value> 元素设值,如果是bean则通过<ref>元素设值。
Map 属性使⽤对应的<map> 元素进⾏装配,然后通过多个<entry> 元素设值,entry 中包含⼀个键值对(key-value)的设置,普通值使⽤key和value,bean使⽤key-ref和value-ref设值。
Properties 属性使⽤对应的<properties> 元素进⾏装配,通过多个<property> 元素设值,只是properties 元素有⼀个必填属性key ,然后可以设置值
对于数组⽽⾔,可以使⽤<array> 设置值,然后通过多个<value> 元素设值。
简单来测试⼀下,测试代码如下:
public class SpringTest {
public static void main(String[] args) {
//1.初始化Spring容器,加载配置⽂件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("l");
//2.通过容器获取实例,getBean()⽅法中的参数是bean标签中的id
User user = Bean("user2", User.class);
//3.调⽤实例中的属性
System.out.println("List集合:"+Lists());
System.out.println("Set集合:"+Sets());
System.out.println("Map集合:"+Maps());
System.out.println("Properties:"+Properties());
System.out.println("数组:");
String[] array = Array();
for (String s : array) {
System.out.println(s);
}
}
}
运⾏结果:
5、命名空间装配 Bean(了解)
除了使⽤上述的的⽅法来装配Bean之外,Spring还提供了对应的命名空间的定义。
c 命名空间:⽤于通过构造器注⼊的⽅式来配置bean
p 命名空间:⽤于通过setter的注⼊⽅式来配置bean
util 命名空间:⼯具类的命名空间,可以简化集合类元素的配置
下⾯来简单介绍。要使⽤它们⾸先得犹如对应的命名空间和XML模式(XSD)⽂件。
⽰例代码:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:c="/schema/c"
xmlns:p="/schema/p"
xmlns:util="/schema/util"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd
/schema/util
/schema/util/spring-util.xsd">
<!--c 命名空间实例化GirlFriend,给GirlFriend显⽰的创建了⼀个⽆参和有参构造器-->
<bean id="girlFriend1" class="com.thr.pojo.GirlFriend" c:_0="王美丽" c:_1="18" c:_2="170"/>
<!--p 命名空间实例化GirlFriend-->
<bean id="girlFriend2" class="com.thr.pojo.GirlFriend" p:girlName="杨美丽" p:girlAge="20" p:girlHeight="168"/>
<!--util 命名空间-->
<!--List集合-->
<util:list id="lists">
<ref bean="girlFriend1"/>
<ref bean="girlFriend2"/>
</util:list>
<!--Set集合-->
<util:set id="sets">
<ref bean="girlFriend1"/>
<ref bean="girlFriend2"/>
</util:set>
<!--Map集合-->
<util:map id="maps">
<entry key="第⼀个⼥友" value-ref="girlFriend1"/>
<entry key="第⼆个⼥友" value-ref="girlFriend2"/>
</util:map>
<!--Properties集合-->
<util:properties id="properties">
实例化bean的三种方式<prop key="k1">v1</prop>
</util:properties>
<!--实例化User-->
<bean id="user3" class="com.thr.pojo.User"
p:userId="2020"
p:userName="菜逼唐"
p:userAge="18"
p:userPwd="123456"
p:userAddress="地球中国"
p:girlFriend-ref="girlFriend1"
p:lists-ref="lists"
p:sets-ref="sets"
p:maps-ref="maps"
p:properties-ref="properties">
</bean>
</beans>
总结:
c 命名空间:⽤于通过构造器注⼊的⽅式来配置bean,c:_0 表⽰构造⽅法的第⼀个参数,c:_1 表⽰构造⽅法的第⽽个参数,以此类推。
p 命名空间:⽤于通过setter的注⼊⽅式来配置bean,p:属性名表⽰为属性设值,p:list-ref 表⽰采⽤List属性,引⽤其上下⽂对应好的Bean,这⾥显然是util命名空间定义的List,Map和Set同理。
util 命名空间:⼯具类的命名空间,可以简化集合类元素的配置。下表提供了util-命名空间提供的所有元素:
util元素描述
<util:constant>引⽤某个类型的 public static 域,并将其暴露为 bean
<util:list>创建⼀个 java.util.List 类型的 bean,其中包含值或引⽤
<util:map>创建⼀个 java.util.map 类型的 bean,其中包含值或引⽤
<util:properties>创建⼀个 java.util.Properties 类型的 bean
<util:property-path>引⽤⼀个 bean 的属性(或内嵌属性),并将其暴露为 bean <util:set>创建⼀个 java.util.Set 类型的 bean,其中包含值或引⽤
参考资料:
《Java EE 互联⽹轻量级框架整合开发》
《Spring 实战》(第四版)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论