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

网友投稿 190 2023-06-03


详解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参数

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

执行结果

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

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

结果:

销毁

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

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

配置加载器

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被销毁完成");

}

}

配置文件

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

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

正常情况下,如果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

}

}

配置文件:

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

加载配置文件:

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国际化支持

配置配置文件

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

message

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:p="http://springframework.org/schema/p"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd">

message

新建中文配置文件

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);

}

}

结果

总结

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java IO 字节流详解及实例代码
下一篇:ajax实现加载页面、删除、查看详细信息 bootstrap美化页面!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~