美文网首页
spring----bean生命周期的探索

spring----bean生命周期的探索

作者: 不过意局bugyj | 来源:发表于2019-09-28 16:38 被阅读0次

bean的生命周期是面试题中出现频率很高的一题,以前总是靠死记硬背来记住(毕竟在对bean的使用中这些操作很少),现在才尝试着用代码一试。

直接上代码:

xml配置bean:

        <bean id="person" class="bean.Person" init-method="initMethod" destroy-method="destroyMethod">
            <property name="name" value="hsw"/>
            <property name="age" value="12"/>
        </bean>

这里只配置了属性的值和init-method以及destroy-method两个方法。

bean的类代码:

@ToString
public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, DisposableBean, InitializingBean {

   private String name;
   private int age;

   public Person() {
      System.out.println("无参构造函数!");
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      System.out.println("setter begin!");
      this.name = name;
   }

   public int getAge() {
      return age;
   }

   public void setAge(int age) {
      System.out.println("setter begin!");
      this.age = age;
   }

   public String getBeanName() {
      return beanName;
   }

   public BeanFactory getBeanFactory() {
      return beanFactory;
   }

   private String beanName;
   private BeanFactory beanFactory;
   private ApplicationContext applicationContext;

   @Override
   public void setBeanName(String s) {
      System.out.println("beanNameAware");
      this.beanName = s;
   }

   @Override
   public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      System.out.println("beanFactoryAware");
      this.beanFactory = beanFactory;
   }

   @Override
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      System.out.println("applicationContextAware");
      this.applicationContext = applicationContext;
   }

   private void initMethod() {
      System.out.println("init-method");
   }

   private void destroyMethod() {
      System.out.println("destroy-method");
   }

   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println("InitializingBean afterPropertiesSet");
   }

   @Override
   public void destroy() throws Exception {
      System.out.println("Disposable destroy");
   }
}

可以看到bean实现的方法有很多,首先是xxxAware三个接口,能让bean察觉到spring容器存在的三个接口。然后就是两个非方法对应xml配置中的两个配置:initMethod、destroyMethod。最后就是实现了InitializingBean 的 afterPropertiesSet 方法和 Disposable 的 destroy 方法。这些方法都会在bean的生命周期中被调用以实现一些自定义的功能。

PostProcessor即bean的后处理器

自定义InstantiationAwareBeanPostProcessor:

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInstantiation");
        return null;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("postProcessProperties");
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInstantiation");
        return true;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization");
        return bean;
    }
}

在xml文件中配置一下:

<bean id="myInstantiationAwareBeanPostProcessor" class="others.MyInstantiationAwareBeanPostProcessor"/>

这里有必要说一下:此自定义类命名为MyInstantiationBeanPostProcessor,实现了InstantiationAwareBeanPostProcessor 的几个方法。意思是对实例化阶段处理。但却多出了与接口不太相符的初始化方法,这是因为InstantiationAwareBeanPostProcessor的父接口是BeanPostProcessor,这个接口有两个默认自定义类的接口没有实现(postProcessBeforeInitialization 和 postProcessAfterInitialization),我直接在自定义类中实现了(当然也可以自己自定义一个如MyInitialazation...自定义类实现)。

测试方法:

    @Test
    public void testOne() {
        ClassPathXmlApplicationContext context
                = new ClassPathXmlApplicationContext("/bean.xml");
        Person person = (Person) context.getBean("person");
        System.out.println(person);
        context.close();
    }

启动容器获取bean打印后关闭容器。

运行结果:

postProcessBeforeInstantiation
无参构造函数!
postProcessAfterInstantiation
postProcessProperties
setter begin!
setter begin!
beanNameAware
beanFactoryAware
applicationContextAware
postProcessBeforeInitialization
InitializingBean afterPropertiesSet
init-method
postProcessAfterInitialization
Person(...)//person信息,这里略
Disposable destroy
destroy-method

流程梳理

所以根据输出结果可以得出bean的生命周期大致为:

  1. InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation,顾名思义实例化之前调用,方法有两个参数,bean所属class对象和beanName,返回Object对象。
  2. 实例化,配置时使用的是set注入属性,所以这里调用无参构造方法。如果使用的是有参构造方法就不会了。
  3. InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation,顾名思义实例化之后调用,方法依旧两个参数:Object bean, String beanName,返回boolean。

这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。如果该方法返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值

  1. InstantiationAwareBeanPostProcessor 的 postProcessProperties 。

方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内对属性值进行修改

  1. 开始调用bean的setter方法注入配置的属性值。
  2. 注入配置好的aware接口的属性。
  3. BeanPostProcessor 的 postProcessBeforeInitialization方法,即调用初始化方法前进行相关处理,方法参数同样为Object bean, String beanName,返回Object对象。这里可以返回已经初始化好了bean,也可以返回包装后的bean,甚至其他bean。
  4. bean实现的接口InitializingBean 的 afterPropertiesSet方法,无参数无返回值,但在bean内部可以访问bean的相关属性。
  5. 然后就是init-method方法了,无参数无返回值,在bean内部。
  6. BeanPostProcessor 的 PostProcessAfterInitialation方法,参数返回值和before相同。
  7. 至此相关作用域获取到bean,这里是打印了bean的信息。如果是原型模式,bean的生命周期随其作用域。如果配置的是单例,则由spring容器管理,后面容器关闭时会有后续过程。
  8. 调用DisposableBean 的 destroy 方法, 无参数无返回值。
  9. 调用xml文件配置的destroy-method。

相关文章

网友评论

      本文标题:spring----bean生命周期的探索

      本文链接:https://www.haomeiwen.com/subject/qmctpctx.html