文档章节

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

yuhuan121
 yuhuan121
发布于 2017/08/25 00:38
字数 2477
阅读 1
收藏 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基于组建扫描和自动装配实现自动化装配,能将用户的显示配置降到最低。以下通过一段代码...

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

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

Java小铺
08/27
0
0
day33_Spring学习笔记_01

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

黑泽明军
07/22
0
0
Spring_总结_02_依赖注入

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

rayner
07/27
0
0
Spring实战 (一) 一切从Bean开始

Spring可以做很多事情,但是归根究底.Spring的核心仅仅是依赖注入(DI)/控制反转(IoC)和面向切面编程(AOP)而已.Spring的一切都是基于这2点 Spring的一切都是从Bean开始的.什么是Bean?凡是被Spr...

kenshiro
2013/09/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何在Java中生成比特币钱包地址

让我们通过学习比特币(Bitcoin)如何实施该技术的各个方面来工作,好吗?该技术包括以下几个方面: 比特币地址bitcoin address是用来发送和接收比特币的。 交易transaction是比特币从一个地...

geek12345
5分钟前
0
0
面试必备Linux基础知识

学习Linux之前,我们先来简单的认识一下操作系统。 一 从认识操作系统开始 1.1 操作系统简介 我通过以下四点介绍什么操作系统: 操作系统(Operation System,简称OS)是管理计算机硬件与软件...

小小明童鞋
5分钟前
0
0
SpringBoot基础教程3-1-3 Quartz定时任务单点持久化

1 概述 实际项目中,复杂的定时任务都会结合持久化,动态改变定时任务状态,本文将介绍基于Quartz的定时任务单点持久化方式,通过RESTful风格,演示定时任务的CRUD,最后使用Swagger测试。 ...

Mkeeper
22分钟前
3
0
Android入门—文件目录解析

AndroidManifest.xml 是每个android程序中必须的文件,它位于整个项目的根目录。我们每天都在使用这个文件,往里面配置程序运行所必要的组件,权限,以及一些相关信息。但是对于这个文件,我...

haoyuehong
25分钟前
0
0
IDEA中Maven打包时如何跳过测试

方法1:直接使用IDEA提供的方式 Maven命令栏的工具栏有下图中的图标,上面就写着 Skip Tests 按下图标后,如下图,test就不可用了 直接使用package命令即可。 方法2:自己编辑maven命令 进入...

karma123
38分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部