文档章节

Spring的学习(五):Spring容器中的Bean

yuhuan121
 yuhuan121
发布于 2017/08/25 00:38
字数 2477
阅读 3
收藏 0

1、Bean的定义和别名

对于开发者而言,使用Spring主要是做两件事情:开发Bean和配置Bean; <beans../>元素是Spring配置文件的根元素,可以指定以下属性:

  • lazy-init:指定该<beans../>元素下配置的所有Bean默认的_延迟初始化行为_;
  • merge:指定该<beans../>元素下配置的所有Bean默认的_merge行为_;
  • autowire:指定该<beans../>元素下配置的所有Bean默认的_自动装配的行为_;
  • autowire-candidates:指定该<beans../>元素下配置的所有Bean默认_是否作为自动装配的候选Bean_;
  • init-method:指定该<beans../>元素下配置的所有Bean默认的_初始化方法_;
  • destroy-method:指定该<beans../>元素下配置的所有Bean默认的_回收方法_;

<bean../>元素是<beans../>元素的子元素,可以包含很多个子元素。每个子元素定义一个Bean,每个Bean对应Spring容器里的一个java实例。

<beans../>元素可以给<bean../>元素指定属性,当两者属性值不一样时,后者的属性会覆盖前者指定的属性。

<bean../>元素包括两个id、class属性:id属性遵循XML文档的id属性规则,因此有一些特殊要求,比如不能以“/"等特殊符号作为属性值。此时name属性就出场了,可以用来指定Bean的别名,通过访问别名也可以访问Bean实例。

指定别名有两种方式:

  1. 定义<bean../>元素通过name指定别名:同上;但是当Bean实例指定多个别名时,可以用逗号、冒号、空格来分隔多个别名;
  2. 当程序无法在定义Bean时指定所有的别名,需要在其他地方指定时,用<alias../>元素,也包含两个属性:
  • name:指定一个已有的Bean实例的标识名
  • alias:指定一个别名
//为Bean指定了三个别名
<bean id = "person"  class = "..."  name = "#abc,@123,abc*"/>
//下面两行为已有的personBean指定别名
<alias name = "person" alias = "jack"/>

2、Bean的作用域

当通过Spring容器创建Bean实例是我,不仅完成其实例化,还能为其指定特定的作用域。

Spring支持下面5中作用域:

  • singleton:单例模式,在整个SpringIoC容器中,singleton作用域的Bean将只生成一个实例;
  • prototype:原型模式。每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。
  • request:对于每次HTTP请求,使用request定义的Bean都将只产生一个实例,即每次HTTP请求都会产生同一个Bean实例。当然只有在WEB应用中使用Spring时,该作用域才真正有效。
  • session:对于每次HTTP会话,使用session定义的Bean都将只产生一个实例,即每次HTTP Session都将产生同一个的Bean实例。当然只有在WEB应用中使用Spring时,该作用域才真正有效。
  • global session:每个全局的HTTP Session对应一个Bean实例。仅在portlet Context的时候才有效。当然只有在WEB应用中使用Spring时,该作用域才真正有效。

常用的是singleton和prototype作用域。_spring配置文件用scope属性指定Bean的作用域。_如果不指定Bean的作用域,spring默认是singleton作用域。由于singleton作用域的实例一旦被创建成功,就可以重复使用。但是prototype每次都产生一个新的实例。Java在创建Java实例时,会进行内存申请;销毁实例时,会完成垃圾回收,这都会导致系统开销的增加。prototype作用域的Bean创建,销毁的代价比较大,所有应避免将Bean设置prototype作用域。

3、创建Bean的方式

Spring支持使用3种方式:

3.1、调用构造器

  • 不采用构造注入,spring底层会调用Bean类的无参构造器来创建实例;
  • 采用构造注入,spring底层会调用Bean类的带有对应参数的构造器来创建实例;

3.2、 调用静态工厂方法

<bean../>元素包括以下两个属性:

  • class:不再是指定Bean类的实现类,而是静态工厂类名,Spring由此知道哪个工厂类来创建Bean实例;
  • factory-method:指定静态工厂方法来生产Bean实例

当静态工厂方法需要参数时候,用<constructor-arg../>传入

代码实现

3.2.1、定义一个Being接口

静态工厂方法生产的产品都是这个接口的实例

package org.crazyit.app.service;
public interface Being{
	public void testBeing();
}

3.2.2、定义该接口的两个实现类

静态工厂方法将会产生这两个实现类的实例

package org.crazyit.app.service.impl;

import org.crazyit.app.service.Being;

public class Dog implements Being{
	private String msg;
	public void setMsg(String msg){
		this.msg = msg;
	}
	//实现该接口的方法
	public void testBeing() {
		System.out.println(msg + ",狗爱啃骨头!");		
	}
}
package org.crazyit.app.service.impl;

import org.crazyit.app.service.Being;

public class Cat implements Being{
	private String msg;
	public void setMsg(String msg){
		this.msg = msg;
	}
	//实现该接口的方法
	public void testBeing() {
		System.out.println(msg + ",猫爱吃鱼!");		
	}
}

3.2.3、创建静态工厂类

下面的getBeing()方法用于返回一个Being实例

package org.crazyit.app.factory;

import org.crazyit.app.service.Being;
import org.crazyit.app.service.impl.Cat;
import org.crazyit.app.service.impl.Dog;

public class BeingFactory{
	//返回Being实例的静态工厂方法,arg参数决定返回哪个实例
	public static Being getBeing(String arg){
		// 调用此静态方法的参数为dog,则返回Dog实例
		if(arg.equalsIgnoreCase("dog")){
			return new Dog();
		}else{
			return new Cat();
		}
	}
}

3.2.4、配置

下面是按照静态工厂方法的方式来配置Bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<!-- 下面配置驱动Spring调用BeingFactory的静态getBeing()方法来创建Bean
	该bean元素包含的constructor-arg元素用于为静态工厂方法指定参数,
	因此这段配置会驱动Spring以反射方式来执行如下代码:
	dog = org.crazyit.app.factory.BeingFactory.getBeing("dog"); -->
	<bean id="dog" class="org.crazyit.app.factory.BeingFactory"
		factory-method="getBeing">
		<!-- 配置静态工厂方法的参数 -->
		<constructor-arg value="dog"/>
		<!-- 驱动Spring以"我是狗"为参数来执行dog的setMsg()方法 -->
		<property name="msg" value="我是狗"/>
	</bean>
	<!--  下面配置会驱动Spring以反射方式来执行如下代码:
	dog = org.crazyit.app.factory.BeingFactory.getBeing("cat"); -->
	<bean id="cat" class="org.crazyit.app.factory.BeingFactory"
		factory-method="getBeing">
		<!-- 配置静态工厂方法的参数 -->
		<constructor-arg value="cat"/>
		<!-- 驱动Spring以"我是猫"为参数来执行dog的setMsg()方法 -->
		<property name="msg" value="我是猫"/>
	</bean>
</beans>

一旦为<bean../>元素指定了factory-method属性,spring就不再调用构造器来创建Bean实例,而是调用工厂方法。如果同时指定了class和factory-method属性,那就会调用静态工厂方法来创建。

3.2.5、主程序

package lee;

import org.crazyit.app.service.Being;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

	public static void main(String[] args) {
		//以类加载路径下的配置文件创建ClassPathResource实例
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
		Being b1 = ctx.getBean("dog" , Being.class);
		b1.testBeing();
		Being b2 = ctx.getBean("cat" , Being.class);
		b2.testBeing();
	}
}

输出 输入图片说明

3.2.6、文件目录

输入图片说明

3.3、调用实例工厂方法

与静态工厂方法的区别

  • 调用静态工厂方法只需要工厂类就行,而调用实例工厂方法需要工厂实例;
  • 配置也有一点区别:前者使用class属性代表静态工厂类,后者不再需要class,用factory-bean代表工厂实例;之所以不用class是因为使用实例工厂方法时,spring不再直接实例化该bean,而是调用实例工厂的工厂方法来创建Bean实例。

<bean../>元素包括以下两个属性:

  • factory--bean:其值为工厂Bean的id;
  • factory-method:指定实例工厂的工厂方法;

代码实现

3.3.1、创建一个接口

该接口为实例工厂方法产生对象实现的接口

package org.crazyit.app.service;
public interface Person{
	//定义一个打招呼的方法
	public String sayHello(String name);
	//定义一个再见的方法
	public String sayGoodBye(String name);	
}

3.3.2、定义两个实现类

package org.crazyit.app.service.impl;

import org.crazyit.app.service.Person;

public class American implements Person{
	public String sayHello(String name) {
		return name + ",Hello";
	}
	public String sayGoodBye(String name) {
		return name + ",GoodBye";
	}
}
package org.crazyit.app.service.impl;

import org.crazyit.app.service.Person;

public class Chinese implements Person{
	public String sayHello(String name) {
		return name + ",你好!";
	}
	public String sayGoodBye(String name) {
		return name + ",再见!";
	}
}

3.3.3、定义一个实例工厂类

PersonFactory是负责产生person对象的实例工厂,该类提供了一个getPerson()的方法,根据传入的参数决定产生哪种person对象

package org.crazyit.app.factory;

import org.crazyit.app.service.Person;
import org.crazyit.app.service.impl.American;
import org.crazyit.app.service.impl.Chinese;

public class PersonFactory{
	//	获得Person实例的实例工厂方法,返回相应的Person实例的实现类;
	public Person getPerson(String ethnic){
		if(ethnic.equalsIgnoreCase("chin")){
			return new Chinese();
		}else{
			return new American();
		}
	}
}

3.3.4、创建配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<!-- 配置工厂Bean,该Bean负责产生其他Bean实例 -->
	<bean id="personFactory" class="org.crazyit.app.factory.PersonFactory"/>
	<!-- 下面配置驱动Spring调用personFactory Bean的getPerson()方法来创建Bean
	该bean元素包含的constructor-arg元素用于为工厂方法指定参数,-->
	<bean id="chinese" factory-bean="personFactory" 
		factory-method="getPerson">
		<!-- 配置实例工厂方法的参数 -->
		<constructor-arg value="chin"/>
	</bean>
	<bean id="american" factory-bean="personFactory"
		factory-method="getPerson">
		<constructor-arg value="ame"/>
	</bean>
</beans>

<bean../>的配置会驱动Spring以反射方式来执行如下代码:

// container代表Spring容器
PersonFactory pf = container.get("personFactory"); 
chinese = pf.getPerson("chin"); 

3.3.5、主程序

package lee;

import org.crazyit.app.service.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest
{
	public static void main(String[] args)
	{
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
		Person p1 = ctx.getBean("chinese" , Person.class);
		System.out.println(p1.sayHello("张三"));
		System.out.println(p1.sayGoodBye("张三"));
		Person p2 = ctx.getBean("american" , Person.class);
		System.out.println(p2.sayHello("Jack"));
		System.out.println(p2.sayGoodBye("Jack"));
	}
}

输出 输入图片说明

3.3.6、文件目录

输入图片说明

3.4、总结

调用静态工厂和实例工厂方法创建Bean的异同之处:

(1)、相同点

  • 都使用factory-method属性来制定生产Bea的实例方法;
  • 若工厂方法需要传入参数,都需要<constructor-arg../>元素指定参数值;
  • 普通的设值注入都需要<property../>元素确定参数值;

(2)、不同点

  • 配置实例工厂创建Bean,必须将实例工厂配置成Bean实例;配置静态工厂创建Bean,无需配置工厂Bean;
  • 配置实例工厂创建Bean,必须用factory-bean属性来确定工厂Bean;配置静态工厂创建Bean,用class来确定静态工厂类;

© 著作权归作者所有

yuhuan121
粉丝 0
博文 36
码字总数 38704
作品 0
佛山
程序员
私信 提问
《Spring5学习》 01 装配Bean之自动化装配

Spring的自动化装配就便利性方面远远优于其他装配方法,这也是业界目前主要采用的Bean装配机制。Spring基于组建扫描和自动装配实现自动化装配,能将用户的显示配置降到最低。以下通过一段代码...

老韭菜
2018/08/05
123
0
三条路线告诉你如何掌握Spring IoC容器的核心原理

一、前言 前三篇已经从历史的角度和大家一起探讨了为什么会有Spring,Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国。本节的主要目的就是通过一个切入点带大家一...

Java小铺
2018/08/27
0
0
Spring_总结_02_依赖注入

一、前言 本文承接上一节:Spring总结01_Spring概述 在上一节中,我们了解了Spring的最根本使命、四大原则、六大模块以及Spring的生态。 这一节我们开始了解Spring的第二大原则中的依赖注入,...

rayner
2018/07/27
0
0
day33_Spring学习笔记_01

零、蓦然回首 Struts2:web层,比较简单(难点:ValueStack值栈、拦截器) Hibernate:dao层,知识点杂(学了不用,默认设置够用了) Spring:service层,重要,(讲多少用多少) Spring课程...

黑泽明军
2018/07/22
0
0
向Spring大佬低头——大量源码流出解析

用Spring框架做了几年的开发,只停留在会用的阶段上,然而Spring的设计思想和原理确实一个巨大的宝库。大部分人仅仅知道怎么去配,或着加上什么属性就能达到什么效果,这些东西都可以通过查文...

Java团长17
2018/07/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Cloud Sleuth 整合 feign 源码分析之修改span名称

org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClient 包括创建span一些参数 需求场景: 由于项目中有restful 风格的http请求,sleuth feign 的span名称默认是u...

xiaomin0322
30分钟前
4
0
Less 延伸

extend 是一个 Less 伪类,它通过使用 :extend 选择器在一个选择器中扩展其他选择器样式。 扩展语法 扩展可以是附加到选择器,也可以是集中放置在规则,看上去像是带有选择器参数的可选伪类,...

凌兮洛
30分钟前
4
0
RedHat 7.0系统中安装mysql 5.7.22

在安装之前,首先要查看的是,你的系统中有没有已经安装过的情况。键入rpm -qa|grep mysql,如果无任何显示,则表示没有安装过相关组件,如果有,则根据显示出来的名字,键入rpm -e --nodeps...

最菜最菜之小菜鸟
36分钟前
4
0
RPA:企业信息孤岛的“克星”

为了降本增效,近来世界范围内掀起一股流程优化的热潮,转型升级成为众多企业时刻挂在嘴边的热词。不过在企业数字化转型的过程中,信息孤岛的出现,往往成为了企业升级的绊脚石。 信息孤岛:...

UiBot
36分钟前
4
0
我的测试

我的测试

daiison
36分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部