詳解Spring中Bean的生命周期和作用域及實(shí)現(xiàn)方式
前言
在applicationContext.xml中配置完bean之后,Bean的聲明周期狀態(tài)有哪些。生命周期的各個(gè)階段可以做什么。在applicationContext.xml配置bean的作用域有哪些。其中各個(gè)作用域代表的是什么。適用于什么情況。這篇文章做一個(gè)記錄。
生命周期
初始化
可以直接查看圖片,圖片來(lái)自Spring Bean Life Cycle

從上圖看出,Bean初始化完成包括9個(gè)步驟。其中一些步驟包括接口的實(shí)現(xiàn),其中包括BeanNameAware接口,BeanFactoryAware接口。ApplicationContextAware接口。BeanPostProcessor接口,InitializingBean接口。那么這些接口在整個(gè)生命周期階段都起到什么作用?后面我們一一介紹。
實(shí)例化前
當(dāng)Bean全部屬性設(shè)置完畢后,往往需要執(zhí)行一些特定的行為,Spring提供了兩種方式來(lái)實(shí)現(xiàn)此功能:
- 使用init-mothod方法
- 實(shí)現(xiàn)initializingBean接口
指定初始化方法
如下:
package com.model;
public class InitBean {
public static final String NAME = "mark";
public static final int AGE = 20;
public InitBean() {
// TODO Auto-generated constructor stub
System.out.println("執(zhí)行構(gòu)造方法");
}
public String name;
public int age ;
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 void init(){
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
}
編寫加載器
package com.model;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.service.UserServiceImpl;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("initbean.xml");
InitBean bean = (InitBean) context.getBean("init");
}
}
配置Bean
注意init-method參數(shù)
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="init" class="com.model.InitBean" init-method="init"/> </beans>
執(zhí)行結(jié)果

實(shí)現(xiàn)InitializingBean接口
實(shí)現(xiàn)InitializingBean接口會(huì)實(shí)現(xiàn)afterPropertiesSet方法,這個(gè)方法會(huì)自動(dòng)調(diào)用。但是這個(gè)方式是侵入性的。一般情況下,不建議使用。
實(shí)現(xiàn)afterPropertiesSet方法
package com.model;
import org.springframework.beans.factory.InitializingBean;
public class InitBean implements InitializingBean {
public static final String NAME = "mark";
public static final int AGE = 20;
public InitBean() {
// TODO Auto-generated constructor stub
System.out.println("執(zhí)行構(gòu)造方法");
}
public String name;
public int age ;
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 void init(){
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
}
配置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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- <bean id="init" class="com.model.InitBean" init-method="init"/> --> <bean id="init" class="com.model.InitBean" init-method="init"/> </beans>
結(jié)果:

銷毀

同樣,上圖中表示來(lái)Bean銷毀時(shí)候的過(guò)程。包括DisposableBean接口。
使用destroy-method方法
package com.model;
import org.springframework.beans.factory.InitializingBean;
public class InitBean implements InitializingBean {
public static final String NAME = "mark";
public static final int AGE = 20;
public InitBean() {
// TODO Auto-generated constructor stub
System.out.println("執(zhí)行構(gòu)造方法");
}
public String name;
public int age ;
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 void init(){
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
public void close(){
System.out.println("bean被銷毀");
}
}
配置Bean
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- <bean id="init" class="com.model.InitBean" init-method="init"/> --> <bean id="init" class="com.model.InitBean" destroy-method="close"/> </beans>
配置加載器
package com.model;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.service.UserServiceImpl;
public class Main {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("initbean.xml");
context.registerShutdownHook();
InitBean bean = (InitBean) context.getBean("init");
}
}
結(jié)果:

實(shí)現(xiàn)DisposableBean接口
實(shí)現(xiàn)DisposableBean接口
package com.model;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class InitBean implements InitializingBean,DisposableBean {
public static final String NAME = "mark";
public static final int AGE = 20;
public InitBean() {
// TODO Auto-generated constructor stub
System.out.println("執(zhí)行構(gòu)造方法");
}
public String name;
public int age ;
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 void init(){
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("調(diào)用init方法進(jìn)行成員變量的初始化");
this.name = NAME;
this.age = AGE;
System.out.println("初始化完成");
}
public void close(){
System.out.println("bean被銷毀");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("bean被銷毀完成");
}
}
配置文件
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- <bean id="init" class="com.model.InitBean" init-method="init"/> --> <!-- <bean id="init" class="com.model.InitBean" destroy-method="close"/> --> <bean id="init" class="com.model.InitBean"/> </beans>

Spring Bean的作用域
| 作用域 | 描述 |
| singleton | 該作用域?qū)?bean 的定義的限制在每一個(gè) Spring IoC 容器中的一個(gè)單一實(shí)例(默認(rèn))。 |
| prototype | 該作用域?qū)我?bean 的定義限制在任意數(shù)量的對(duì)象實(shí)例。 |
| request | 該作用域?qū)?bean 的定義限制為 HTTP 請(qǐng)求。只在 web-aware Spring ApplicationContext 的上下文中有效。 |
| session | 該作用域?qū)?bean 的定義限制為 HTTP 會(huì)話。 只在web-aware Spring ApplicationContext的上下文中有效。 |
| global-session | 該作用域?qū)?bean 的定義限制為全局 HTTP 會(huì)話。只在 web-aware Spring ApplicationContext 的上下文中有效。 |
配置示例
<bean id="..." class="..." scope="singleton"> </bean>
使用方法注入?yún)f(xié)調(diào)作用域不同的Bean
正常情況下,如果singleton作用域依賴singleton作用域。即每次獲取到的都是一樣的對(duì)象。同理,prototype作用域依賴prototype作用域,每次獲取到的都是新的對(duì)象。但是,如果singleton依賴prototype作用域,那么每次獲取到的singleton中的prototype都是第一次創(chuàng)建的prototype。如何協(xié)調(diào)這種關(guān)系。保證每次獲取到的都是正確的呢。
對(duì)于這種情況,Spring提供了lookup方法用來(lái)解決這種問(wèn)題。
首先我們定義一個(gè)原型:
package com.model;
public class MyHelper {
public void doSomethingHelpful() {
}
}
然后通過(guò)接口注入:
package com.model;
public interface DemoBean {
MyHelper getHelper();
void somePeration();
}
配置一個(gè)單例:
package com.model;
/**
* 測(cè)試類
* @author kevin
*
*/
public abstract class AbstractLookupDemo implements DemoBean {
public abstract MyHelper getMyHelper();
@Override
public MyHelper getHelper() {
// TODO Auto-generated method stub
return getMyHelper();
}
@Override
public void somePeration() {
// TODO Auto-generated method stub
}
}
配置文件:
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helper" class="com.model.MyHelper" scope="prototype"/> <bean id="standardLookupBean" class="com.model.StandardLookupDemo"> <property name="myHelper" ref="helper"></property> </bean> <bean id = "abstractLookupBean" class="com.model.AbstractLookupDemo"> <lookup-method name="getMyHelper" bean="helper"></lookup-method> </bean> </beans>
加載配置文件:
package com.model;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StopWatch;
public class Main {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("lookBean.xml");
context.registerShutdownHook();
System.out.println("傳遞standardLookupBean");
test(context, "standardLookupBean");
System.out.println("傳遞AbstractLookupDemo");
test(context, "abstractLookupBean");
}
public static void test(AbstractApplicationContext context,String beanName) {
DemoBean bean = (DemoBean) context.getBean(beanName);
MyHelper helper1 = bean.getHelper();
MyHelper helper2 = bean.getHelper();
System.out.println("測(cè)試"+beanName);
System.out.println("兩個(gè)helper是否相同?"+(helper1==helper2));
StopWatch stopWatch = new StopWatch();
stopWatch.start("lookupDemo");
for (int i = 0; i < 10000; i++) {
MyHelper helper = bean.getHelper();
helper.doSomethingHelpful();
}
stopWatch.stop();
System.out.println("獲取10000次花費(fèi)了"+stopWatch.getTotalTimeMillis()+"毫秒");
}
}
結(jié)果:

從上面的結(jié)果圖看出,以前的方式生成的對(duì)象每次都是相同的。通過(guò)lookup方式注入每次是不同的??梢越鉀Q這種問(wèn)題。但是有沒(méi)有更簡(jiǎn)單的方式,感覺(jué)這種方式優(yōu)點(diǎn)麻煩。
讓Bean感知Spring容器
實(shí)現(xiàn)BeanNameAware,自定設(shè)置id值。
實(shí)現(xiàn)BeanFactoryAware,ApplicationContextAware 感知Spring容器。獲取Spring容器。
Spring國(guó)際化支持
配置配置文件
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>message</value> </list> </property> </bean> </beans>
新建中文配置文件
message_zh_CN.properties:
hello=welcome,{0}
now=now is : {0}
新建英文配置文件
message_en_US.properties:
hello=\u4F60\u597D,{0}
now=\u73B0\u5728\u7684\u65F6\u95F4\u662F : {0}
加載配置文件
package com.model;
import java.util.Date;
import java.util.Locale;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StopWatch;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("globalization.xml");
String[] a = {"讀者"};
String hello = context.getMessage("hello",a, Locale.CHINA);
Object[] b = {new Date()};
String now = context.getMessage("now",b, Locale.CHINA);
System.out.println(hello);
System.out.println(now);
hello = context.getMessage("hello",a, Locale.US);
now = context.getMessage("now",b, Locale.US);
System.out.println(hello);
System.out.println(now);
}
}
結(jié)果

總結(jié)
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
關(guān)于Java中常見(jiàn)的負(fù)載均衡算法
這篇文章主要介紹了關(guān)于Java中常見(jiàn)的負(fù)載均衡算法,負(fù)載平衡是一種電子計(jì)算機(jī)技術(shù),用來(lái)在多個(gè)計(jì)算機(jī)、網(wǎng)絡(luò)連接、CPU、磁盤驅(qū)動(dòng)器或其他資源中分配負(fù)載,以達(dá)到優(yōu)化資源使用、最大化吞吐率、最小化響應(yīng)時(shí)間、同時(shí)避免過(guò)載的目的,需要的朋友可以參考下2023-08-08
JAVA面試題String產(chǎn)生了幾個(gè)對(duì)象
這篇文章主要介紹了JAVA面試題 String s = new String("xyz");產(chǎn)生了幾個(gè)對(duì)象?,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
IntelliJ IDEA2025創(chuàng)建SpringBoot項(xiàng)目的實(shí)現(xiàn)步驟
本文主要介紹了IntelliJ IDEA2025創(chuàng)建SpringBoot項(xiàng)目的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-07-07
帶大家認(rèn)識(shí)Java語(yǔ)法之泛型與通配符
使用泛型的目的是利用Java編譯機(jī)制,在編譯過(guò)程中幫我們檢測(cè)代碼中不規(guī)范的有可能導(dǎo)致程序錯(cuò)誤的代碼,下面這篇文章主要給大家介紹了關(guān)于Java泛型與通配符的相關(guān)資料,需要的朋友可以參考下2022-03-03
java生成申請(qǐng)單序列號(hào)的實(shí)現(xiàn)方法
申請(qǐng)單序列號(hào)一般要求根據(jù)一定的規(guī)則生成后幾位連續(xù)的字符串,下面是我項(xiàng)目中使用的生成序列號(hào)的代碼,其中用到了鎖機(jī)制,有需要的朋友可以參考一下2014-01-01
MyBatis中resultType和resultMap的用法及說(shuō)明
MyBatis通過(guò)resultType和resultMap將SQL查詢結(jié)果映射為Java對(duì)象,resultType適用于簡(jiǎn)單類型或完全匹配的Java類,resultMap則用于處理列名和屬性名不一致的情況2025-12-12
通過(guò)實(shí)例解析java String不可變性
這篇文章主要介紹了通過(guò)實(shí)例解析java String不可變性,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
解決Nacos成功啟動(dòng)但是無(wú)法訪問(wèn) (Connection refused)
這篇文章主要介紹了解決Nacos成功啟動(dòng)但是無(wú)法訪問(wèn) (Connection refused)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06

