标签:scope dev outer roo idea 导致 有一个 结构 要求
如上一节所述,你可以将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定义时使用支持自动属性填充的IntelliJ IDEA或Spring Tool Suite(STS)等IDE,否则会在运行时而不是设计时发现拼写错误。强烈建议使用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实例。嵌套<value />元素是一个很好的快捷方式,并且是Spring团队推荐使用的少数几个地方之一。
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本地引用更改为idref bean即可。
<idref />元素传值的常见地方(至少在Spring 2.0之前的版本中)是在AOP拦截器的配置中定义ProxyFactoryBean bean的地方。指定拦截器名称时使用<idref />元素可以防止拦截器ID拼写错误。
ref元素是<constructor-arg />或<property />定义元素中的最后一个元素。在这里,你将bean的指定属性的值设置为对容器管理的另一个bean(协作者)的引用。引用的bean是属性将被设置的bean的依赖项,并且在设置属性之前根据需要按需初始化。(如果协作者是单例bean,它可能已经被容器初始化了。)所有引用最终都是对另一个对象的引用。作用范围和校验取决于你是否通过bean,local或parent属性指定其他对象的id / name。
通过<ref />标记的bean属性指定目标bean是最常用的形式,并允许创建对同一容器或父容器中的任何bean的引用,而不管它是否在同一个XML文件中。bean属性的值可以与目标bean的id属性相同,也可以是目标bean的name属性中的值之一。
<ref bean="someBean"/>
通过parent属性指定目标bean会创建一个属于当前容器的父容器中的bean的引用。 parent属性的值可以与目标bean的id属性相同,也可以与目标bean的name属性中的一个值相同,并且目标bean必须位于当前bean的父容器中。你主要是在拥有容器的层次结构并且希望通过一个与父bean具有相同名称的代理包装一个父容器中的现有的Bean的时候使用这种bean的引用变体。
<!-- in the parent context -->
<bean id="accountService" class="com.foo.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 bean xsd不再支持ref元素的local属性,因为它不再提供常规bean引用的值。 升级到4.0架构时,只需将现有的ref本地引用更改为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,或者单独访问它们。
作为极端情况,可以接收来自自定义范围的销毁回调,例如,对一个包含在单例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的key值或者value值,或者set值,也可以是以下任何元素:
bean | ref | idref | list | set | map | props | value | null
Spring容器还支持集合的合并。 应用程序开发人员可以定义<list />,<map />,<set />或<props />元素的父样式,并且可以具有从父集合中继承并覆盖的值的<list />,<map />,<set />或 <props />元素的子样式。也就是说,子集合的值是合并父集合和子集合的元素的结果,子集合的元素覆盖父集合中指定的值。
关于合并的这一部分讨论了父子bean机制。在继续本节之前,不熟悉父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>
注意在子bean定义的adminEmails属性的<props />元素上使用merge = true属性。当容器解析并实例化子bean时,生成的实例有一个adminEmails属性集合,其中包含子项的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引入了泛型类型,因此你可以使用强类型集合。也就是说,例如,可以声明只能包含String元素Collection类型。 如果你使用Spring依赖注入一个强类型的Collection到bean中,你可以利用Spring的类型转换的优势去支持,在被添加到Collection之前,将这样强类型Collection实例的元素转换为适当的类型。
public class Foo { private Map<String, Float> accounts; public void setAccounts(Map<String, Float> accounts) { this.accounts = accounts; } }
<beans>
<bean id="foo" class="x.y.Foo">
<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>
当foo bean的accounts属性准备好注入时,可以通过反射获得有关强类型Map <String,Float>的元素类型的泛型信息。因此,Spring的类型转换体系结构将各种值元素识别为Float类型,并将字符串值9.99,2.75和3.99转换为实际的Float类型。
Spring将属性为空的参数视为空Strings。以下基于XML的配置元数据片段将email属性设置为空String值(“”)。
<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命名空间可以让你使用bean元素的属性代替嵌套的<property />元素来描述属性值和/或协作bean。
Spring支持具有命名空间的可扩展配置格式,这些命名空间基于XML Schema定义。 本章中讨论的bean配置格式定义在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="foo@bar.com"/> </bean> <bean name="p-namespace" class="com.example.ExampleBean" p:email="foo@bar.com"/> </beans>
该示例显示了bean定义中名为email的p命名空间中的属性。 这告诉Spring包含一个属性声明。 如前所述,p命名空间没有模式定义,因此你可以将attribute的名称设置为property的名称。
下一个示例包含超过两个的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”作为属性,去做与第一个Bean完全相同的事情。在这种情况下,spouse是属性名称,而-ref部分表示这不是直接值,而是对另一个bean的引用。
注意:p命名空间不如标准XML格式灵活。例如,声明属性引用的格式与以Ref结尾的属性冲突,而标准XML格式则不然。 我们建议你仔细选择你的方法并将其告诉给你的团队成员,以避免生成同时使用这三种方法的XML文档。
类似于“c命名空间简化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="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <!-- traditional declaration --> <bean id="foo" class="x.y.Foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> <constructor-arg value="foo@bar.com"/> </bean> <!-- c-namespace declaration --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/> </beans>
c:名称空间使用与p:(以-ref结尾的,用于bean引用)相同的惯例,用于按名称设置构造函数参数。同样,它需要声明,即使它没有在XSD模式中定义(但它存在于Spring核心中)。
对于像构造函数参数名称不可用的这样极少的情况(通常,如果字节码是在没有调试信息的情况下编译的话),可以使用参数索引:
<!-- c-namespace index declaration -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/>
注意:由于XML语法,索引表示法要求:以_作为开头的XML属性名称不能以数字开头(即使某些IDE允许它)。
实际上,构造函数解析机制在匹配参数方面非常有效,因此除非确实需要,否则我们建议在整个配置中使用名称表示法。
只要除最终属性名称之外的此路径的所有组件都不为null,你可以在设置bean属性时使用复合或嵌套属性名称。请思考以下bean定义。
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>
foo bean有一个fred属性,它有一个bob属性,它有一个sammy属性,最后的sammy属性被设置为值123。为了使其生效,foo的fred属性和bob属性,在构造bean之后,fred禁止为null,否则会抛出NullPointerException。
Spring框架参考手册(4.2.6版本)翻译——第三部分 核心技术 6.4.2 依赖注入和配置的细节
标签:scope dev outer roo idea 导致 有一个 结构 要求
原文地址:https://www.cnblogs.com/springmorning/p/10327832.html