文档章节

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

yuhuan121
 yuhuan121
发布于 2017/08/25 00:38
字数 2477
阅读 1
收藏 0
点赞 0
评论 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
佛山
程序员
spring梳理(二) 基于注解的方式注册bean

我们知道,如果想要将bean交由spring容器管理,就需要首先将bean注册在spring容器中,而bean可以通过xml或者注解的方式进行注册,基于xml的配置一般是通过、等xml标签进行配置,然后由sprin...

wyn_lin ⋅ 05/25 ⋅ 0

spring4.0之二:@Configuration的使用

从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfi...

文文1 ⋅ 06/01 ⋅ 0

SpringBoot的幕后推手...

一、背景   这两年随着微服务的盛行,SpringBoot框架水到渠成的得到了高曝光,作为程序猿的我们,现在要是不知道一点SpringBoot相关的东西,貌似出去找工作都会被深深地鄙视,不过在我们开...

Java工程师-Distance ⋅ 06/01 ⋅ 0

Spring IOC 容器源码分析系列文章导读

1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本。经过十几年的迭代,现在的 Spring 框架已经非常成熟了。Spring 包含了众多模块,包括但不限于...

coolblog ⋅ 05/30 ⋅ 0

Spring中关于bean的作用域与生命周期

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什...

忻胜霄 ⋅ 06/07 ⋅ 0

Spring IOC知识点一网打尽!

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工...

Java3y ⋅ 05/22 ⋅ 0

Spring源码解析系列之IOC容器(一)

前言 实际上我所有的博客都是原来对原来印象笔记里笔记内容的加工,关于Spring源码自己已经解析了很多遍,但是时间长总是忘记,写一篇博客权当加强记忆,也算再次学习下大师们的设计思想,思...

后厂村老司机 ⋅ 06/02 ⋅ 0

深入理解Spring源码(一)-IOC容器的定位,载入,注册

前言:Spring源码继承,嵌套层次非常多,读起来非常容易晕,小伙伴们在看文章的时候一定要跟着文章的思路自己去源码里点一点,看一看,并且多看几次。就会越来越清晰。下面开始正题 1.Spring...

Meet相识_bfa5 ⋅ 05/01 ⋅ 0

Spring温故而知新 - bean的装配

按条件装配bean 就是当满足特定的条件时Spring容器才创建Bean,Spring中通过@Conditional注解来实现条件化配置bean package com.sl.ioc;import org.springframework.context.annotation.Bean;...

Java-老刘 ⋅ 05/07 ⋅ 0

Spring BeanFactory和FactoryBean

Spring BeanFactory和FactoryBean 1、BeanFactory BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是 Spring IOC所遵守的最底层和最基本的编程规范...

秋风醉了 ⋅ 04/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

线程池

一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。 二、线程池的体系结构: java.util.concurrent.Executor : 负责线程的使用...

stars永恒 ⋅ 21分钟前 ⋅ 0

你值5K还是15K?实战案例,测测你的分析功力

本文源自陈老师遇到的真实案例。 老板说:“我们今年准备参加展会,做一年。以前我没参加过,没关系,这里有一份展会数据,你回去分析下哪些有价值,后边组织的时候有个指导”。现在你收到任...

加米谷大数据 ⋅ 23分钟前 ⋅ 0

中文转英文功能

package com.sysware.task.util;import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;import net.sourceforge.pinyin4j.for......

AK灬 ⋅ 24分钟前 ⋅ 0

JNI Java层类关联C/C++层的类

Android开发时,因为要实现某某功能,需要集成算法公司的算法库(so库),这就需要自己编写JNI。 通常这些库提供的接口可以概况成1、初始化 2、算法处理 3、释放 4、打印版本号 初始化后会返...

国仔饼 ⋅ 27分钟前 ⋅ 0

maven下载jar包改为阿里云的maven库

一:修改maven安装路径中conf文件夹下的setting.xml文件 <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/......

夜醒者 ⋅ 28分钟前 ⋅ 0

电商用户行为分析大数据平台相关系列10-基础数据结构分析

电商用户行为分析大数据平台相关系列1-环境介绍 电商用户行为分析大数据平台相关系列2-HADOOP环境搭建 电商用户行为分析大数据平台相关系列3-HIVE安装 电商用户行为分析大数据平台相关系列4...

xiaomin0322 ⋅ 28分钟前 ⋅ 0

使用readLine()方法遇到的坑

下午玩 TCP/IP 的 Socket 通信时,使用 BufferedReader 的 readLine() 遇到了一个坑,现在终于解决了,特此记录下来。 程序很简单,客户段从控制台读取用户输入,然后发送至服务器端,主要代...

孟飞阳 ⋅ 29分钟前 ⋅ 0

基于Hadoop集群的Hive安装配置(Derby数据库)

Hive是一个数据仓库基础工具在Hadoop中用来处理结构化数据,提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行(具体的Hive架构大家自行搜索)。接下来主要讲下Hadoop集群下...

海岸线的曙光 ⋅ 30分钟前 ⋅ 0

CoreOS裸机iso安装和相关配置

裸机通过iso安装CoreOS,个人趟了很多坑,以下就是完整的从零开始部署和配置的过程,希望对大家有用。 一、安装CoreOS到硬盘 1. 准备Live iso镜像,制作好usb启动盘 Live iso下载地址 2. 搭建...

ykbj ⋅ 35分钟前 ⋅ 0

jquery控制表格锁列(转)

表格已经完成后新加的需求,要实现锁表格的第一列。很多带这种效果的都是js封装的框架或者具体某种框架的组件,不适用解决当前问题。作为后端开发又实在不熟样式,搜到了一个可以用的,虽然样...

刘昌鑫 ⋅ 37分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部