一、Spring Bean引用例子
1. Bean在不同的XML 文件
如果实在不同的XML配置文件中的Bean,可以用一个
[
标签,“bean”属性引用它:
]
1 2 3 4 5
|
<bean id="OutputHelper" class="com.myprj.output.OutputHelper"> <property name="outputGenerator" > <ref bean="CsvOutputGenerator"/> </property> </bean>
|
2. 在同一个XML文件中的Bean
如果引用在同一个XML文件中的bean,你可以用 ‘ref’ 标签,“local”属性引用它,使用时常省略。
1
|
<ref local="someBean"/>
|
二、如何注入值到Spring Bean属性
在Spring中,有三种方式将值注入到Bean的属性:
如下一个简单的Java类,包含两个数属性:name和type,稍后使用Spring注入值到这个Bean的属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
package com.myprj.common;
public class { private String name; private String type; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
|
1. 正常方式
在
标签中的
标签中赋值:
1 2 3 4 5 6 7 8
|
<bean id="FileNameGenerator" class="com.myprj.common.FileNameGenerator"> <property name="name"> <value>myprj</value> </property> <property name="type"> <value>txt</value> </property> </bean>
|
2. 快速方式
在
标签中的“value”属性赋值:
1 2 3 4
|
<bean id="FileNameGenerator" class="com.myprj.common.FileNameGenerator"> <property name="name" value="myprj" /> <property name="type" value="txt" /> </bean>
|
3. “p”模式方式
通过
标签中p模式赋值:
1 2 3 4
|
//... xmlns:p="http://www.springframework.org/schema/p" //... <bean id="FileNameGenerator" class="com.myprj.common.FileNameGenerator" p:name="myprj" p:type="txt" />
|
三、Spring Bean加载多个配置文件
1 2 3 4 5 6
|
<beans //... <import resource="common/Spring-Common.xml"/> <import resource="connection/Spring-Connection.xml"/> <import resource="moduleA/Spring-ModuleA.xml"/> </beans>
|
四、Spring 内部Bean实例
在Spring框架中,一个bean仅用于一个特定的属性,这是提醒其声明为一个内部bean。内部bean支持setter注入“property”和构造器注入”constructor-arg“。
如下几种方式将达到同样的效果:
使用
标签和“ref”属性:
1 2 3 4 5 6 7 8 9
|
<bean id="CustomerBean" class="com.myprj.common.Customer"> <property name="person" ref="PersonBean" /> </bean>
<bean id="PersonBean" class="com.myprj.common.Person"> <property name="name" value="myprj" /> <property name="address" value="address1" /> <property name="age" value="28" /> </bean>
|
使用内部Bean方式:
1 2 3 4 5 6 7 8 9
|
<bean id="CustomerBean" class="com.myprj.common.Customer"> <property name="person"> <bean class="com.myprj.common.Person"> <property name="name" value="myprj" /> <property name="address" value="address1" /> <property name="age" value="28" /> </bean> </property> </bean>
|
内部 bean 也支持构造器注入:
1 2 3 4 5 6 7 8 9
|
<bean id="CustomerBean" class="com.myprj.common.Customer"> <constructor-arg> <bean class="com.myprj.common.Person"> <property name="name" value="myprj" /> <property name="address" value="address1" /> <property name="age" value="28" /> </bean> </constructor-arg> </bean>
|
五、Spring Bean作用域实例
在Spring中,Bean作用域用来确定那种类型的Bena实例应该被Spring的容器返回给调用者。Spring Bean支持的5种作用域:
- 单例——每个Spring IoC容器返回一个Bean实例;
- 原型——每次请求时返回一个新的Bean实例;
- 请求——返回每个HTTP请求的一个Bean实例;
- 会话——返回每个HTTP会话的一个Bean实例;
- 全局会话——返回全局HTTP会话的一个Bean实例。
在大多数情况下,可能只处理了 Spring 的核心作用域 - 单例和原型,默认作用域是单例。
这里有一个例子来说明,bean的作用域单例和原型之间的不同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
package com.myprj.customer.services;
public class CustomerService { String message; public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; } }
|
1. 单例实例
如果Bean配置文件中没有指定Bean的范围,默认为单例;
1 2 3 4 5 6 7 8 9
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="customerService" class="com.myprj.customer.services.CustomerService" /> </beans>
|
执行代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
package com.myprj.common;
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.myprj.customer.services.CustomerService;
public class App { public static void main( String[] args ) { ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});
CustomerService custA = (CustomerService)context.getBean("customerService"); custA.setMessage("Message by custA"); System.out.println("Message : " + custA.getMessage()); CustomerService custB = (CustomerService)context.getBean("customerService"); System.out.println("Message : " + custB.getMessage()); } }
|
输出结果:
1 2
|
Message : Message by custA Message : Message by custA
|
在单例中,每个Spring IoC容器只有一个实例,无论多少次调用getBean()方法获取它,总是返回同一个实例。
2. 原型实例
如果每次获取Bean对象时需要一个新的Bean实例,需要在bean配置中添加“scope”属性,值为“prototype”(原型)。
1 2 3 4 5 6 7 8 9
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="customerService" class="com.myprj.customer.services.CustomerService" scope="prototype"/> </beans>
|
运行代码并执行:
1 2
|
Message : Message by custA Message : null
|
3. Bean作用域注解
在此之前在XML配置文件中启用自动组件扫描:
1
|
<context:component-scan base-package="com.myprj.customer" />
|
使用注解定义Bean的作用域:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
package com.myprj.customer.services;
import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service;
@Scope("prototype") public class CustomerService { String message; public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; } }
|
六、Spring集合(List、Set、Map、Properties)实例
以下例子将展示Spring如何注入值到集合中。
Spring Beans:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
package com.myprj.common;
import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set;
public class Customer { private List<Object> lists; private Set<Object> sets; private Map<Object, Object> maps; private Properties pros; }
|
1. List示例
1 2 3 4 5 6 7 8 9 10 11
|
&l 大专栏 Spring Bean基础t;property name="lists"> <list> <value>1</value> <ref bean="PersonBean" /> <bean class="com.myprj.common.Person"> <property name="name" value="myprjList" /> <property name="address" value="Hainan" /> <property name="age" value="28" /> </bean> </list> </property>
|
2. Set示例
1 2 3 4 5 6 7 8 9 10 11
|
<property name="sets"> <set> <value>1</value> <ref bean="PersonBean" /> <bean class="com.myprj.common.Person"> <property name="name" value="myprjSet" /> <property name="address" value="Hainan" /> <property name="age" value="28" /> </bean> </set> </property>
|
3. Map示例
1 2 3 4 5 6 7 8 9 10 11 12 13
|
<property name="maps"> <map> <entry key="Key 1" value="1" /> <entry key="Key 2" value-ref="PersonBean" /> <entry key="Key 3"> <bean class="com.myprj.common.Person"> <property name="name" value="myprjMap" /> <property name="address" value="Hainan" /> <property name="age" value="28" /> </bean> </entry> </map> </property>
|
4. Properties示例
七、Spring注入日期到Bean属性
当我们有个Bean属性需要注入时间日期时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
package com.myprj.common;
import java.util.Date;
public class Customer {
Date date;
public Date getDate() { return date; }
public void setDate(Date date) { this.date = date; }
@Override public String toString() { return "Customer [date=" + date + "]"; }
}
|
简单的如下配置将会出现错误:
1 2 3
|
<bean id="customer" class="com.myprj.common.Customer"> <property name="date" value="2015-12-31" /> </bean>
|
解决办法:在Spring中可以通过两种方式注入时间日期:
1. Factory Bean
声明一个dateFormat工厂Bean,该工厂实例为SimpleDateFormat类型,传入时间日期格式字符串构造对象;在“customer”Bean中引入dateFormat Bean,并调用parse()方法将字符串转换为Date对象:
1 2 3 4 5 6 7 8 9 10 11
|
<bean id="dateFormat" class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd" /> </bean>
<bean id="customer" class="com.myprj.common.Customer"> <property name="date"> <bean factory-bean="dateFormat" factory-method="parse"> <constructor-arg value="2018-12-31" /> </bean> </property> </bean>
|
2. CustomDateEditor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
<bean id="dateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg> <bean class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd" /> </bean> </constructor-arg> <constructor-arg value="true" />
</bean>
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="java.util.Date"> <ref local="dateEditor" /> </entry> </map> </property> </bean>
<bean id="customer" class="com.myprj.common.Customer"> <property name="date" value="2018-12-31" /> </bean>
|
有些时候Spring开发人员会把项目的部署信息(数据库连接信息、日志文件的路径)写在XML bean配置文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
<bean id="customerSimpleDAO" class="com.myprj.customer.dao.impl.SimpleJdbcCustomerDAO">
<property name="dataSource" ref="dataSource" /> </bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/myprjjava" /> <property name="username" value="root" /> <property name="password" value="password" /> </bean>
|
但是,在实际企业环境下,项目部署信息不会出现在bean配置文件中,而是配置在一个单独的文件,如properties文件;
为了解决这个问题,可以使用 PropertyPlaceholderConfigurer 类通过一个特殊的格式在外部部署细节到一个属性(properties )文件,并在bean的配置文件中配置 :${variable}。
创建一个属性文件(database.properties),包含数据库的详细信息,把它放到你的项目类路径:
1 2 3 4
|
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/myprj_db jdbc.username=root jdbc.password=123456
|
在bean配置文件中声明提供一个PropertyPlaceholderConfigurer映射到刚才创建的“database.properties”属性文件:
1 2 3 4 5 6 7
|
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"> <value>database.properties</value> </property> </bean>
|
于是可以如下配置:
1 2 3 4 5 6 7 8
|
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean>
|
九、Spring的继承配置
1 2 3 4 5 6 7 8
|
<bean id="BaseCustomerMalaysia" class="com.myprj.common.Customer"> <property name="country" value="Malaysia" /> </bean>
<bean id="CustomerBean" parent="BaseCustomerMalaysia"> <property name="action" value="buy" /> <property name="type" value="1" /> </bean>
|
十、Spring依赖检查
在Spring中,可以使用依赖检查功能,以确保所要求的属性可设置或者注入。
4个依赖检查支持的模式:
- none – 没有依赖检查,这是默认的模式。
- simple – 如果基本类型(int, long,double…)和集合类型(map, list..)的任何属性都没有设置,UnsatisfiedDependencyException将被抛出。
- objects – 如果对象类型的任何属性都没有设置,UnsatisfiedDependencyException将被抛出。
- all – 如果任何类型的任何属性都没有被设置,UnsatisfiedDependencyException将被抛出。
1 2 3 4 5 6 7 8 9 10 11 12
|
<bean id="xxxx" class="xxxxxr" dependency-check="simple"> //... </bean> <bean id="xxxx" class="xxxxxr" dependency-check="objects"> //... </bean> <bean id="xxxx" class="xxxxxr" dependency-check="all"> //... </bean>
|
Spring使用@Required注解依赖检查
在使用之前需要在Bean配置中包含<context:annotation-config />或
1 2
|
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
|
@Required使用在 setter方法或属性上,以确保该属性被注入值。
十一、Spring Bean InitializingBean和DisposableBean
在Spring中,InitializingBean和DisposableBean是两个标记接口,为Spring执行时bean的初始化和销毁某些行为时的有用方法。
- 对于Bean实现 InitializingBean,它将在所有的 bean 属性被设置之后运行 afterPropertiesSet()。
- 对于 Bean 实现了DisposableBean,它将在 Spring 容器释放该 bean 之后运行 destroy()。