欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Spring中Bean的生命周期和作用域及实现方式

程序员文章站 2024-03-05 12:12:36
前言 在applicationcontext.xml中配置完bean之后,bean的声明周期状态有哪些。生命周期的各个阶段可以做什么。在applicationcontex...

前言

在applicationcontext.xml中配置完bean之后,bean的声明周期状态有哪些。生命周期的各个阶段可以做什么。在applicationcontext.xml配置bean的作用域有哪些。其中各个作用域代表的是什么。适用于什么情况。这篇文章做一个记录。

生命周期

初始化

可以直接查看图片,图片来自spring bean life cycle

详解Spring中Bean的生命周期和作用域及实现方式

从上图看出,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>

执行结果

详解Spring中Bean的生命周期和作用域及实现方式

实现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>

结果:

详解Spring中Bean的生命周期和作用域及实现方式

销毁

详解Spring中Bean的生命周期和作用域及实现方式

同样,上图中表示来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");
 }
}

结果:

详解Spring中Bean的生命周期和作用域及实现方式

实现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的生命周期和作用域及实现方式

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()+"毫秒");
 }
}

结果:

详解Spring中Bean的生命周期和作用域及实现方式

从上面的结果图看出,以前的方式生成的对象每次都是相同的。通过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);
 }
}

结果

详解Spring中Bean的生命周期和作用域及实现方式

总结

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。