标签:驱动程序 ssi 管理 第一个 require 文档 Edito merge 出现
接上篇:Spring 核心技术(3)
version 5.1.8.RELEASE
如上一节所述,你可以将 bean 属性和构造函数参数定义为对其他托管 bean(协作者)的引用,或者作为内联定义的值。Spring 基于 XML 的配置元数据为此目的支持子元素<property/>
和<constructor-arg/>
。
<property/>
元素的 value
属性指定一个属性或构造器参数为可读的字符串。Spring 的转换服务用于将这些值从 String
转换为属性或参数的实际类型。以下示例展示了要设置的各种值:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="masterkaoli"/>
</bean>
以下示例使用 p 命名空间进行更简洁的 XML 配置:
<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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="masterkaoli"/>
</beans>
前面的 XML 更简洁。但是,除非您在创建 bean 定义时使用支持自动属性完成的 IDE(例如 IntelliJ IDEA 或 Spring Tool Suite),否则会在运行时而不是设计时发现拼写错误。强烈建议使用此类 IDE 帮助。
还可以配置 java.util.Properties
实例,如下所示:
<bean id="mappings"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Spring 容器通过使用 JavaBeans PropertyEditor
机制将 <value/>
元素内的文本转换为 java.util.Properties
实例。这是一个很好的快捷方式,也是 Spring 团队建议嵌套 <value/>
元素而不是 value
属性的少数几个地方之一。
idref
元素idref
元素只是一种防错方法,可以将容器中另一个 bean 的 id
属性(字符串值 - 而不是引用)传递给 <constructor-arg/>
或 <property/>
元素。以下示例展示了如何使用它:
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
前面的 bean 定义代码段与以下代码段完全等效(运行时):
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
第一种形式优于第二种形式,因为使用 idref
标签可以让容器在部署时验证引用的命名 bean 是否存在。在第二个变体中,不会对传递给 client
bean targetName
属性的值执行验证。只有在 client
bean 真正实例化时才会发现拼写错误(很可能是致命的结果)。如果 client
bean 是原型 bean,那么可能在部署容器后很长时间才能发现此错误和产生的异常。
4.0 beans XSD 不再支持
idref
元素的local
属性,因为它不再提供除常规bean
引用以外的值。升级到 4.0 版本时,需要将现有idref local
引用更改idref bean
。
其中一个共同的地方(至少早于 Spring 2.0 版本),<idref/>
元素的值是 ProxyFactoryBean
bean 定义中 AOP 拦截器的配置项。指定拦截器名称时使用 <idref/>
元素可防止拼写错误的拦截器 ID。
ref
元素是 <constructor-arg/>
或 <property/>
定义元素内部的最终元素。在这里,你将 bean 指定属性的值设置为对容器管理的另一个 bean(协作者)的引用。引用的 bean 是要设置属性的 bean 的依赖项,并且在设置该属性之前根据需要对其进行初始化。(如果协作者是单例 bean,它可能已经被容器初始化。)所有引用最终都是对另一个对象的引用。作用域和有效性取决于是否通过 bean
、local
或 parent
属性指定其他对象的 ID 或名称。
通过 <ref />
标签的 bean
属性指定目标 bean 是最常用的方式,允许创建对同一容器或父容器中的任何 bean 的引用,不管它是否在同一 XML 文件中。bean
属性的值可以与目标 Bean 的 id
属性相同,也可以与目标 bean 的 name
属性之一相同。以下示例演示如何使用 ref
元素:
<ref bean="someBean"/>
通过 parent
属性指定目标 bean 会创建对当前容器的父容器中的 bean 的引用。parent
属性的值可以与目标 bean 的 id
属性相同,也可以与目标 bean 的 name
属性之一相同。目标 bean 必须位于当前 bean 的父容器中。当容器具备层次结构,且希望和父级 bean 一样通过代理的方式包装父容器中现有的 bean 时,应该主要使用 bean 引用变量。以下一对列表演示了如何使用该 parent
属性:
<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
<!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
4.0 beans XSD 不再支持
ref
元素的local
属性,因为它不再提供除常规bean
引用以外的值。升级到 4.0 架构时,需要将现有ref local
引用更改ref bean
。
<property/>
或 <constructor-arg/>
元素中的 <bean/>
元素定义一个内部 bean,如下面的示例所示:
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
内部 bean 定义不需要定义 ID 或名称。即使指定,容器也不使用其作为标识符。容器也会在创建时忽略 scope
标志,因为内部 bean 始终是匿名的,并且始终和外部 bean 一起创建。内部 bean 无法单独访问或注入协作 bean 中。
作为一个极端情况,可以从自定义作用域接收销毁回调,例如包含在单例 bean 中作用域为 request 的内部 bean。内部 bean 实例的创建与包含它的 bean 相关联,但是销毁回调允许它参与 request 作用域的生命周期。这不是常见的情况。内部 bean 通常只是共享包含它的 bean 的作用域。
<list/>
、<set/>
、<map/>
和 <props/>
元素分别设置 Java Collection
类型 List
、Set
、Map
和 Properties
的属性和参数。以下示例演示了如何使用它们:
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
map 的键或值,或 set 的值,可以是以下任何元素:
bean | ref | idref | list | set | map | props | value | null
集合合并
Spring 容器支持合并集合。应用程序开发人员可以定义父级 <list/>
、<map/>
、<set/>
或 <props/>
元素,并定义子元素 <list/>
、<map/>
、<set/>
或 <props/>
继承并覆盖父集合的值。也就是说,子集合的元素会覆盖父集合中指定的值,子集合的值是合并父集合和子集合的元素的结果。
关于合并的这一部分讨论了父子 bean 机制。不熟悉父子 bean 定义的读者可能希望在继续阅读之前阅读之前阅读相关部分。
以下示例演示了集合合并:
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
注意 child
bean 定义中 adminEmails
属性的 <props/>
元素的 merge=true
属性的使用。当容器解析并实例化 child
bean 时,生成的实例有一个 adminEmails
Properties
集合,其中包含将子集合 adminEmails
与父 adminEmails
集合合并的结果 。以下清单显示了结果:
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
子元素的 Properties
集合的值继承了父元素 <props/>
的所有属性元素,子元素中 support
的值将覆盖父集合的值。
这一合并行为同样适用于 <list/>
、<map/>
和 <set/>
集合类型。在 <list/>
元素的特定场景中,建议保持与 List
集合类型(即有序集合的概念)相关联的语义。父级的值位于所有子级列表的值之前。在 Map
、Set
和 Properties
集合类型场景中,不存在次序的。因此,容器内部使用的 Map
、Set
以及 Properties
实现类也是无序的。
集合合并的局限性
你无法合并不同的集合类型(例如 Map
和 List
)。如果你尝试这样做,则会抛出对应的 Exception
。merge
属性必须在较低层级的子定义上指定。在父集合定义上指定 merge
属性是多余的,不会导致所需的合并。
强类型集合
通过在 Java 5 中引入的泛型类型,你可以使用强类型集合。也就是说,可以声明一种 Collection
类型,使得它只能包含(例如)String
元素。如果使用 Spring 将强类型 Collection
依赖注入到 bean 中,可以使用 Spring 的类型转换支持,以便强类型 Collection
实例的元素在添加到 Collection
之前转换为适当的类型。以下 Java 类和 bean 定义演示了如何执行此操作:
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
当 something
bean 的 accounts
属性已经准备注入时,通过反射可获得关于强类型的元素 Map<String, Float>
的泛型信息。因此,Spring 的类型转换机制将各种值识别为 Float
类型,并将字符串值(9.99
, 2.75
和 3.99
)转换为实际 Float
类型。
Spring 将属性等的空参数视为空字符串。以下基于 XML 的配置元数据片段将 email
属性设置为空字符串("")。
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
上面的示例等效于以下 Java 代码:
exampleBean.setEmail("");
<null/>
元素可以处理 null
值。以下显示了一个示例:
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
上述配置等同于以下 Java 代码:
exampleBean.setEmail(null);
带有 p 命名空间的 XML 快捷方式
p 命名空间允许你使用 bean
元素的属性(而不是嵌套 <property/>
元素)来描述属性值或协作 bean
。
Spring 支持具备命名空间的可扩展配置格式,这些命名空间基于 XML Schema 定义。本章中讨论的 beans
配置格式在一个 XML Schema 文档中定义。但是,p 命名空间未在 XSD 文件中定义,仅存在于 Spring 的核心中。
以下示例显示了两个 XML 片段(第一个使用标准 XML 格式,第二个使用 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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="someone@somewhere.com"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="someone@somewhere.com"/>
</beans>
该示例演示了 bean 定义中调用的 p 命名空间设置 email
属性。这告诉 Spring 包含一个属性声明。如之前所述,p 命名空间没有模式定义,因此可以将属性的名称设置为属性名。
下一个示例包括另外两个 bean 定义,它们都引用了另一个 bean:
<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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
此示例不仅包含使用 p 命名空间的属性值,还使用特殊格式来声明属性引用。第一个 bean 定义使用 <property name="spouse" ref="jane"/>
创建从 bean john
到 bean jane
的引用 ,而第二个 bean 定义使用 p:spouse-ref="jane"
作为属性来执行完全相同的操作。在这种情况下,spouse
是属性名称,而 -ref
部分表示这不是直接值,而是对另一个 bean 的引用。
p 命名空间不如标准 XML 格式灵活。例如,声明属性引用的格式与
Ref
结尾的属性冲突,而标准 XML 格式则不会。我们建议仔细选择你的方法并将其传达给其他团队成员,以避免生成同时使用三种方法的 XML 文档。
带有 c 命名空间的 XML 快捷方式
与带有 p 命名空间的 XML 快捷方式类似,Spring 3.1 中引入的 c 命名空间允许使用内联属性来配置构造函数参数,而不是嵌套 constructor-arg
元素。
以下示例使用 c:
命名空间执行与基于构造函数的依赖注入相同的操作:
<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">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>
</beans>
通过名称设置构造函数参数时,c:
命名空间和 p:
使用相同的约定(尾部 -ref 的 bean 引用)。类似地,它需要在 XML 文件中声明,即使它没有在 XSD schema 中定义(它存在于 Spring 核心内部)。
对于构造函数参数名称不可用的罕见情况(通常在没有调试信息的情况下编译字节码),可以使用备用的参数索引,如下所示:
<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
c:_2="something@somewhere.com"/>
因为采用 XML 语法,且 XML 属性名称不能以数字开头(即使某些 IDE 允许),所以索引表示法要求存在前缀
_
。<constructor-arg>
元素也可以使用相应的索引符号,但不常用,因为声明顺序通常就足够了。
实际上,构造函数解析机制在匹配参数时非常有效,因此除非确实需要,否则我们建议在整个配置中使用名称表示法。
设置 bean 属性时,可以使用复合或嵌套属性名称,只要除最终属性名称之外的路径的所有组件都不是 null。请看以下 bean 定义:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
something
bean 具有一个 fred
属性,fred
属性包含 bob
属性,bob
属性包含 sammy
属性,最终 sammy
属性的值被设置为 123。为了确保其可以正常运行,在构造 bean 之后,something
的 fred
属性和 fred
属性的 bob
属性不得为 null。否则将会抛出 NullPointerException
。
depends-on
如果一个 bean 是另一个 bean 的依赖项,那通常意味着将一个 bean 设置为另一个 bean 的属性。通常情况下可以使用基于 XML 的配置元数据中的 <ref/>
元素来完成此操作。但是,有时 bean 之间的依赖关系不那么直接。例如需要在类中触发的静态初始化程序,例如数据库驱动程序注册。depends-on
属性可以在初始化使用此元素的 bean 之前显式的强制初始化一个或多个 bean。以下示例使用 depends-on
属性表示对单个bean的依赖关系:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
要表示对多个 bean 的依赖关系,请提供 bean 名称列表作为 depends-on
属性的值(逗号,空格和分号是有效的分隔符):
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
depends-on
属性可以指定初始化时的依赖性,也可以指定单例 bean 销毁时的依赖性。通过depends-on
定义的依赖项会在指定 bean 本身销毁之前被销毁。这样,depends-on
也可以控制停止顺序。
默认情况下,ApplicationContext
实现会在初始化时创建和配置所有单例 bean,作为初始化过程的一部分。通常,这种预先实例化是合理的,因为配置或环境中的错误可以立刻被发现,而不是几小时甚至几天后。当不希望出现这种情况时,可以通过将 bean 定义标记为延迟初始化来阻止单例 bean 的预实例化。延迟初始化的 bean 告诉 IoC 容器在第一次请求时创建 bean 实例,而不是在启动时。
在 XML 中,此行为由 <bean/>
元素的 lazy-init
属性控制,如以下示例所示:
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
当前面的配置被 ApplicationContext
使用时,lazy
bean 不会在 ApplicationContext
启动时预先实例化,而 not.lazy
bean 会被预先实例化。
但是当延迟初始化的 bean 是未进行延迟初始化的单例 bean 的依赖项时,ApplicationContext
会在启动时创建延迟初始化的 bean
,因为它必须满足单例的依赖关系。延迟初始化的 bean
会被注入到其他不是延迟初始化的单例 bean 中。
你还可以通过使用 <beans/>
元素的 default-lazy-init
上的属性来控制容器级别的延迟初始化,如以下示例显示:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
标签:驱动程序 ssi 管理 第一个 require 文档 Edito merge 出现
原文地址:https://www.cnblogs.com/aotian/p/11235013.html