spring中bean的配置以及更多详细配置

配置bean

 

配置形式:基于xml文件的方式;基于注解的方式

Bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean

IOC容器:BeanFactory&ApplicationContext概述

依赖注入的方式:属性注入;构造器注入

 

一、基于xml文件的形式

<!--
    配置bean
    class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须要有无参数的构造器
    id:通过id获取bean,标识容器中的bean,并且唯一
-->
<bean id="hello" class="beans.HelloWorld">
	<property name="name" value="Spring">
	</property>
</bean>

在spring IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器里获取Bean实例并使用

spring提供了两种类型的IOC容器实现

  • BeanFactory:IOC容器的基本实现(BeanFactory是spring框架的基础设施,面向spring本身)
  • ApplicationContext:提供了更多的高级特性,是BeanFactory的子接口(ApplicationContext面向使用spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory)
  • 无论使用何种方式,配置文件时相同的

ApplicationContext的主要实现类:

  • ClassPathXmlApplicationContext:从类路径下加载配置文件
  • FileSystemXmlApplicationContext:从文件系统中加载配置文件

可以通过ApplicationContext类来查看结构

ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法:refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力

ApplicationContext在初始化上下文时就实例化所有的bean

WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作

// 创建spring的容器对象
// ApplicationContext代表IOC容器
// ClassPathXmlApplicationContext:是ApplicationContext接口的实现类,该实现类从类路径下来加载配置
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

// 从IOC容器中获取bean实例
HelloWorld he = (HelloWorld)ctx.getBean("hello");

//调用方法		
he.hello();

拓展:从IOC容器获取bean实例不仅可以通过id获取,也可以通过类类型来获取

HelloWorld he = ctx.getBean(HelloWorld.class);

缺点:当IOC容器中有多个相同的该类型的bean时,不能使用该方式获取bean

二、依赖注入的方式

spring支持3中依赖注入的方式

  • 属性注入(最常用的注入方式)
  • 构造器注入
  • 工厂方法注入(很少使用,不推荐)

1.属性注入

通过setter方法注入Bean的属性值或依赖的对象,使用<property>元素,使用name属性指定bean的属性名称,value属性或<value>子节点指定属性值

2.构造方法注入

通过构造方法注入bean的属性值或依赖的对象,它保证bean实例在实例化后就可以使用,构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性

现在有一个Car类

package beans;

public class Car
{
	private String brand;
	private String corp;
	private int price;
	private int maxSpeed;
	
	// 只初始化了三个属性
	public Car(String brand, String corp, int price)
	{
		super();
		this.brand = brand;
		this.corp = corp;
		this.price = price;
	}

	@Override
	public String toString()
	{
		return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price + 
		", maxSpeed=" + maxSpeed + "]";
	}
}

然后在ApplicationContext.xml中配置bean

<!-- 通过构造方法来配置bean的属性 -->
<!-- 这里的index为参数顺序的索引,不写index默认按标签顺序注入-->

<bean id="car" class="beans.Car">
	<constructor-arg value="Audi" index="0"></constructor-arg>
	<constructor-arg value="Shanghai" index="1"></constructor-arg>
	<constructor-arg value="300000" index="2"></constructor-arg>
</bean>

<!-- 通过构造方法来配置bean的属性 -->
<!-- 也可以通过类中的构造方法的参数类型来注入 -->

<bean id="car" class="beans.Car">
    <constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
    <constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>

    <!-- 这里的类型为int,但是写法和String类型写法一样,注入时会自动转为int类型 -->
    <constructor-arg value="300000" type="int"></constructor-arg>

    <!--也可以这样写-->
    <constructor-arg type="int">
        <value>1000</value>
    </constructor-arg>
</bean>

然后获取bean并调用得到结果

Car car = ctx.getBean(Car.class);
System.out.println(car);

通过构造方法注入时可以用字符串表示的值注入,也可以通过<value>元素标签或value属性进行注入。基本数据类型及其封装类、String等类型都可以采用字面值的注入的方式,若字面值中包含特殊字符可以使用<![CDATA[]]>把字面值包裹起来。

<constructor-arg value="<Shanghai>" type="java.lang.String"></constructor-arg>

例如:"<>"是必须加上<![CDATA[]]>的,应写作

<constructor-arg type="java.lang.String">
    <value><![CDATA[<shanghai^>]]></value>
</constructor-arg>

引用其他Bean

  • 组成应用程序的Bean经常需要相互协作以完成应用程序的功能,要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean 的引用
  • 在Bean的配置文件中,可以通过<ref>元素或ref属性为Bean的属性或构造器参数指定对Bean 的引用
  • 也可以在属性或构造器包含Bean的声明,这样的Bean称为内部Bean

现在有一个Person类

package beans;

public class Person
{
	private String name;

	private int age;
	
	private Car car;

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public Car getCar()
	{
		return car;
	}

	public void setCar(Car car)
	{
		this.car = car;
	}

	@Override
	public String toString()
	{
		return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
	}
		
}

在配置中加入以下配置就可以建立Car类和Person类的引用关系

<bean id="person" class="beans.Person">
    <property name="name" value="tom"></property>
    <property name="age" value="24"></property>
    <property name="car" ref="car"></property>

    <!--两种写法等价-->
    <property name="car">
        <ref bean="car"/>
    </property>
</bean>

获取bean后运行结果为

也可以配置内部Bean

<bean id="person" class="beans.Person">
    <property name="name" value="tom"></property>
	<property name="age" value="24"></property>
	<!-- 内部bean ,不能被外部引用,只能在内部使用-->
	<property name="car">
		<bean id="car" class="beans.Car">
			<constructor-arg value="Ford"></constructor-arg>
			<constructor-arg value="Changan"></constructor-arg>
			<constructor-arg value="20000" type="double"></constructor-arg>
		</bean>
	</property>
</bean>

运行结果为

null值和级联属性

  • 可以使用专用的<null/>元素标签为Bean的字符串或其它对象类型的属性注入null值

例如

<bean id="person" class="beans.Person">
	<constructor-arg value="Jerry"></constructor-arg>
	<constructor-arg value="25"></constructor-arg>
	<constructor-arg ><null/></constructor-arg>
</bean>

获取bean运行后结果

  • 和struts、Hibernate等框架一样,spring支持级联属性的配置

例如

<bean id="person" class="beans.Person">
	<constructor-arg value="Jerry"></constructor-arg>
	<constructor-arg value="25"></constructor-arg>
	<constructor-arg ref="car"></constructor-arg>
        <!--为级联属性赋值-->
	<property name="car.maxSpeed" value="300"></property>
</bean>

运行也是可以得到结果的,这里不做展示

 

集合属性

  • 在spring中可以通过一组内置的xml标签(例如:<list>,<set>或<map>来配置集合属性)
  • 配置java.util.List类型的属性,需要指定<list>标签,在标签里包含一些元素,这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用,通过<bean>指定内置Bean的定义,通过<null/>指定空元素,甚至可以内嵌其他集合
  • 数组的定义和List一样,都使用<list>
  • 配置java.util.Set需要使用<set>标签,定义元素的方法与List一样

当car是一个集合时,在Person类里把car改为List类型

配置如下

	<bean id="car1" class="beans.Car">
		<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
		<constructor-arg value="wuhan" type="java.lang.String"></constructor-arg>
		<constructor-arg value="100000" type="int"></constructor-arg>
	</bean>
	
	<bean id="car2" class="beans.Car">
		<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
		<constructor-arg value="Wuhan" type="java.lang.String"></constructor-arg>
		<constructor-arg value="200000" type="int"></constructor-arg>
	</bean>
	
	<bean id="car3" class="beans.Car">
		<constructor-arg value="Luland" type="java.lang.String"></constructor-arg>
		<constructor-arg value="Beijing" type="java.lang.String"></constructor-arg>
		<constructor-arg value="300000" type="int"></constructor-arg>
	</bean>
	
	<bean id="person1" class="beans.Person">
		<property name="name" value="Mike"></property>
		<property name="age" value="27"></property>
		<property name="car">
			<list>
				<ref bean="car1"/>
				<ref bean="car2"/>
				<ref bean="car3"/>
			</list>
		</property>
	</bean>

获取Bean运行后得到结果

 

 

  • Java.util.Map通过<map>标签定义,<map>标签里可以使用多个<entry>作为子标签,每个条目包含一个键和一个值

同样的,car类型改为Map类型,配置如下

	<!-- 配置Map属性值 -->
	<bean id="newPerson" class="beans.NewPerson">
		<property name="name" value="Rose"></property>
		<property name="age" value="28"></property>
		<property name="car">
			<map>
				<entry key="AA" value-ref="car1"></entry>
				<entry key="BB" value-ref="car2"></entry>
			</map>
		</property>
	</bean>

获取bean后运行得到结果

  • 必须在<key>标签里定义键
  • 因为键和值的类型没有限制,所以可以自由地为它们指定<value>,<ref>,<bean>或<null/>元素
  • 可以将Map的键和值作为<entry>的属性定义:简单常量使用key和value来定义,Bean引用通过key-ref和value-ref属性定义
  • 使用<props>定义java.util.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性

添加一个DataSource类

package beans;

import java.util.Properties;

public class DataSource
{
	private Properties properties;

	public Properties getProperties()
	{
		return properties;
	}

	public void setProperties(Properties properties)
	{
		this.properties = properties;
	}

	@Override
	public String toString()
	{
		return "DataSource [properties=" + properties + "]";
	}
	
	
}

Bean配置如下

    <!-- 配置properties属性值 -->
	<bean id="dataSource" class="beans.DataSource">
		<property name="properties">
			<props>
				<prop key="user">root</prop>
				<prop key="password">123456</prop>
				<prop key="jdbcUrl">jdbc:mysql://test</prop>
				<prop key="driverClass">com.mysql.jdbc.Driver</prop>
			</props>
		</property>
	</bean>

运行得到结果

 

使用utility scheme定义集合

  • 使用基本的集合标签定义集合时,不能将集合作为独立的Bean定义,导致其他Bean无法引用该集合,所以无法在不同的Bean,所以无法在不同的Bean之间共享集合
  • 可以使用util schema里的集合标签定义独立的集合Bean,需要注意的是,必须在<beans>根元素里添加util schema定义

配置如下

	<!-- 配置单例的集合Bean,以供多个bean进行引用 ,需要导入util命名空间-->
	<util:list id="car">
		<ref bean="car1"/>
		<ref bean="car2"/>
	</util:list>
	
	<bean id="person4" class="beans.Person">
		<property name="name" value="Jack"></property>
		<property name="age" value="29"></property>
		<property name="car" ref="car"></property>
	</bean>

获取bean,运行后得到结果

 

使用p命名空间

  • 为了简化XML文件的配置,越来越多的XML文件采用属性而非子元素配置信息。
  • spring 从2.5版本开始引入了一个新的p命名空间,可以通过<bean>元素属性的方式配置Bean的属性
  • 使用p命名空间后,基于XML的配置方式将进一步简化

配置如下

	<!-- 通过p命名空间为bean的属性赋值,需要先导入p命名空间,相对于传统的方式更加简洁 -->
	<bean id="person5" class="beans.Person" 
		p:age="30" p:name="Queen" p:car-ref="car">
	</bean>

获取bean运行得到结果

3.通过调用工厂方法创建Bean

a.静态工厂方法

  • 实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里,当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
  • 要声明通过工厂方法创建的Bean
  • 在bean的factory-bean属性里指定拥有该工厂方法的Bean
  • 在factory-method属性里指定该工厂方法的名称
  • 使用constructor-arg元素为工厂方法传递参数

现在有一个类StaticCarFactory

package factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 静态工厂方法:直接调用某一个类的静态方法就可以返回Bean的实例
 * @author dacryon
 *
 */
public class StaticCarFactory
{
	private static Map<String,Car> cars = new HashMap<String,Car>();
	
	static
	{
		cars.put("audi", new Car("audi",300000));
		cars.put("ford", new Car("ford",400000));
	}
	//静态工厂方法
	public static Car getCar(String name)
	{
		return cars.get(name);
	}
}

bean配置如下

<!-- 通过静态方法工厂来配置Bean,注意不是配置静态工厂方法实例,而是配置Bean实例 -->
<!--
	class属性:指向静态工厂方法的全类名
	factory-method:指向静态工厂方法的名字 
	constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数
-->
<bean id="car1" class="factory.StaticCarFactory" factory-method="getCar">
    <constructor-arg value="audi"></constructor-arg>
</bean>

运行后得到结果

b.实例工厂方法

  • 实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里,当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
  • 要声明通过实例工厂方法创建的Bean
  • 在bean的factory-bean属性里指定拥有该工厂方法的Bean
  • 在factory-method属性里指定该工厂方法的名称
  • 使用constructor元素为工厂方法传递参数

现在有一个类 InstanceCarFactory

package factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 实例工厂方法:实例工厂的方法,即现需要创建工厂本身,在调用工厂的实例方法来返回Bean的实例
 * @author dacryon
 *
 */
public class InstanceCarFactory
{
	private Map<String,Car> cars = null;
	
	public InstanceCarFactory()
	{
		cars = new HashMap<String,Car>();
		cars.put("audi", new Car("audi",300000));
		cars.put("ford", new Car("ford",400000));
	}
	
	public Car getCar(String brand)
	{
		return cars.get(brand);
	}
}

 配置如下

<!-- 通过实例工厂方法来配置bean -->
<!--
	class属性:指向实例工厂方法的全类名
	factory-method:指向实例工厂方法的名字 
	constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数
-->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
	<constructor-arg value="ford"></constructor-arg>
</bean>

获取bean运行后得到结果

 

4.通过FactoryBean配置Bean

添加一个类CarFactoryBean

package factoryBean;

import org.springframework.beans.factory.FactoryBean;

/**
 * 自定义的FactoryBean需要实现FactoryBean接口
 * @author dacryon
 *
 */
public class CarFactoryBean implements FactoryBean<Car>
{

	private String brand;
	
	public void setBrand(String brand)
	{
		this.brand = brand;
	}
	/**
	 *  返回Bean的对象
	 */
	@Override
	public Car getObject() throws Exception
	{
		// TODO Auto-generated method stub
		return new Car("brand",500000);
	}

	/**
	 *  返回Bean的类型
	 */
	@Override
	public Class<?> getObjectType()
	{
		// TODO Auto-generated method stub
		return Car.class;
	}

	@Override
	public boolean isSingleton()
	{
		// TODO Auto-generated method stub
		return true;
	}

}

 配置如下

<!--
    通过FactoryBean来配置Bean的实例
    class:指向FactoryBean的全类名
    property:配置FactoryBean的属性,但实际返回的实例确实FactoryBean的getObject()方法返回的实例
-->
<bean id="car" class="factoryBean.CarFactoryBean">
	<property name="brand" value="BMW"></property>
</bean>

获取bean实例运行得到结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值