Spring之Bean的配置使用

1.Bean的基本概念

IoC管理的应用程序对象叫做Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。在Spring中由BeanDefinition代表,配置元数据指定如何实例化Bean、如何组装Bean等。

2.Spring IoC管理Java Bean

Spring IoC容器如何知道哪些是它管理的对象呢?在Spring Ioc容器的代表就是org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能;而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。简单说, BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。

容器实现一览:

 XmlBeanFactoryBeanFactory实现,提供基本的IoC容器功能,可以从classpath或文件系统等获取资源;

(1)File file = new File("fileSystemConfig.xml");

         Resource resource = new FileSystemResource(file);

         BeanFactory beanFactory = new XmlBeanFactory(resource);

(2)Resource resource = new ClassPathResource("classpath.xml");                 

        BeanFactory beanFactory = new XmlBeanFactory(resource);

ClassPathXmlApplicationContextApplicationContext实现,从classpath获取配置文件;

         BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");

FileSystemXmlApplicationContextApplicationContext实现,从文件系统获取配置文件。

         BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");

ApplicationContext接口获取Bean方法简介:

 Object getBean(String name) 根据名称返回一个Bean,客户端需要自己进行类型转换;

 T getBean(String name, Class<T> requiredType) 根据名称和指定的类型返回一个Bean,客户端无需自己进行类型转换,如果类型转换失败,容器抛出异常;

 T getBean(Class<T> requiredType) 根据指定的类型返回一个Bean,客户端无需自己进行类型转换,如果没有或有多于一个Bean存在容器将抛出异常;

 Map<String, T> getBeansOfType(Class<T> type) 根据指定的类型返回一个键值为名字和值为Bean对象的 Map,如果没有Bean对象存在则返回空的Map。


Spring IoC容器目的就是管理Bean,这些Bean将根据配置文件中的Bean定义进行创建,而Bean定义在容器内部由BeanDefinition对象表示,该定义主要包含以下信息:

1.全限定类名(FQN):用于定义Bean的实现类;

2.Bean行为定义:这些定义了Bean在容器中的行为;包括作用域(单例、原型创建)、是否惰性初始化及生命周期等;

3.Bean创建方式定义:说明是通过构造器还是工厂方法创建Bean;

4.Bean之间关系定义:即对其他bean的引用,也就是依赖关系定义,这些引用bean也可以称之为同事bean 或依赖bean,也就是依赖注入;

Bean定义只有“全限定类名”在当使用构造器或静态工厂方法进行实例化bean时是必须的,其他都是可选的定义。难道Spring只能通过配置方式来创建Bean吗?回答当然不是,某些SingletonBeanRegistry接口实现类实现也允许将那些非BeanFactory创建的、已有的用户对象注册到容器中,这些对象必须是共享的,比如使用DefaultListableBeanFactory 的registerSingleton() 方法。不过建议采用元数据定义。

IoC容器工作方式:

1.准备配置文件:在配置文件中声明Bean定义也就是为Bean配置元数据。

2.由IoC容器进行解析元数据: IoC容器的Bean Reader读取并解析配置文件,根据定义生成BeanDefinition配置元数据对象,IoC容器根据BeanDefinition进行实例化、配置及组装Bean。

3.实例化IoC容器:由客户端实例化容器,获取需要的Bean。

3.Bean的命名

下面来看看实例:
注:这里用的spring-framework-4.3.7.RELEASE,jar包如下:
spring-beans-4.3.7.RELEASE.jar
spring-core-4.3.7.RELEASE.jar
spring-context-4.3.7.RELEASE.jar
spring-expression-4.3.7.RELEASE.jar
commons-logging-1.2.jar
log4j-1.2.17.jar
junit-4.10.jar(用于单元测试)

BeanApi

package com.chensan.spring.chapter1;

public interface BeanApi {
	public void sayHello();
}
BeanImpl1
package com.chensan.spring.chapter1;

public class BeanImpl1 implements BeanApi {
	//@Override
	public void sayHello() {
		System.out.println("Welcome to Spring World!");
	}
}

1.全限定名方式

不指定id,只配置必须的全限定类名,由IoC容器为其生成一个标识,客户端必须通过接口“T getBean(Class<T> requiredType)”获取Bean;

bean1_1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:context="http://www.springframework.org/schema/context" 
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.3.xsd">
  
  <!-- 不指定id,只配置必须的全限定类名,由IoC容器为其生成一个标识,
  	客户端必须通过接口“T getBean(Class<T> requiredType)”获取Bean;
   -->
  <bean class="com.chensan.spring.chapter1.BeanImpl1"/>
</beans>
TestBeanApi1_1
package com.chensan.spring.chapter1.test;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_1 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_1.xml");
		BeanApi beanApi = beanFactory.getBean(BeanApi.class);
		beanApi.sayHello();
	}
}

2.只指定id

id必须在IoC容器中唯一
bean1_2.xml(省略篇幅,xml文件格式不再给出)

<!-- 指定id,必须在IoC容器中唯一 -->
  <bean id="bean1_2" class="com.chensan.spring.chapter1.BeanImpl1"/>
TestBeanApi1_2
package com.chensan.spring.chapter1.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_2 {
	@Test
	public void testHelloSpringWorld(){
		//1. 读取配置文件实例化一个IoC容器
		ApplicationContext context = new ClassPathXmlApplicationContext("bean1_2.xml");
		//2. 从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
		BeanApi beanApi = context.getBean("bean1_2", BeanApi.class);
		//3. 执行业务逻辑
		beanApi.sayHello();
	}
}

3.指定一个name,不指定id

name是标识符,必须在Ioc容器中唯一;

bean1_3

<!-- 指定name,这样name就是“标识符”,必须在Ioc容器中唯一; -->
  <bean name="bean1_3" class="com.chensan.spring.chapter1.BeanImpl1"/>
TestBeanApi1_3
package com.chensan.spring.chapter1.test;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_3 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_3.xml");
		BeanApi beanApi = beanFactory.getBean("bean1_3", BeanApi.class);
		beanApi.sayHello();
	}
}

4.同时指定id和name,id和name不同名

id是标识符,而name是别名,必须在Ioc容器中唯一;

bean1_4

<!-- 
  	指定id和name,id就是标识符,而name就是别名,必须在Ioc容器中唯一;
   -->
  <bean id="bean1_4_1" name="bean1_4_2" class="com.chensan.spring.chapter1.BeanImpl1"/>
TestBeanApi1_4
package com.chensan.spring.chapter1.test;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_4 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_4.xml");
		BeanApi beanApi1 = beanFactory.getBean("bean1_4_1", BeanApi.class);
		beanApi1.sayHello();
		BeanApi beanApi2 = beanFactory.getBean("bean1_4_2", BeanApi.class);
		beanApi2.sayHello();
		String[] bean4Alias = beanFactory.getAliases("bean1_4_2");
		Assert.assertEquals(1, bean4Alias.length);
	}
}

5.同时指定id和name,id和name同名

bean1_5

<!-- 
  	指定id和name,id就是标识符,而name就是别名,必须在Ioc容器中唯一;
   	 如果id和name一样,IoC容器能检测到,并消除冲突;
   -->
  <bean id="bean1_5" name="bean1_5" class="com.chensan.spring.chapter1.BeanImpl1"/>
TestBeanApi1_5
package com.chensan.spring.chapter1.test;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_5 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_5.xml");
		BeanApi beanApi = beanFactory.getBean("bean1_5", BeanApi.class);
		beanApi.sayHello();
		String[] bean5Alias = beanFactory.getAliases("bean1_5");
		Assert.assertEquals(0, bean5Alias.length);//bean1_5别名获取数组长度为0,bean1_4别名获取数组长度为1;说明:别名不能和id一样,如果一样则由IoC容器负责消除冲突;
	}
}

6.指定多个name,不指定id

指定多个name,第一个name后用“;”,后面的name用“,”隔开第一个被用作标识符,其他的为别名;

bean1_6.xml

<!-- 指定多个name,第一个name后用“;”,后面的name用“,”隔开第一个被用作标识符,其他的为别名; -->
  <bean name="bean1_6;alias1_6_1,alias1_6_2,alias1_6_3,alias1_6_4" 
  	class="com.chensan.spring.chapter1.BeanImpl1"/>
TestBeanApi1_6
package com.chensan.spring.chapter1.test;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_6 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_6.xml");
		//根据id获取bean
		BeanApi beanApi = beanFactory.getBean("bean1_6", BeanApi.class);
		beanApi.sayHello();
		//根据别名获取bean
		BeanApi alias161 = beanFactory.getBean("alias1_6_1", BeanApi.class);//alias51, alias52, alias53都是别名
		alias161.sayHello();
		String[] aliases = beanFactory.getAliases("bean1_6");
		Assert.assertEquals(4, aliases.length);
		for(String alias : aliases){
			System.out.println(alias);
		}		
	}
}

7.指定多个name,同时指定id

指定多个name,第一个name后用“;”,后面的name用“,”隔开第一个被用作标识符,其他的为别名;当指定id时,name指定的标识符全部为别名;
bean1_7.xml

<!-- 指定多个name,第一个name后用“;”,后面的name用“,”隔开第一个被用作标识符,其他的为别名;
   	 当指定id时,name指定的标识符全部为别名;
   -->
  <bean id="bean1_7" name="bean1_7_1;alias1_7_1,alias1_7_2,alias1_7_3,alias1_7_4" 
  	class="com.chensan.spring.chapter1.BeanImpl1"/>
TestBeanApi1_7
package com.chensan.spring.chapter1.test;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_7 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_7.xml");
		//根据id获取bean
		BeanApi beanApi = beanFactory.getBean("bean1_7", BeanApi.class);
		beanApi.sayHello();
		//根据别名获取bean
		BeanApi alias171 = beanFactory.getBean("bean1_7_1", BeanApi.class);//alias51, alias52, alias53都是别名
		alias171.sayHello();
		String[] aliases = beanFactory.getAliases("bean1_7");
		Assert.assertEquals(5, aliases.length);
		for(String alias : aliases){
			System.out.println(alias);
		}	
	}
}

8.使用<alias>标签指定别名

别名也必须在IoC容器中唯一

bean1_8.xml

<!-- 使用<alias>标签指定别名,别名也必须在IoC容器中唯一   -->
  <bean name="bean1_8_1" class="com.chensan.spring.chapter1.BeanImpl1"/>
  <alias alias="alias1_8_1" name="bean1_8_1"/>
  <alias alias="alias1_8_2" name="bean1_8_1"/>
TestBeanApi1_8
package com.chensan.spring.chapter1.test;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBeanApi1_8 {
	@Test
	public void testHelloSpringWorld(){
		BeanFactory beanFactory  = new ClassPathXmlApplicationContext("bean1_8.xml");
		
		//根据别名获取bean
		BeanApi beanApi2 = beanFactory.getBean("bean1_8_1", BeanApi.class);
		beanApi2.sayHello();
		
		String[] aliases = beanFactory.getAliases("bean1_8_1");
		Assert.assertEquals(2, aliases.length);
		for(String alias : aliases){
			System.out.println(alias);
		}	
	}
}

4.实例化Bean

传统应用程序可以通过new和反射方式进行实例化Bean。而Spring IoC容器则需要根据Bean定义里的配置元数据使用反射机制来创建Bean。在Spring IoC容器中根据Bean定义创建Bean主要有以下几种方式:

1.构造器实例化Bean

构造器实例化Bean是最简单的方式,Spring IoC容器既能使用默认空构造器也能使用有参数构造器两种方式创建Bean,如以下方式指定要创建的Bean类型:
使用空构造器进行定义,使用此种方式,class属性指定的类必须有空构造器。

BeanImpl2

package com.chensan.spring.chapter2;

import com.chensan.spring.chapter1.BeanApi;

public class BeanImpl2 implements BeanApi {
	private String message;
	public BeanImpl2(){
		this.message = "Hello Spring!";
	}

	public BeanImpl2(String message){
		this.message = message;
	}
	
	@Override
	public void sayHello() {
		System.out.println(message);
	}

	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
}

bean2_1.xml

<!-- 使用默认构造参数 -->
<bean name="bean2_1_1" class="com.chensan.spring.chapter2.BeanImpl2"/>
<!-- 使用有参构造参数 -->
<bean name="bean2_1_2" class="com.chensan.spring.chapter2.BeanImpl2">
  <!-- 指定构造器参数 -->
  <constructor-arg index="0" value="Spring Constructor BeanFactory"/>
</bean>
TestBean2_1
package com.chensan.spring.chapter2.test;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBean2_1 {
	//构造器实例化Bean
	@Test
	public void instantiatingBeanByConstructor(){
		BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean2_1.xml");
		BeanApi beanApi1 = beanFactory.getBean("bean2_1_1", BeanApi.class);
		beanApi1.sayHello();
		BeanApi beanApi2 = beanFactory.getBean("bean2_1_2", BeanApi.class);
		beanApi2.sayHello();
	}
}
注意:看起来bean2_1_1与之前Bean的命名是一样的,区别在于BeanImpl2中的sayHello方法中的参数是从构造器中传入的,所以需要指定对应参数个数的构造器。

2.静态工厂方式实例化Bean

使用静态工厂方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取Bean

BeanApiStaticFactory

package com.chensan.spring.chapter2;

import com.chensan.spring.chapter1.BeanApi;

public class BeanApiStaticFactory {
	//静态工厂方法
	public static BeanApi newInstance(String message){
		return new BeanImpl2(message);
	}
}
bean2_2.xml
<!-- 使用静态工厂方法 -->
<bean name="bean2_2" class="com.chensan.spring.chapter2.BeanApiStaticFactory" 
    factory-method="newInstance">
  <!-- 指定构造器参数 -->
  <constructor-arg index="0" value="Spring Static BeanFactory"/>
</bean>
TestBean2_2
package com.chensan.spring.chapter2.test;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBean2_2 {
	//使用静态工厂方法
	@Test
	public void instantiatingBeanByStaticFactory(){
		BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean2_2.xml");
		BeanApi beanApi1 = beanFactory.getBean("bean2_2", BeanApi.class);
		beanApi1.sayHello();
	}
}

3.实例工厂方法实例化Bean

使用实例化工厂方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样

BeanApiInstanceFactory

package com.chensan.spring.chapter2;

import com.chensan.spring.chapter1.BeanApi;

public class BeanApiInstanceFactory {
	//实例化工厂方法
	public BeanApi newInstance(String message){
		return new BeanImpl2(message);
	}
}
bean2_3.xml
<!-- 定义实例化工厂Bean -->
<bean id="bean2_3_1" class="com.chensan.spring.chapter2.BeanApiInstanceFactory"/>
<!-- 使用实例化工厂Bean实例化Bean -->
<bean id="bean2_3_2" factory-bean="bean2_3_1" factory-method="newInstance">
  <!-- 指定构造器参数 -->
  <constructor-arg index="0" value="Spring Instance BeanFactory"/>
</bean>
TestBean2_3
package com.chensan.spring.chapter2.test;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chensan.spring.chapter1.BeanApi;

public class TestBean2_3 {
	//使用实例化工厂方法
	@Test
	public void instantiatingBeanByInstanceFactory(){
		BeanFactory beanFactory = new ClassPathXmlApplicationContext("bean2_3.xml");
		BeanApi beanApi2 = beanFactory.getBean("bean2_3_2", BeanApi.class);
		beanApi2.sayHello();
	}
}

这三种方式只是配置不一样,从获取方式看完全一样,没有任何不同。这也是Spring IoC的魅力,Spring IoC帮你创建Bean,我们只管使用就可以。

参考:http://jinnianshilongnian.iteye.com/blog/1413857

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值