Spring中bean的生命周期

淩亂°似流年 2022-02-20 15:47 361阅读 0赞

Spring 中bean 的生命周期短暂吗?

生命周期源码解析

  1. spring中,从BeanFactoryApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton模式产生单一实例,对单线程的程序说并不会有什么问题,但对于多线程的程序,就必须注意安全(Thread-safe)的议题,防止多个线程同时存取共享资源所引发的数据不同步问题。
  2. 然而在spring中可以设定每次从BeanFactoryApplicationContext指定别名并取得Bean时都产生一个新的实例:例如:在spring中,singleton属性默认是true,只有设定为false,则每次指定别名取得的Bean时都会产生一个新的实例一个Bean从创建到销毁,如果是用BeanFactory来生成,管理Bean的话,会经历几个执行阶段(如图1.1):

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppblhZYW4_size_16_color_FFFFFF_t_70

Spring bean 实现初始化、销毁方法的方式

Spring 允许 Bean 在初始化完成后以及销毁前执行特定的操作,常用方法有三种:

  • 使用注解,在指定方法上加上@PostConstruct或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用;

    watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppblhZYW4_size_16_color_FFFFFF_t_70 1

  • 使用xml配置或注解Bean(initMethod=“方法名”,destoryMethod=“方法名”),通过 元素的 init-method/destroy-method属性指定初始化之后 /销毁之前调用的操作方法;
  • 实现InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法。

    watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppblhZYW4_size_16_color_FFFFFF_t_70 2

找工作的时候有些人会被问道Spring中Bean的生命周期,其实也就是考察一下对Spring是否熟悉,工作中很少用到其中的内容,那我们简单看一下。

  1. 在说明前可以思考一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy
  2. Spring上下文中的Bean也类似,如下
  • 1、实例化一个Bean--容器寻找Bean的定义信息并将其实例化,也就是我们常说的new;
  • 2、按照Spring上下文对实例化的Bean进行配置--使用依赖注入,Spring按照Bean定义信息配置Bean所有属性,也就是IOC注入;
  • 3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值;
  • 4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
  • 5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
  • 6、前置处理器:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
  • 7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。

    1. <bean id="demoBean" class="com.yangsq.bean.DemoBean" init-method="initMethod" destory-method="destoryMethod">
    2. .......
    3. </bean>

    watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppblhZYW4_size_16_color_FFFFFF_t_70 3

  1. ![20190414111907368.png][]
  • 8、后置处理器:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;
  • 注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
  • 9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
  • 10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

以上10步骤可以作为面试或者笔试的模板,另外我们这里描述的是应用Spring上下文Bean的生命周期,如果应用Spring的工厂也就是BeanFactory的话去掉第5步就Ok了。

实例:

  1. package com.linjie.cycle;
  2. import org.springframework.beans.factory.BeanNameAware;
  3. /**
  4. * @author LinJie
  5. * @Description:一个学生类(Bean),能体现其生命周期的Bean
  6. */
  7. public class Student implements BeanNameAware {
  8. private String name;
  9. //无参构造方法
  10. public Student() {
  11. super();
  12. }
  13. /** 设置对象属性
  14. * @param name the name to set
  15. */
  16. public void setName(String name) {
  17. System.out.println("设置对象属性setName()..");
  18. this.name = name;
  19. }
  20. //Bean的初始化方法
  21. public void initStudent() {
  22. System.out.println("Student这个Bean:初始化");
  23. }
  24. //Bean的销毁方法
  25. public void destroyStudent() {
  26. System.out.println("Student这个Bean:销毁");
  27. }
  28. //Bean的使用
  29. public void play() {
  30. System.out.println("Student这个Bean:使用");
  31. }
  32. /* 重写toString
  33. * @see java.lang.Object#toString()
  34. */
  35. @Override
  36. public String toString() {
  37. return "Student [name = " + name + "]";
  38. }
  39. //调用BeanNameAware的setBeanName()
  40. //传递Bean的ID。
  41. @Override
  42. public void setBeanName(String name) {
  43. System.out.println("调用BeanNameAware的setBeanName()..." );
  44. }
  45. }

XML注册:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- init-method:指定初始化的方法
  7. destroy-method:指定销毁的方法 -->
  8. <bean id="student" class="com.linjie.cycle.Student" init-method="initStudent" destroy-method="destroyStudent">
  9. <property name="name" value="LINJIE"></property>
  10. </bean>
  11. </beans>

测试类:

  1. package com.linjie.cycle;
  2. import org.junit.Test;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.AbstractApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class CycleTest {
  7. @Test
  8. public void test() {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10. Student student = (Student) context.getBean("student");
  11. //Bean的使用
  12. student.play();
  13. System.out.println(student);
  14. //关闭容器
  15. ((AbstractApplicationContext) context).close();
  16. }
  17. }

显示结果

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppblhZYW4_size_16_color_FFFFFF_t_70 4

Bean的后置处理器

  1. 上面bean的一生其实已经算是对bean生命周期很完整的解释了,然而bean的后置处理器,是为了对bean的一个增强。
  2. 分别在Bean的初始化前后对Bean对象提供自己的实例化逻辑
  3. - 实现BeanPostProcessor接口
  4. - postProcessBeforeInitialization方法
  5. - postProcessAfterInitialization方法

实例:MyBeanPostProcessor.java(实现BeanPostProcessor接口)

  1. package com.linjie.cycle;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. /**
  5. * bean的后置处理器
  6. * 分别在bean的初始化前后对bean对象提供自己的实例化逻辑
  7. * postProcessAfterInitialization:初始化之后对bean进行增强处理
  8. * postProcessBeforeInitialization:初始化之前对bean进行增强处理
  9. */
  10. public class MyBeanPostProcessor implements BeanPostProcessor {
  11. //对初始化之后的Bean进行处理
  12. //参数:bean:即将初始化的bean
  13. //参数:beanname:bean的名称
  14. //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean
  15. @Override
  16. public Object postProcessAfterInitialization(Object bean, String beanname) throws BeansException {
  17. Student stu = null;
  18. System.out.println("对初始化之后的Bean进行处理,将Bean的成员变量的值修改了");
  19. if("name".equals(beanname) || bean instanceof Student) {
  20. stu = (Student) bean;
  21. stu.setName("Jack");
  22. }
  23. return stu;
  24. }
  25. //对初始化之前的Bean进行处理
  26. //参数:bean:即将初始化的bean
  27. //参数:beanname:bean的名称
  28. //返回值:返回给用户的那个bean,可以修改bean也可以返回一个新的bean
  29. @Override
  30. public Object postProcessBeforeInitialization(Object bean, String beanname) throws BeansException {
  31. System.out.println("对初始化之前的Bean进行处理,此时我的名字"+bean);
  32. return bean;
  33. }
  34. }

XML注册组件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <!-- init-method:指定初始化的方法
  7. destroy-method:指定销毁的方法 -->
  8. <bean id="student" class="com.linjie.cycle.Student" init-method="initStudent" destroy-method="destroyStudent">
  9. <property name="name" value="LINJIE"></property>
  10. </bean>
  11. <!-- 配置bean的后置处理器,不需要id,IoC容器自动识别是一个BeanPostProcessor -->
  12. <bean class="com.linjie.cycle.MyBeanPostProcessor"></bean>
  13. </beans>

测试:

  1. package com.linjie.cycle;
  2. import org.junit.Test;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.AbstractApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class CycleTest {
  7. @Test
  8. public void test() {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  10. Student student = (Student) context.getBean("student");
  11. //Bean的使用
  12. student.play();
  13. System.out.println(student);
  14. //关闭容器
  15. ((AbstractApplicationContext) context).close();
  16. }
  17. }

结果:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0ppblhZYW4_size_16_color_FFFFFF_t_70 5

可以在applicationContext.xml中看到配置Bean后置处理器,不需要ID,只需要其全类名,因为IoC容器自动识别一个BeanPostProcessor。是对所有组件进行增强

参考:https://blog.csdn.net/w_linux/article/details/80086950

发表评论

表情:
评论列表 (有 0 条评论,361人围观)

还没有评论,来说两句吧...

相关阅读