目录
十、p命名空间和c命名空间
十、p命名空间和c命名空间
老版本的Spring框架XML配置文件是使用DTD的,但是在目前Spring框架中多使用XSD。因为在XSD扩 展支持。这也是为什么Spring框架配置文件由原来的DTD更换成XML Schema,毕竟Spring现在是模块化了,用哪个模块,XML文件支持这个模块的配置会更好。
1. DTD 和 XSD复习
Spring Framework在老版本时配置文件支持DTD,但是随着Spring框架项目拆分,配置文件也变为 XSD。下面我们来复习一下DTD和XSD。
DTD 复习
DTD (Document Type Definition,文档类型定义)属于XML文档的一部分。作用是对XML文档内容进行校验。
缺点:
1、独立语法,没有使用XML语法。例如:spring-beans.dtd文件部分截图
2、支持类型较少。只有(#PCDATA)类似Java中的字符串类型。
3、扩展能力差。一个XML文件只能导入一个DTD。当需要扩展,必须更换整个DTD文件。例如 MyBatis框架配置文件就是用的是DTD。
XSD复习
XSD(XML Schemas Definition,XML结构定义)属于DTD的升级版。相对DTD来说XSD具备更多优点。
1、XSD本身就是一个XML文档,所以使用XML的语法。例如:spring-beans.xsd截图
2、 支持类型较多。支持简单数据类型和复杂类型。
简单类型
复杂类型
支持扩展。只需要在 xsi:schemaLocation 中添加一组键值对。其中key表示XSD文件名称,value 表示XSD文件路径。如果需要添加新的XSD粘贴到这里面就可以,但需要保证Key和Value不分家 (中间没有其他键值对)。
支持命名空间.XSD支持对标签和标签属性的扩展。命名空间作为根标签(beans)的一个属性。 语法为 xmlns:自定名称="key"
使用时为
<标签 自定名称:xxx=""> 或 <自定义名称:标签名 >
大部分命名空间的key需要与 xsi:schemaLocation 中键值对的key对应。但是部分内容没有xsd文 件,因为这个命名空间没有内容限制,而是通过反射根据类的内容而决定。下面学习的p命名空间 和c命名空间就是没有添加xsd键值对的实际应用。
2. p命名空间
Spring 框架提供了p命名空间,属于 <property> Setter注入的简写方式。所以p就是property的缩写。 但是要注意,p命名空间是为了代替 <property name="" ref=""/> 和 <property name="" value=""> 这两种写法。
使用时需要在xml文件中导入p命名空间。
xmlns: 代表Schema的命名空间的意思。
p是命名空间的名称。可以修改的。但是为了增加可读性,官方叫什么,我们就跟着叫什么。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
我们重新建立一个类,进行测试
public class Animate {
private int id;
private String name;
// 省略getter、setter、构造方法
}
在没有使用p命名空间时
<bean id="animate" class="com.tong.pojo.Animate">
<property index="0" value="1"></property>
<property name="name" value="毛毛"></property>
</bean>
使用p命名空间后的简写方式。
语法:p:属性名="值" 或 p:_序号="值"
<bean id="animate2" class="com.tong.pojo.Animate" p:_0="2" p:name="旺财"></bean>
3.c命名空间
Spring 框架提供了c命名空间,属于<constructor-args> 构造注入的简写方式。所以c就是constructor 的缩写。
但是要注意,c命名空间只提供了<constructor-args> 中name和index属性等效效果,而且还不能混 合使用。也就是说当构造方法比较多,且无法通过一个属性就能明确确认构造方法时,不要使用c命名空间。
c命名空间需要在配置文件中添加新的Schema配置
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
在没有使用c命名空间时
<bean id="animate" class="com.tong.pojo.Animate">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg index="1" value="毛毛"></constructor-arg>
</bean>
在使用c命名空间简写后的写法。
语法:c:属性名="值" 或 c:_序号="值"
<bean id="animate2" class="com.tong.pojo.Animate" c:id="2" c:_1="旺财" ></bean>
4.util命名空间
util命名空间从Spring Framework 2.0开始就有了。但是作为Spring框架支持的命名空间,还是有必要 给小伙伴们介绍一下。
util命名空间主要的作用简化定义集合类型Bean、常量类型Bean的语法。实现快速给特定类型定义为 Bean。像这种给特定类型单独定义成Bean是为了这个类型值实现复用,其他Bean可以通过ref直接引用,但是util命名空间的作用是简化定义的语法,而不是为了复用。
想要使用util命名空间,必须在Spring框架配置文件中导入对应的xsd文件路径及命名空间。
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
https://www.springframework.org/schema/util/spring-util.xsd">
</beans>
导入命名空间后,可以发现util一共支持6个标签,分别代表的含义:
1、util:constant 定义常量 util:list 定义list集合
2、util:map 定义map集合 util:properties 定义属性文件
3、util:property-path 使用连缀写法给关联Bean属性赋值。
4、util:set 定义set集合
4.1 util:constant
先创建一个类,类中包含一个静态属性com.tong.pojo.MyUtil
public class MyUtil {
public static String NAME="smallmming";
}
当我们想要把上面这个静态变量定义为一个Bean时,必须借助FieldRetrievingFactoryBean才能定义。
<bean id="myName" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField" value="com.tong.pojo.MyUtil.NAME"></property>
</bean>
上面的写法也有一种简写方式
<bean id="com.tong.pojo.MyUtil.NAME" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
</bean>
简写方式已经比较简单了,但是最简单的方式还是使用util命名空间。不需要再去记忆 FieldRetrievingFactoryBean这个类。
<util:constant static-field="com.tong.pojo.MyUtil.NAME"></util:constant>
如果定义完成后,想要把常量Bean注入到其他类属性中
先定义一个类com.tong.pojo.Demo
public class Demo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Demo{" +
"name='" + name + '\'' +
'}';
}
}
修改配置文件,给util:constant定义一个id,然后让Demo的name属性ref这个id值。
<util:constant static-field="com.tong.pojo.MyUtil.NAME" id="myUtilName"></util:constant>
<bean id="demo" class="com.tong.pojo.Demo">
<property name="name" ref="myUtilName"></property>
</bean>
编写测试
@Test
void util(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext5.xml");
Demo demo = ac.getBean("demo", Demo.class);
System.out.println(demo);
}
4.2 util:list
当我们想要定义一个List类型Bean时,必须借助ListFactoryBean
<bean id="myList" class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
</bean>
如果不想要去记忆ListFactoryBean,可以使用util命名空间。
1、 list-class 定义List接口的实现类是谁。默认是ArrayList。
2、value-type 定义List的值类型,即泛型类型。否则由Spring框架判断。
注意:对于初学者,很容易在util:list里面又套一个 <list>标签,如果写上了,相当于 List<List<String>>
<util:list id="myUtilList" list-class="java.util.LinkedList" value-type="java.lang.String">
<value>a</value>
<value>b</value>
<value>c</value>
</util:list>
相同道理如果想要把定义成List的Bean注入给某个Bean的属性,依然使用ref引用id即可。
修改Demo类,添加list属性,生成getter、setter方法,和toString()方法
public class Demo {
private String name;
private List<?> list;
public List<?> getList() {
return list;
}
public void setList(List<?> list) {
this.list = list;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Demo{" + "name='" + name + '\'' + ", list=" + list +'}';
}
}
修改配置文件中Demo的bean
<bean id="demo" class="com.tong.pojo.Demo">
<property name="name" ref="myUtilName"></property>
<property name="list" ref="myUtilList"></property>
</bean>
运行结果,可以发现正常输出list属性值。
4.3 util:map
正常定义一个Map类型的Bean需要借助MapFactoryBean
<bean id="myMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="a" value="a1"></entry>
<entry key="b" value="b1"></entry>
</map>
</property>
</bean>
使用util命名空间简化后的写法。可以定义map的细节
1、key-type 定义map的key类型
2、value-type 定义map的value类型
3、map-class 定义使用map接口的哪个实现类,默认是HashMap
<util:map id="myUtilMap" key-type="java.lang.String" value-type="java.lang.String" map-
class="java.util.TreeMap">
<entry key="c" value="c1"></entry>
<entry key="d" value="d1"></entry>
</util:map>
4.4 util:set
正常定义Set类型Bean需要借助SetFactoryBean
<bean id="mySet" class="org.springframework.beans.factory.config.SetFactoryBean">
<property name="sourceSet">
<set>
<value>a</value>
<value>b</value>
</set>
</property>
</bean>
使用util:set简化后的语法
<util:set id="myUtilSet" value-type="java.lang.String" set-class="java.util.TreeSet">
<value>c</value>
<value>c</value>
</util:set>
4.5 util:properties
Properties是从java 1.0就出现的类,是HashTable的子类,存放键值对值。常与物理文件.properties文
件对应。
正常定义一个Properties类型Bean,需要借助PropertiesFactoryBean。
可以直接给定固定值,也可以从外部读取properties文件。在src/main/resources下新建my.properties
文件。
<!-- 使用固定值定义一个properties类型Bean -->
<bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="a">a1</prop>
<prop key="b">b1</prop>
</props>
</property>
</bean>
<!-- 读取外部properties文件定义一个properties类型Bean -->
<bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:my.properties"></property>
</bean>
使用util:properties简化后的代码
<util:properties id="myUtilProperties" value-type="java.lang.String">
<prop key="c">c1</prop>
<prop key="d">d1</prop>
</util:properties>
<util:properties id="myUtilProperties2" location="classpath:my.properties">
</util:properties>
4.6 util:property-path
如果想要把某个Bean的属性单独定义成一个Bean,需要借助PropertyPathFactoryBean。 注意:既然是某个Bean的属性要定义成一个Bean,就必须现有这个某个Bean。
<bean id="demo" class="com.tong.pojo.Demo">
<property name="name" ref="myUtilName"></property>
<property name="list" ref="myUtilList"></property>
</bean>
<bean id="demo.name" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"></bean>
使用util:property-path简化后的代码
<bean id="demo" class="com.tong.pojo.Demo">
<property name="name" ref="myUtilName"></property>
<property name="list" ref="myUtilList"></property>
</bean>
<util:property-path id="myPropertyPath" path="demo.age"></util:property-path>