Spring Bean基础

一、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的属性:

  • 正常方式
  • 快速方式
  • “p”模式方式

如下一个简单的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“。

如下几种方式将达到同样的效果:

  1. 使用 标签和“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>
  2. 使用内部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>
  3. 内部 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示例

1
2
3
4
5
6
<property name="pros">
<props>
<prop key="admin">[email protected]</prop>
<prop key="support">[email protected]</prop>
</props>
</property>

七、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
<!--声明一个 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配置文件中:

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示例

为了解决这个问题,可以使用 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的初始化和销毁某些行为时的有用方法。

  1. 对于Bean实现 InitializingBean,它将在所有的 bean 属性被设置之后运行 afterPropertiesSet()。
  2. 对于 Bean 实现了DisposableBean,它将在 Spring 容器释放该 bean 之后运行 destroy()。

猜你喜欢

转载自www.cnblogs.com/liuzhongrong/p/12390389.html
今日推荐