Spring Bean基础

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“。

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

  1. 使用 标签和“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>
    
  2. 使用内部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>
    
  3. 内部 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的初始化和销毁某些行为时的有用方法。

  1. 对于Bean实现 InitializingBean,它将在所有的 bean 属性被设置之后运行 afterPropertiesSet()。
  2. 对于 Bean 实现了DisposableBean,它将在 Spring 容器释放该 bean 之后运行 destroy()。
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值