7 -- Spring的基本用法 -- 5...
7.5 Spring容器中的Bean
7.5.1 Bean的基本定义和Bean别名
<beans.../>元素是Spring配置文件的根元素,该元素可以指定如下属性:
default-lazy-init : 指定该<beans.../> 元素下配置的所有Bean默认的延迟初始化行为。
default-merge : 指定该<beans.../> 元素下配置的所有Bean默认的merge行为。
default-autowire : 指定该<beans.../> 元素下配置的所有Bean 默认的自动装配行为。
default-autowire-candidates: : 指定该<beans.../> 元素下配置的所有Bean 默认是否作为自动装配的候选Bean。
default-init-method : 指定该<beans.../> 元素下配置的所有Bean 默认的初始化方法。
default-destroy-method : 指定该<beans.../> 元素下配置的所有Bean 默认的回收方法。
<beans.../>元素下所能指定的属性都可以在每个<bean.../>子元素中指定----将属性名去掉default即可。区别是:为<bean.../>指定的这些属性,只对特定Bean起作用;如果在<beans.../>元素下指定这些属性,这些属性将会对<beans.../>包含的所有Bean都起作用。当二者所指定的属性不一致时,<bean.../>下指定的属性会覆盖<beans.../>下指定的属性。
<bean.../>元素的id属性具有唯一性,而且是一个真正的XML ID 属性,因此其他XML元素在引用id时,可以利用XML解析器的验证功能。
指定别名有两种方式:
⊙ 定义<bean.../>元素时通过name属性指定别名;如果需要为Bean实例指定多个别名,则可以在name属性中使用逗号、冒号或者空格来分隔多个别名,后面通过任一别名即可访问该Bean实例。
⊙ 通过<alias.../>元素为已有的Bean指定别名。
<alias name="" alias=""/> name:指定一个Bean实例的标识名,表明将为该Bean实例指定别名;alias:指定一个别名。
<bean id="person" class="edu.pri.lime._7_4_5.bean.Person" name="chinese,lime,oracle"/>
<alias name="person" alias="jackson"/>
<alias name="person" alias="tomcat"/>
7.5.2 容器中Bean的作用域
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。
⊙ singleton : 单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
⊙ prototype : 每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
⊙ request : 对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
⊙ session : 对于一次HTTP回话,session作用域的Bean将只生成一个实例,这意味着,在同一次HTTP回话内,程序每次请求该Bean,得到的总是同一个实例。只有在Web应用中使用Spring时,该作用域才真正有效。
⊙ global session : 每个全局的HTTP Session对应一个Bean实例。在典型的情况下,仅在使用portlet context的时候有效。只有在Web应用中使用Spring时,该作用域才真正有效。
比较常用的是singleton和prototype两种作用域,对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new关键字创建Bean实例,一旦创建成功,容器就不再跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。
Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域的Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,就可以重复使用。
Spring配置文件通过scope属性指定Bean的作用域。
对于request作用域:
<bean id="loginAction" class="edu.pri.lime._7_5_2.bean.LoginAct" scope="request"/>
针对每次HTTP请求,Spring容器会根据loginAction Bean定义创建一个全新的LoginAction Bean实例,且该loginAction Bean 实例仅在当前HTTP Request内有效。因此,如果程序需要,完全可以自由更改Bean实例的内部状态;其他请求所获得的loginAction Bean实例无法感受到这种内部状态的改变。当处理请求结束时,request作用域的Bean实例将被销毁。
request、session作用域的Bean只对Web应用才真正有效。实际上通常只会将Web应用的控制器Bean指定成request作用域。
request和session作用域只在Web应用中才有效,并且必须在Web应用中增加额外配置才会生效。为了让request和session两个作用域生效,必须将HTTP请求对象绑定到为该请求提供服务的线程上,这是的具有request和session两个作用域的Bean实例能够在后面的调用链中被访问到。
对于支持Servlet2.4 及更新规范的Web容器,可以在Web应用的web.xml文件中增加如下Listener配置,该Listener负责是request作用域生效。
Web : Listener
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
对于只支持Servlet2.4 以前规范的Web容器,则该容器不支持Listener规范,故无法使用这种配置方式,只能改为使用Filter配置方式。
Web :Filter
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
一旦web.xml中增加了如上任意一种配置,程序就可以在Spring配置文件中使用request或session作用域了。
xml :app_7_5_2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 指定使用request作用域 -->
<!-- 这样Spring容器会为每次HTTP请求生成一个Person实例,当请求响应结束时,该实例也随之消失。 -->
<bean id="per" class="edu.pri.lime._7_4_5.bean.Person" scope="request" /> <!-- 默认作用域为singleton -->
<bean id="chinese" class="edu.pri.lime._7_4_5.bean.Person" />
<!-- 指定作用域为prototype -->
<bean id="french" class="edu.pri.lime._7_4_5.bean.Person" scope="prototype" />
<bean id="date" class="java.util.Date" />
<bean id="loginAction" class="edu.pri.lime._7_5_2.bean.LoginAct"
scope="request" /> </beans>
如果Web应用直接使用Spring MVC作为MVC框架,即用SpringDispatcherServlet或DispatcherPorlet来拦截所有用户请求,则无须这些额外的配置,因为Spring DispatcherServlet和DispatcherPortlet已经处理了所有和请求有关的状态处理。
Jsp :
<%
/* 获取Web应用初始化的Spring容器 */
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext("app_7_5_2.xml");
/* 两次获取容器中id为per的Bean */
Person perA = (Person)ctx.getBean("per");
Person perB = (Person)ctx.getBean("per");
out.println((perA == perB) + "<br/>");
out.println(perA); %>
7.5.3 配置依赖
Java 应用中各组件相互调用的实质可以归纳为依赖管理,根据注入方式的不同,Bean的依赖注入通常有如下两种形式。
设置注入 : 通过<property.../>元素驱动Spring执行setter方法。
构造注入 : 通过<constructor-arg.../>元素驱动Spring执行带参数的构造器。
通常不建议使用配置文件管理Bean的基本类型的属性值;通常只使用配置文件管理容器中Bean与Bean之间的依赖关系。
对于singleton作用域的Bean,如果没有强行取消其预初始化行为,系统会在创建Spring容器时预初始化所有的singleton Bean,与此同时,该Bean所以来的Bean也被一起实例化。
BeanFactory 与 ApplicationContext 实例化容器中Bean的时机不同;BeanFactory等到程序需要Bean实例时才创建Bean;而ApplicationContext在容器创建ApplicationContext实例时,会预初始化容器中所有的singleton Bean。
因为采用ApplicationContext作为Spring容器,创建容器时会同时创建容器中所有singleton作用域的Bean,因此可能需要更多的系统开销。但一旦创建成功,应用后面的响应速度更快,因此,对于普通的Java EE 应用,推荐使用ApplicationContext作为Spring容器。
Spring的作用就是管理Java EE组件,Spring把所有的Java对象都称为Bean。因此完全可以把任何Java类都部署在Spring容器中----只要该Java类具有响应的构造器即可。Spring可以为任何Java对象注入任何类型的属性------只要该Java对象为该属性提供了对应的setter方法即可。
Java 类的成员变量可以是各种数据类型,出了基本类型值、字符串类型值等,还可以是其他Java 实例,也可以是容器中的其他Bean实例,甚至是Java 集合、数组等,所以Spring允许通过如下元素为setter方法、构造器参数指定参数值:
⊙ value
⊙ ref
⊙ bean
⊙ list、set、map 及 props
7.5.4 设置普通属性值------<value>
<value.../>元素用于指定基本类型及其包装、字符串类型的参数值,Spring使用XML解析器来解析出这些数据,然后利用java.beans.PropertyEditor完成类型转换:从java.lang.String类型转换为所需的参数值类型。
Class : ExampleBean
package edu.pri.lime._7_5_4.bean; public class ExampleBean { // 定义一个int型的成员变量
private int integerField;
// 定义一个double型的成员变量
private double doubleField;
// integerField和doubleField的setter和getter值
public int getIntegerField() {
return integerField;
}
public void setIntegerField(int integerField) {
this.integerField = integerField;
}
public double getDoubleField() {
return doubleField;
}
public void setDoubleField(double doubleField) {
this.doubleField = doubleField;
}
@Override
public String toString() {
return "ExampleBean [integerField=" + integerField + ", doubleField=" + doubleField + "]";
}
}
XML :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="exampleBean" class="edu.pri.lime._7_5_4.bean.ExampleBean">
<property name="integerField" value="1" />
<property name="doubleField" value="3.1" />
</bean> </beans>
Class : Test
package edu.pri.lime._7_5_4.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_5_4.bean.ExampleBean; public class Test { public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_5_4.xml");
ExampleBean exb = ctx.getBean("exampleBean",ExampleBean.class);
System.out.println(exb.toString());
}
}
7.5.5 配置合作者Bean------<ref.../>
如果需要为Bean设置的属性值是容器中的另一个Bean实例,则应该使用<ref.../>元素。使用<ref.../>元素时可指定一个bean属性,该属性用于引用容器中其他Bean实例的id属性值。
<!-- 配置名为chinese的Bean。其实现类是edu.pri.lime._7_3_3.bean.impl.Chinese类 -->
<bean id="chinese" class="edu.pri.lime._7_3_3.bean.impl.Chinese">
<!-- 驱动Spring调用Chinese的带一个参数的构造器来创建对象 -->
<constructor-arg ref="stoneAxe"/>
</bean>
<contructor-arg.../>运算也可增加ref属性,从而指定将容器中另一个Bean作为构造器参数。
7.5.6 使用自动装配注入合作者Bean------<beans default-autowire="" .../> 或 <bean autowire="" .../>
Spring 能自动装配Bean与Bean之间的依赖关系,即无须使用ref显示指定依赖Bean,而是有Spring容器检查XML配置文件内容,根据某种规则,为调用者Bean注入被依赖的Bean。
Spring 的自动装配可通过<beans.../>元素的default-autowire属性指定,该属性对配置文件中所有的Bean起作用;也可通过<bean.../>元素的autowire属性指定,该属性只对该Bean起作用。
自动装配可以减少配置文件的工作量,但降低了依赖关系的透明性和清晰性。
default-autowire、autowire属性可以接受如下值:
⊙ no : 不使用自动装配。Bean依赖必须通过ref元素定义。这是默认配置,在较大的部署环境中不鼓励改变这个配置,显示配置合作者能够得到跟清晰的依赖关系。
⊙ byName : 根据setter方法名进行自动装配。Spring 容器查找容器中的全部Bean,找出其id与setter方法匹配的Bean作为参数来完成注入。如果没有找到匹配的Bean实例,则Spring不会进行任何注入。
⊙ byType : 根据setter方法的形参类型来自动装配。Spring容器查找容器中的全部Bean,如果正好有一个Bean类型与setter方法的形参类型匹配,就自动注入这个Bean;如果找到多个这样的Bean,就抛出一个异常;如果没有找到这样的Bean,则什么都不会发生,setter方法不会被调用。
⊙ constructor : 与byType类似,区别是用于自动匹配构造器的参数。如果容器不能恰好找到一个与构造器类型匹配的Bean,则会抛出一个异常。
BUG ⊙ autodetect : Spring容器根据Bean内部结构,自行决定使用constructor或byType策略。如果找到一个默认的构造函数,那么就会应用byType策略。
⊙ default :
7.5.6.1 byName 规则
byName 规则是指setter方法的方法名与Bean的id进行匹配,假如Bean A的实现类包含setB()方法,而Spring的配置文件恰好包含id为b的Bean,则Spring容器会将b实例注入Bean A中。如果容器中没有名字匹配的Bean,Spring则不会做任何事情。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 指定使用byName策略,Spring会根据setter方法的方法名与Bean的id进行匹配 -->
<bean id="chinese" class="edu.pri.lime._7_5_6_1.bean.impl.Chinese" autowire="byName"/> <bean id="axe" class="edu.pri.lime._7_3_2.bean.impl.SteelAxe"/>
</beans>
7.5.6.2 byType 规则
byType 规则是根据setter方法的参数类型与Bean的类型进行匹配。假如A实例有setB(B b)方法,而Spring的配置文件中恰好有一个类型为B的Bean实例,容器为A注入类型匹配的Bean实例,如果容器中没有类型为B的实例,Spring不会调用setB()方法;但如果容器中包含多于一个的B实例,程序将会抛出异常。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 指定使用byType策略,Spring会根据setter方法的参数类型与Bean的类型进行匹配 -->
<bean id="chinese" class="edu.pri.lime._7_5_6_1.bean.impl.Chinese" autowire="byType"/> <bean id="steelAxe" class="edu.pri.lime._7_3_2.bean.impl.SteelAxe"/>
</beans>
当一个Bean既使用自动装配依赖,又使用ref显式指定依赖时,则显式指定的依赖覆盖自动装配依赖。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 即使china类中有setAxe(Axe axe) 方法,Spring也依赖以steelAxe作为调用setAxe()方法的参数,而不会以axe作为参数 -->
<bean id="china" class="edu.pri.lime._7_5_6_1.bean.impl.Chinese" autowire="byName">
<property name="axe" ref="stoneAxe"/>
</bean> <bean id="axe" class="edu.pri.lime._7_3_2.bean.impl.SteelAxe"/> <bean id="stoneAxe" class="edu.pri.lime._7_3_2.bean.impl.StoneAxe"/>
</beans>
在某些情况下,程序希望将某些Bean排除在自动装配之外,不作为Spring自动装配策略的候选者,此时可设置autowire-candidate属性,通过为<bean.../>元素设置autowire-candidate=“false”,即可将Bean排除在自动装配之外,容器在查找自动装配Bean时将不考虑该Bean。
还可通过在<beans.../>元素中指定default-autowire-candidates属性将一批Bean排除在自动装配之外。default-autowire-candidates属性的值允许使用模式字符串,例如指定default-autowire-candidates=“*abc”,则所有以“abc”结尾的Bean都将被排除在自动装配之外。不仅如此,该属性甚至可以指定多个模式字符串,这样所有匹配任意模式字符串的Bean都将被排除在自动装配之外。
7.5.7 注入嵌套Bean
如果某个Bean所依赖的Bean不想被Spring容器直接访问,则可以使用嵌套Bean。
把<bean.../>配置成<property.../>或<constructor-args.../>的子元素,那么该<bean.../>元素配置的Bean仅仅作为setter注入、构造注入的参数,这种Bean就是嵌套Bean。由于容器布恩那个获取嵌套Bean,因此它不需要指定id属性。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="chinese" class="edu.pri.lime._7_5_6_1.bean.impl.Chinese">
<!-- 驱动调用chinese的setAxe()方法,使用嵌套Bean作为参数 -->
<property name="axe">
<!-- 嵌套Bean配置的对象仅作为setter方法的参数,嵌套Bean不能被容器访问,因此无须指定id属性 -->
<bean class="edu.pri.lime._7_3_2.bean.impl.SteelAxe"/>
</property>
</bean> </beans>
使用嵌套Bean与使用ref引用ref引用容器中另一个Bean在本质上是一样的。
Spring框架的本质就是通过XML配置文件来驱动Java代码,当程序要调用setter方法或有参数的构造器时,程序总需要传入参数值,随参数类型的不同,Spring配置文件当然也要随之改变。
⊙ 形参类型是基本类型、String、日期等,直接使用value指定字面值即可。
⊙ 形参类型是复合类,那就需要传入一个Java队形作为实参,于是有两种方式:① 使用ref引用一个容器中已配置的Bean;② 使用<bean.../>元素配置一个嵌套Bean。
7.5.8 注入集合值
如果需要调用形参类型为集合的setter方法,或调用形参类型为集合的构造器,则可使用集合元素<list.../>、<set.../>、<map.../>和<props.../>分别来设置类型为List、Set、Map和Properties的集合参数值。
Class : Chinese
package edu.pri.lime._7_5_8.bean.impl; import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set; import edu.pri.lime._7_5_8.bean.Axe;
import edu.pri.lime._7_5_8.bean.Person; public class Chinese implements Person { // 集合类型的成员变量
private List<String> schools;
private Map scores;
private Map<String,Axe> phaseAxes;
private Properties health;
private Set axes;
private String[] books;
public Chinese() {
super();
System.out.println("Spring 实例化主调bean:Chinese实例...");
}
public List<String> getSchools() {
return schools;
}
public void setSchools(List<String> schools) {
this.schools = schools;
}
public Map getScores() {
return scores;
}
public void setScores(Map scores) {
this.scores = scores;
}
public Map<String, Axe> getPhaseAxes() {
return phaseAxes;
}
public void setPhaseAxes(Map<String, Axe> phaseAxes) {
this.phaseAxes = phaseAxes;
}
public Properties getHealth() {
return health;
}
public void setHealth(Properties health) {
this.health = health;
}
public Set getAxes() {
return axes;
}
public void setAxes(Set axes) {
this.axes = axes;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
// 访问全部的集合类型的成员变量
public void test(){
System.out.println(schools);
System.out.println(scores);
System.out.println(phaseAxes);
System.out.println(health);
System.out.println(axes);
System.out.println(Arrays.toString(books));
}
}
XML :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 定义2个普通的Axe Bean -->
<bean id="stoneAxe" class="edu.pri.lime._7_5_8.bean.impl.StoneAxe" />
<bean id="steelAxe" class="edu.pri.lime._7_5_8.bean.impl.SteelAxe" />
<!-- 定义chinese Bean -->
<bean id="chinese" class="edu.pri.lime._7_5_8.bean.impl.Chinese">
<!-- Spring 对List集合和数组的处理是一样的,都用<list.../>元素来配置 -->
<property name="schools">
<!-- 为调用setSchools()方法配置List集合作为参数值 -->
<list>
<!-- 每个value、ref、bean...都可配置一个List元素 -->
<value>小学</value>
<value>中学</value>
<value>大学</value>
</list>
</property>
<property name="scores">
<!-- 为调用setScores()方法配置Map集合作为参数值 -->
<map>
<!-- 每个entry都配置一个key-value对 -->
<entry key="数学" value="87" />
<entry key="英语" value="89" />
<entry key="语文" value="82" />
</map>
</property>
<property name="phaseAxes">
<!-- 为调用setPhaseAxes()方法配置Map集合作为参数 -->
<map>
<!-- 每个entry都配置一个key-value对 -->
<entry key="原始社会" value-ref="stoneAxe" />
<entry key="农业社会" value-ref="steelAxe" />
</map>
</property>
<property name="health">
<!-- 为调用prop元素都匹配一个属性项,其中key指定属性名 -->
<props>
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props>
<!--
<value>
pressure=normal
height=175
</value>
-->
</property>
<property name="axes">
<!-- 为调用setAxes()方法配置Set集合作为参数值 -->
<set>
<!-- 每个value、ref、bean...都配置一个Set元素 -->
<value>普通的字符串</value>
<bean class="edu.pri.lime._7_5_8.bean.impl.SteelAxe"/>
<ref bean="stoneAxe"/>
<!-- 为Set集合配置一个List集合作为元素 -->
<list>
<value>20</value>
<!-- 再次为List集合配置一个Set集合作为元素 -->
<set>
<value type="int">30</value>
</set>
</list>
</set>
</property>
<!-- Spring 对List集合和数组的处理是一样的,都用<list.../>元素来配置 -->
<property name="books">
<!-- 为调用setBooks()方法配置数组作为参数值 -->
<list>
<!-- 每个value、ref、bean...都可配置一个数组元素 -->
<value>li</value>
<value>me</value>
<value>Oracle</value>
</list>
</property>
</bean>
</beans>
Spring对List集合和数组的处理是一样的,都用<list.../>元素来配置。
当使用<list.../>、<set.../>、<map.../>等元素配置集合类型的参数值时,还需要配置集合元素。由于集合元素又可以是基本类型值、引用容器中的其他Bean、嵌套Bean或集合属性等,所以<list.../>、<key.../>和<set.../>元素又可接受如下子元素。
⊙ value : 指定集合元素是基本数据类型值或字符串类型值。
⊙ ref : 指定集合元素是容器中的另一个Bean实例。
⊙ bean : 指定集合元素是一个嵌套Bean。
⊙ list、set、map及props : 指定集合元素又是集合。
<props.../>元素用于配置Properties类型的参数值,Properties类型是一种特殊的类型,其key和value都只能是字符串,故Spring配置Properties类型的参数值比较简单:每个key-value对只要分别给出key和value就足够了------而且key和value都是字符串类型,所以使用如下格式的<prop.../>元素就够了。
⊙ <prop key="key">value</prop> : 其中<prop.../>元素的key属性指定key的值,<prop.../>元素的内容指定value的值。
当使用<map.../>元素配置Map参数值时,Map集合的每个元素由key、value两个部分组成,所以配置文件中的每个<entry.../>配置一组key-value对,其中<entry.../>元素支持如下4个属性:
⊙ key : 如果Map key是基本类型值或字符串,则可使用该属性来指定Map key。
⊙ key-ref : 如果Map key是容器中的另一个Bean实例,则可使用该属性指定容器中其他Bean的id。
⊙ value : 如果Map value 是节本类型值或字符串,则可使用该属性来指定Map value。
⊙ value-ref : 如果Map value 是容器中的另一个Bean实例,则可使用该属性指定容器中其他Bean的id。
Spring 还提供了一个简化语法来支持Properties形参的setter方法:但这种配置语法中属性名、属性值都只能是英文、数字,不可出现中文。
<property name="health">
<!-- 为调用prop元素都匹配一个属性项,其中key指定属性名 -->
<!-- <props>
<prop key="血压">正常</prop>
<prop key="身高">175</prop>
</props> -->
<value>
pressure=normal
height=175
</value>
</property>
从Spring 2.0 开始,Spring IoC容器支持集合的合并,子Bean中集合属性值可以从其父Bean的集合属性继承和覆盖而来。即子Bean的集合属性的最终值是父Bean、子Bean合并后的最终结果,而且子Bean集合的元素可以覆盖父Bean集合中对应的元素。
<beans>
<!-- 将父Bean定义成抽象Bean -->
<bean id="parent" abstract="true" class="edu.pri.lime._7_5_8.bean.impl.ComplexObject">
<!-- 定义Properties类型的集合属性 -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@crazyit.org</prop>
<prop key="support">support@crazyit.org</prop>
</props>
</property>
</bean>
<!-- 使用parent属性指定该Bean继承了parent Bean -->
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- 指定该集合属性支持合并 -->
<props merge="true">
<prop key="sales">sales@crazyit.org</prop>
<prop key="support">master@crazyit.org</prop>
</props>
</property>
</bean>
</beans>
由于泛型的支持,Java可以使用泛型指定集合元素的类型,Spring可通过反射来获取集合元素的类型,这样Spring的类型转换器就会起作用了。
Class : Test
package edu.pri.lime._7_5_8.bean.impl; import java.util.Map; public class Test {
// 程序使用了泛型限制了Map的key是String,value是double,Spring可根据泛型信息把配置文件的集合参数值转换成响应的数据类型
private Map<String,Double> prices; public void setPrices(Map<String, Double> prices) {
this.prices = prices;
} }
XML :
<bean id="test" class="">
<property name="prices">
<map>
<!-- 程序使用了泛型限制了Map的key是String,value是double,Spring可根据泛型信息把配置文件的集合参数值转换成响应的数据类型 -->
<entry key="li" value="23.1"/>
<entry key="me" value="32.1"/>
</map>
</property>
</bean>
Spring 会自动将每个entry中的key值转换成String类型,并将value指定的值转换成Double类型。
7.5.9 组合属性
Spring 还支持组合属性的方式。例如,使用配置文件为形如foo.bar.name的属性设置参数值。为Bean的组合属性设置参数值时,除最后一个属性之外,其他属性值都不允许为null。
Class : ExampleBean
package edu.pri.lime._7_5_9.bean; public class ExampleBean { // 定义一个Person类型的成员变量。使用组合属性设置参数值时person不能为空
private Person person = new Person(); public Person getPerson() {
return person;
} public void setPerson(Person person) {
this.person = person;
} }
Class : Person
package edu.pri.lime._7_5_9.bean; public class Person { private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
XML :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="exampleBean" class="edu.pri.lime._7_5_9.bean.ExampleBean">
<!-- 驱动Spring调用exampleBean的getPerson().setName()方法,以lime为参数 -->
<property name="person.name" value="lime" />
</bean>
</beans>
Class : TestBean
package edu.pri.lime._7_5_9.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_5_9.bean.ExampleBean; public class TestBean { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_5_9.xml");
ExampleBean exampleBean = ctx.getBean("exampleBean",ExampleBean.class);
System.out.println(exampleBean.getPerson().getName());
}
}
7.5.10 Spring的Bean和JavaBean
Spring容器对Bean没有特殊要求,甚至不需要该Bean像标准的JavaBean------必须为每个属性提供对应的getter和setter方法。
Spring中的Bean是Java实例、Java组件;传统Java应用中的JavaBean通常作为DTO(数据传输对象),用来封装值对象,在各层之间传递数据。
传统的JavaBean也可作为Spring的Bean,从而接受Spring管理。
eg:将数据源配置成容器中的Bean,该数据源Bean即可用于获取数据库连接。
XML :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 定义数据源Bean,使用C3P0数据源实现 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 指定连接数据库的驱动 -->
<property name="dirverClass" value="com.mysql.jdbc.Driver" />
<!-- 指定连接数据库的URL -->
<property name="jdbcUrl" value="jdbc:mysql://localhost/spring" />
<!-- 指定连接数据库的用户名 -->
<property name="user" value="root" />
<!-- 指定连接数据库的密码 -->
<property name="password" value="system" />
<!-- 指定连接数据库连接池的最大连接数 -->
<property name="maxPoolSize" value="200" />
<!-- 指定连接数据库连接池的最小连接数 -->
<property name="minPoolSize" value="2" />
<!-- 指定连接数据库连接池的初始连接数 -->
<property name="initialPoolSize" value="2" />
<!-- 指定连接数据库连接池的连接的最大空闲时间 -->
<property name="maxIdleTime" value="200" />
</bean>
</beans>
Class : BeanTest
package edu.pri.lime._7_5_10.main; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException; import javax.sql.DataSource; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class BeanTest { public static void main(String[] args) throws SQLException{
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_5_10.xml");
DataSource ds = ctx.getBean("dataSource",DataSource.class);
// 通过DataSource来获取数据库连接
Connection conn = ds.getConnection();
// 通过数据库连接获取PerparedStatement
PreparedStatement pstmt = conn.prepareStatement("insert into news_inf value(null,?,?)");
pstmt.setString(1, "lime Cry");
pstmt.setString(1, "lime Happy");
// 执行SQL语句
pstmt.executeUpdate();
// 清理资源,回收数据库连接资源
if(pstmt != null){
pstmt.close();
}
if(conn != null){
conn.close();
}
}
}
虽然Spring对Bean没有特殊要求,但依然建议Spring中的Bean应满足如下几个原则:
⊙ 尽量为每个Bean实现类提供无参数的构造器。
⊙ 接受构造注入的Bean,则应提供对应的、带参数的构造器。
⊙ 接受设置注入的Bean,则应提供对应的setter方法,并不要求提供对应的getter方法。
传统的JavaBean和Spring中的Bean之间的区别:
⊙ 用处不同 : 传统的JavaBean更多是作为值对象传递参数;Spring的Bean用处几乎无所不包,任何应用组件都被称为Bean。
⊙ 写法不同 : 传统的JavaBean作为值对象,要求每个属性都提供getter和setter方法;但Spring的Bean只需为接受设置注入的属性提供setter方法即可。
⊙ 生命周期不同 : 传统的javaBean作为值对象传递,不接受任何容器管理其生命周期;Spring中的Bean有Spring管理其声明周期行为。
7 -- Spring的基本用法 -- 5...的更多相关文章
- SpringMVC +mybatis+spring 结合easyui用法及常见问题总结
SpringMVC +mybatis+spring 结合easyui用法及常见问题总结 1.FormatString的用法. 2.用postAjaxFillGrid实现dataGrid 把form表单 ...
- Spring中@Async用法详解及简单实例
Spring中@Async用法 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类 ...
- (转)Spring中@Async用法总结
原文:http://blog.csdn.net/blueheart20/article/details/44648667 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的: ...
- Spring中@Async用法总结
引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3. ...
- spring AOP的用法
AOP,面向切面编程,它能把与核心业务逻辑无关的散落在各处并且重复的代码给封装起来,降低了模块之间的耦合度,便于维护.具体的应用场景有:日志,权限和事务管理这些方面.可以通过一张图来理解下: Spri ...
- Spring常用注解用法总结
转自http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由Dispat ...
- Spring中@Value用法收集
一.配置方式 @Value需要参数,这里参数可以是两种形式: @Value("#{configProperties['t1.msgname']}") 或者 @Value(" ...
- Spring data redis-StringRedisTemplate 用法
Spring-data-redis为spring-data模块中对redis的支持部分,简称为“SDR”,提供了基于jedis客户端API的高度封装以及与spring容器的整合,事实上jedis客户端 ...
- Spring.Net简单用法
Spring.Net其实就是抽象工厂,只不过更加灵活强大,性能上并没有明显的区别. 它帮我们实现了控制反转. 其有两种依赖注入方式. 第一:属性注入 第二:构造函数注入 首先,我们去 Spring. ...
- 7 -- Spring的基本用法 -- 6...
7.6 Spring 3.0 提供的Java配置管理 Spring 允许使用Java类进行配置管理,可以不使用XML来管理Bean,以及Bean之间的依赖关系. Interface :Person p ...
随机推荐
- C# 不重复的随机数
public int RabdomNumber() { num = new Random(Guid.NewGuid().GetHashCode()).Next(0, 40); return num; ...
- 3.Git的诞生和其分布式的优点
Git的诞生 省略了,喜欢的可以看百度. 分布式的优点 先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完 ...
- iOS 解决图片上传到服务器旋转90度的问题(图片倒置)
//使用swift的朋友们可以,把这个所在的类的.h,在-Header-Swift.h中一用一下. - (UIImage *)fixOrientation:(UIImage *)aImage { if ...
- Table排序
<html> <head> <title>tablesorter表单排序插件</title> <link type ="text/css ...
- 20161014006 DataGridView Combobox 数据绑定与传值
//Combobox private void T_Form_CY_CBD_D_CurrentCellChanged(object sender, EventArgs e) ...
- Xamarin.Forms listview中的button按钮,实现带着参数返回上一级页面
今天在做列表显示的时候遇到一个问题,就是在ListView中如何才能让一个button的按钮工作并且包含参数呢? 其实有点类似于rep里的控件无法起获取一样.在Xamarin中,当你button绑定事 ...
- 对json数据的遍历
json格式变化多样,可嵌套好几层,这里只记录了一些遍历方法,具体数据格式具体分析~ "data1": { "key1": [ {"name" ...
- R语言解读多元线性回归模型
转载:http://blog.fens.me/r-multi-linear-regression/ 前言 本文接上一篇R语言解读一元线性回归模型.在许多生活和工作的实际问题中,影响因变量的因素可能不止 ...
- C++Primer 5th 练习 12.19
这阵子真是太忙了, 连续做了四个课设. 当然这并不能作为好久没写博客的借口, 没写博客的主要原因只有一个: 懒. 最近又开始回顾C++的语法与特性(据说C++就是一门需要反复回顾的语言),以及学习C+ ...
- 如何离线创建Ionic/cordova项目
在创建ionic项目的时候,需要联网下载许多东西,由于墙的缘故,我们在创建.添加android平台.编译过程中,失败的可能性非常高,为解决这个问题,我创建了一个空的Ionic1 tab项目,并完成了上 ...