Spring底层原理分析-三(bean的生命周期)

190 阅读4分钟

Bean的生命周期

  这一节我们来探究一下bean的生命周期,这也是个面试高频问题。这里我们先搭建一个基于SpringBoot应用程序来分析一下。

public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(DemoBoot.class, args);
    context.close();
}

@Component
public class DemoBean {

    public DemoBean() {System.out.println("DemoBean构造执行!");}

    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String home) {
        System.out.println("依赖注入:" + home);
    }

    @PostConstruct
    public void init(){System.out.println("初始化");}

    @PreDestroy
    public void destroy(){System.out.println("销毁");}

}
运行结果:
DemoBean构造执行!
依赖注入:D:\Java\jdk1.8
初始化
销毁

  这个程序没什么特殊的地方根据运行结果可以看出bean的运行过程。大致的过程基本可以分为:实例化、依赖注入、初始化、销毁四个阶段。但是每个阶段都附加了很多很多的后置处理器,正是在每个阶段的后置处理器实现了很多很多的功能,我们写个例子测试一下。

@Component
public class DemoBeanPostProcessor implements InstantiationAwareBeanPostProcessor,
       DestructionAwareBeanPostProcessor {
   @Override
   public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
       if(beanName.equals("demoBean"))
           System.out.println("BeanPostProcessor:销毁之前执行方法!");
   }

   @Override
   public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
       if(beanName.equals("demoBean"))
           System.out.println("BeanPostProcessor:实例化之前执行方法!");
       return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
   }

   @Override
   public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
       if(beanName.equals("demoBean"))
           System.out.println("BeanPostProcessor:实例化之后执行方法!");
       return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
   }

   @Override
   public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
       if(beanName.equals("demoBean"))
           System.out.println("BeanPostProcessor:依赖注入执行方法!");
       return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
   }

   @Override
   public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
       return InstantiationAwareBeanPostProcessor.super.postProcessPropertyValues(pvs, pds, bean, beanName);
   }

   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       if(beanName.equals("demoBean"))
           System.out.println("BeanPostProcessor:初始化之前执行方法!");
       return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
   }

   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
       if(beanName.equals("demoBean"))
           System.out.println("BeanPostProcessor:初始化之后执行方法!");
       return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
   }
}

  定义一个专门处理这些后置处理器的bean,实现InstantiationAwareBeanPostProcessor接口和DestructionAwareBeanPostProcessor接口并实现他们的方法。由代码中的打印注释可以看到每个方法的执行时机。

image.png

  对比上面没有添加后置处理器的结果,bean在整个生命周期中,因为后置处理器的存在,增添了很多的步骤来填充整个周期过程。

模板方法

  上面的后置处理器的代码方式,运用模板方法的设计模式,这里扩展一下该设计模式的设计思想。

public class DemoMethodTemplate {
    public static void main(String[] args) {
        MyBeanFactory myBeanFactory = new MyBeanFactory();
        myBeanFactory.addProcessors(bean -> {
            System.out.println("处理bean");
            return bean;
        });
        myBeanFactory.getBean();
    }
    
    static class MyBeanFactory{
        private List<MyBeanPostProcessor> processors = new ArrayList<>();

        public Object getBean(){
            Object bean = new Object();
            System.out.println("执行构造!");
            System.out.println("依赖注入!");
            for (MyBeanPostProcessor processor : processors) {
                bean = processor.inject(bean);
            }
            System.out.println("初始化!");
            System.out.println("销毁!");
            return bean;
        }

        public void addProcessors(MyBeanPostProcessor processor){
            processors.add(processor);
        }
    }

    interface MyBeanPostProcessor{
        Object inject(Object bean);
    }
}

  我们简单模仿一个BeanFactory获取bean的过程,当执行getBean()方法的时候,将会调用bean的构造方法,做一系列的bean生命周期中的操作,这里用简单的打印代替。这时候,我们这些流程就是固定的,我们现在有这样的一个需求,需要给初始化之前添加一些后置处理器来对bean做增强操作,该怎么做呢。我们直接看上面的代码呈现,步骤如下:

  • 我们定义一个公共接口MyBeanPostProcessor,后面我们写的处理器需要定义成什么操作都需要实现该接口;
  • 在MyBeanFactory中定义一个结合,用来存放所有该接口形式的类集合;
  • 在MyBeanFactory中添加一个addProcessors方法,用来给集合中添加后置处理器;
  • main方法中调用addProcessors方法,增加一个MyBeanPostProcessor的实现类,并实现要求的方法;
  • 在需要增强的步骤中循环集合,并执行。

  整体流程走下来,完成了什么呢,我们发现不需要对bean本身做任何修改,当需要做增强操作时,只需要增加一个实现类并实现其中方法做具体操作。当getBean的时候自然会循环调用。这就是模板方法的含义,我们这里将bean本身传入接口定义的方法,这样可以将需要操作的bean传给要实现的方法,方法实现后,可以将增强后的bean再次返回。这也就是上面众多Spring提供的后置处理器里bean参数的意义。如果不做任何操作,默认是将原有bean原样返回。

image.png