详解Spring中Bean的生命周期和作用域及实现方式
前言
在applicationcontext.xml中配置完bean之后,bean的声明周期状态有哪些。生命周期的各个阶段可以做什么。在applicationcontext.xml配置bean的作用域有哪些。其中各个作用域代表的是什么。适用于什么情况。这篇文章做一个记录。
生命周期
初始化
可以直接查看图片,图片来自spring bean life cycle
从上图看出,bean初始化完成包括9个步骤。其中一些步骤包括接口的实现,其中包括beannameaware接口,beanfactoryaware接口。applicationcontextaware接口。beanpostprocessor接口,initializingbean接口。那么这些接口在整个生命周期阶段都起到什么作用?后面我们一一介绍。
实例化前
当bean全部属性设置完毕后,往往需要执行一些特定的行为,spring提供了两种方式来实现此功能:
- 使用init-mothod方法
- 实现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("执行构造方法"); } 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("调用init方法进行成员变量的初始化"); 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参数
<?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>
执行结果
实现initializingbean接口
实现initializingbean接口会实现afterpropertiesset方法,这个方法会自动调用。但是这个方式是侵入性的。一般情况下,不建议使用。
实现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("执行构造方法"); } 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("调用init方法进行成员变量的初始化"); this.name = name; this.age = age; system.out.println("初始化完成"); } @override public void afterpropertiesset() throws exception { // todo auto-generated method stub system.out.println("调用init方法进行成员变量的初始化"); 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>
结果:
销毁
同样,上图中表示来bean销毁时候的过程。包括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("执行构造方法"); } 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("调用init方法进行成员变量的初始化"); this.name = name; this.age = age; system.out.println("初始化完成"); } @override public void afterpropertiesset() throws exception { // todo auto-generated method stub system.out.println("调用init方法进行成员变量的初始化"); 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"); } }
结果:
实现disposablebean接口
实现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("执行构造方法"); } 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("调用init方法进行成员变量的初始化"); this.name = name; this.age = age; system.out.println("初始化完成"); } @override public void afterpropertiesset() throws exception { // todo auto-generated method stub system.out.println("调用init方法进行成员变量的初始化"); 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 | 该作用域将 bean 的定义的限制在每一个 spring ioc 容器中的一个单一实例(默认)。 |
prototype | 该作用域将单一 bean 的定义限制在任意数量的对象实例。 |
request | 该作用域将 bean 的定义限制为 http 请求。只在 web-aware spring applicationcontext 的上下文中有效。 |
session | 该作用域将 bean 的定义限制为 http 会话。 只在web-aware spring applicationcontext的上下文中有效。 |
global-session | 该作用域将 bean 的定义限制为全局 http 会话。只在 web-aware spring applicationcontext 的上下文中有效。 |
配置示例
<bean id="..." class="..." scope="singleton"> </bean>
使用方法注入协调作用域不同的bean
正常情况下,如果singleton作用域依赖singleton作用域。即每次获取到的都是一样的对象。同理,prototype作用域依赖prototype作用域,每次获取到的都是新的对象。但是,如果singleton依赖prototype作用域,那么每次获取到的singleton中的prototype都是第一次创建的prototype。如何协调这种关系。保证每次获取到的都是正确的呢。
对于这种情况,spring提供了lookup方法用来解决这种问题。
首先我们定义一个原型:
package com.model; public class myhelper { public void dosomethinghelpful() { } }
然后通过接口注入:
package com.model; public interface demobean { myhelper gethelper(); void someperation(); }
配置一个单例:
package com.model; /** * 测试类 * @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("测试"+beanname); system.out.println("两个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次花费了"+stopwatch.gettotaltimemillis()+"毫秒"); } }
结果:
从上面的结果图看出,以前的方式生成的对象每次都是相同的。通过lookup方式注入每次是不同的。可以解决这种问题。但是有没有更简单的方式,感觉这种方式优点麻烦。
让bean感知spring容器
实现beannameaware,自定设置id值。
实现beanfactoryaware,applicationcontextaware 感知spring容器。获取spring容器。
spring国际化支持
配置配置文件
<?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); } }
结果
总结
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
上一篇: Java初学者常问的问题(推荐)
下一篇: java编写的文件管理器代码分享