Spring Bean基础
文章目录
一、Spring Bean引用例子
1. Bean在不同的XML 文件
如果实在不同的XML配置文件中的Bean,可以用一个标签,“bean”属性引用它:
<bean id="OutputHelper" class="com.myprj.output.OutputHelper">
<property name="outputGenerator" >
<ref bean="CsvOutputGenerator"/>
</property>
</bean>
2. 在同一个XML文件中的Bean
如果引用在同一个XML文件中的bean,你可以用 ‘ref’ 标签,“local”属性引用它,使用时常省略。
<ref local="someBean"/>
二、如何注入值到Spring Bean属性
在Spring中,有三种方式将值注入到Bean的属性:
- 正常方式
- 快速方式
- “p”模式方式
如下一个简单的Java类,包含两个数属性:name和type,稍后使用Spring注入值到这个Bean的属性:
package com.myprj.common;
public class FileNameGenerator
{
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. 正常方式
在标签中的标签中赋值:
<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”属性赋值:
<bean id="FileNameGenerator" class="com.myprj.common.FileNameGenerator">
<property name="name" value="myprj" />
<property name="type" value="txt" />
</bean>
3. “p”模式方式
通过标签中p模式赋值:
//...
xmlns:p="http://www.springframework.org/schema/p"
//...
<bean id="FileNameGenerator" class="com.myprj.common.FileNameGenerator"
p:name="myprj" p:type="txt" />
三、Spring Bean加载多个配置文件
<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”属性:
<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方式:
<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 也支持构造器注入:
<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的作用域单例和原型之间的不同:
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的范围,默认为单例;
<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>
执行代码:
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());
//retrieve it again
CustomerService custB = (CustomerService)context.getBean("customerService");
System.out.println("Message : " + custB.getMessage());
}
}
输出结果:
Message : Message by custA
Message : Message by custA
在单例中,每个Spring IoC容器只有一个实例,无论多少次调用getBean()方法获取它,总是返回同一个实例。
2. 原型实例
如果每次获取Bean对象时需要一个新的Bean实例,需要在bean配置中添加“scope”属性,值为“prototype”(原型)。
<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>
运行代码并执行:
Message : Message by custA
Message : null
3. Bean作用域注解
在此之前在XML配置文件中启用自动组件扫描:
<context:component-scan base-package="com.myprj.customer" />
使用注解定义Bean的作用域:
package com.myprj.customer.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@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:
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示例
<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示例
<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示例
<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示例
<property name="pros">
<props>
<prop key="admin">admin@myprj.com</prop>
<prop key="support">support@myprj.com</prop>
</props>
</property>
七、Spring注入日期到Bean属性
当我们有个Bean属性需要注入时间日期时:
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 + "]";
}
}
简单的如下配置将会出现错误:
<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对象:
<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
<!--声明一个 CustomDateEditor 类将字符串转换成 java.util.Date-->
<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>
<!--并声明另一个“CustomEditorConfigurer”,使用Spring转换 bean 属性,其类型为java.util.Date-->
<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 PropertyPlaceholderConfigurer实例
有些时候Spring开发人员会把项目的部署信息(数据库连接信息、日志文件的路径)写在XML bean配置文件中:
<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示例
为了解决这个问题,可以使用 PropertyPlaceholderConfigurer 类通过一个特殊的格式在外部部署细节到一个属性(properties )文件,并在bean的配置文件中配置 :${variable}。
创建一个属性文件(database.properties),包含数据库的详细信息,把它放到你的项目类路径:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/myprj_db
jdbc.username=root
jdbc.password=123456
在bean配置文件中声明提供一个PropertyPlaceholderConfigurer映射到刚才创建的“database.properties”属性文件:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database.properties</value>
</property>
</bean>
于是可以如下配置:
<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的继承配置
<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将被抛出。
<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 />或
<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()。