浅尝Spring注解开发_Bean生命周期及执行过程

Spring注解开发

浅尝Spring注解开发,基于Spring 4.3.12
包含Bean生命周期、自定义初始化方法、Debug BeanPostProcessor执行过程及在Spring底层中的应用

Bean生命周期

了解Bean的生命周期,就可以在Bean声明周期的不同阶段进行自定义的操作,满足更复杂的需求。简单的将Bean生命周期分为三个阶段:Bean创建、初始化、销毁

  • 对象创建:单实例在容器启动的时候创建对象,多实例在每次获取的时候创建对象
    • 初始化之前:BeanPostProcessor.postProcessBeforeInitialization()
  • 初始化:对象创建完成,并赋值好,调用初始化方法
    • 初始化之后:BeanPostProcessor.postProcessAfterInitialization()
  • [容器创建完成]
  • 销毁:单实例在容器关闭的时候销毁,多实例容器不会管理这个bean,容器不会调用销毁方法

现在可以通过下面方法在初始化和销毁时自定义初始化方法来干涉Bean创建过程。

  1. @Bean()注解参数
  2. InitializingBean、DisposableBean接口
  3. @PostConstruct、@PreDestroy注解
  4. BeanPostProcessor接口

1.@Bean生命周期

通过@Bean指定init-method和destroy-method的初始化方法

  • 先自定义Bean初始化和销毁方法
    @Component public class Car {    public Car(){   System.out.println("car constructor...");  }  //现在只是普通方法  public void init(){   System.out.println("car ... init...");  }  //现在只是普通方法  public void detory(){   System.out.println("car ... destory...");  }  } 
  • 配置进容器
    • 通过@Bean注解,在@Bean注册进容器时指定自定义方法
    @Configuration public class MainConfigOfLifeCycle {    //@Scope("prototype")多实例,不管销毁  //指定用于初始化和销毁的方法  @Bean(initMethod="init",destroyMethod="destory")  public Car car(){   return new Car();  }  } 
  • 测试
    public class IOCTest_LifeCycle {    @Test  public void test01(){   //1、创建ioc容器   AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);   System.out.println("容器创建完成...");      //applicationContext.getBean("car");   //关闭容器   applicationContext.close();  }  } 

    输出

    //先创建对象 car constructor... //再自定义初始化方法 car ... init... //创建完成 容器创建完成... //关闭时自定义销毁方法 car ... destory... 

2.InitializingBean,DisposableBean生命周期

接口,需实现,通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);

  • 实现接口,自定义初始化Bean
    public class Cat implements InitializingBean,DisposableBean {    public Cat(){   System.out.println("cat constructor...");  }   //定义销毁逻辑  @Override  public void destroy() throws Exception {   // TODO Auto-generated method stub   System.out.println("cat...destroy...");  }   //定义初始化逻辑  @Override  public void afterPropertiesSet() throws Exception {   // TODO Auto-generated method stub   System.out.println("cat...afterPropertiesSet...");  }  } 
  • 配置进容器
    • 在@Configuration配置类中使用@Bean
    • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
    //配置组件 @Component public class Cat implements InitializingBean,DisposableBean {  //... } 
    //扫描进容器 @ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle {  //... } 
  • 测试
    public class IOCTest_LifeCycle {    @Test  public void test01(){   //1、创建ioc容器   AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);   System.out.println("容器创建完成...");      //applicationContext.getBean("car");   //关闭容器   applicationContext.close();  } } 

    输出

    //注意顺序,每个Bean先构造并初始化,然后才进行下一个Bean,关闭时从内向外 (猫)cat constructor... (猫)cat...afterPropertiesSet... (车)car constructor... (车)car ... init... //创建完成  容器创建完成... //关闭时销毁 (车)car ... destory... (猫)cat...destroy... 

3.@PostConstruct生命周期

可以使用JSR250;

  • @PostConstruct:在bean创建完成并且属性赋值完成之后,来执行初始化方法
  • @PreDestroy:在容器销毁bean之前通知我们进行清理工作
  • 标注注解,自定义初始化Bean
    public class Dog {   public Dog(){   System.out.println("dog constructor...");  }    //对象创建并赋值之后调用  @PostConstruct  public void init(){   System.out.println("Dog....@PostConstruct...");  }    //容器移除对象之前  @PreDestroy  public void detory(){   System.out.println("Dog....@PreDestroy...");  } } 
  • 配置进容器
    • 在@Configuration配置类中使用@Bean
    • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
    @Component public class Dog {  //... } 
    //扫描进容器 @ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle {  //... } 
  • 测试
    public class IOCTest_LifeCycle {    @Test  public void test01(){   //1、创建ioc容器   AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);   System.out.println("容器创建完成...");      //applicationContext.getBean("car");   //关闭容器   applicationContext.close();  }  } 

    输出

    //注意顺序,每个Bean先构造并初始化,然后才进行下一个Bean,关闭时从内向外 (猫)cat constructor... (猫)cat...afterPropertiesSet... (狗)dog constructor... (狗)Dog....@PostConstruct... (车)car constructor... (车)car ... init... //创建完成 容器创建完成... //关闭时销毁 (车)car ... destory... (狗)Dog....@PreDestroy... (猫)cat...destroy... 

4.BeanPostProcessor

postProcessBeforeInitialization:在创建Bean实例之后,在自定义初始化之前进行调用

postProcessAfterInitialization:在自定义初始化之后进行调用

BeanPostProcessor接口:bean的后置处理器,需实现,在bean初始化前后进行一些处理工作

  • postProcessBeforeInitialization:(自定义初始化,如InitializingBean[afterPropertiesSet]、init-method等,就是上面那些自定义初始化方法)初始化之前工作(创建Bean实例之后,在自定义初始化之前)
  • postProcessAfterInitialization:在(自定义)初始化之后工作
  • 实现后置处理器接口
    public class MyBeanPostProcessor implements BeanPostProcessor {   //初始化前置方法  //bean:新创建的实例,还未初始化  //beanName:未初始化的Bean名字  @Override  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {   // TODO Auto-generated method stub   System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);   return bean;  }  //初始化后置方法  @Override  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {   // TODO Auto-generated method stub   System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);   return bean;  }      } 
  • 配置进容器
    • 在@Configuration配置类中使用@Bean
    • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan
    @Component public class MyBeanPostProcessor implements BeanPostProcessor {      //... } 
    //扫描进容器 @ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle {  //... } 
  • 测试
    • 这次没有新增的Bean,只配置了一个后置处理器,
    • 这个后置处理器会对容器中的Bean起作用,包括上面三种自定义初始化Bean
    public class IOCTest_LifeCycle {    @Test  public void test01(){   //1、创建ioc容器   AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);   System.out.println("容器创建完成...");      //applicationContext.getBean("car");   //关闭容器   applicationContext.close();  }  } 

    输出

    //对于每一个Bean都要执行一遍 //1.创建 //2.BeanPostProcessor.postProcessBeforeInitialization() //3.初始化:对象创建完成,并赋值好,调用初始化方法... //4.BeanPostProcessor.postProcessAfterInitialization() //5.销毁   //以其中一个Bean为例: //构造对象 cat constructor... //初始化之前 postProcessBeforeInitialization...cat=>com.xxx.bean.Cat@7d68ef40 //使用InitializingBean自定义初始化逻辑 cat...afterPropertiesSet... //初始化之后 postProcessAfterInitialization...cat=>com.xxx.bean.Cat@7d68ef40 //创建完成 容器创建完成... //关闭时销毁 cat ... destroy... 

⭐BeanPostProcessor原理

bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxxBeanPostProcessor都通过BeanPostProcessor实现

详细视频 https://www.bilibili.com/video/BV1gW411W7wy?p=16

主要方法

populateBean(beanName, mbd, instanceWrapper):给bean进行属性赋值 initializeBean:初始化Bean {     applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);初始化前应用后置处理器     invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化     applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);初始化后应用后置处理器 } 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization, 一但返回null,跳出for循环 

执行过程

了解BeanPostProcessor的执行过程,从AnnotationConfigApplicationContext开始Debug

public class IOCTest_LifeCycle {    @Test  public void test01(){   //1、创建ioc容器   AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);   System.out.println("容器创建完成...");      //applicationContext.getBean("car");   //关闭容器   applicationContext.close();  } } 
  1. 先从创建ioc容器开始,进入AnnotationConfigApplicationContext()构造方法,执行里面的refresh()方法刷新容器
    1. refresh()方法里面有一个finishBeanFactoryInitialization(beanFactory)初始化所有剩余的单实例对象,进入这个方法
  2. 这个方法最后一步有一个beanFactory.preInstantiateSingletons()初始化所有单实例Bean,进入这个方法
    1. 触发所有非惰性单例bean的初始化
    2. 里面调用getBean(beanName)
    3. 进入getBean(beanName)里面再调用doGetBean(name,null,null,false)
    4. 进入doGetBean(name,null,null,false)里面有getSingleton(beanName,new ObjectFactory(){singletonFactory.getObject()})通过匿名内部类调用getObject()
  3. 此时通过匿名类getObject()进入下一个调用栈AbstractBeanFactory$1.getObject(),如果是单例,调用createBean(beanName,mbd,args)
  4. 进入createBean(beanName,mbd,args)调用doCreateBean(beanName,mbd,args)创建一个实例,过程如下
    1. 进入doCreateBean(beanName,mbd,args),里面调用一个initializeBean(beanName,exposedObject,mbd)初始化方法,这个方法里面就是调用的后置处理器
    2. 在这个方法上面有populateBean(beanName,mbd,instanceWrapper)方法,这个方法为Bean属性赋值
    3. 进入initializeBean(beanName,exposedObject,mbd),下面有一个invokeInitMethods(beanName,wrappedBean,mbd)执行初始化方法(就是上面的自定义初始化InitializingBean[afterPropertiesSet]、init-method)
    4. invokeInitMethods(beanName,wrappedBean,mbd)[在初始化之前应用 BeanPost 处理器]上面有一个applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)下面有一个applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName)[在初始化之后应用 BeanPost 处理器],作用是在初始化之前应用所有的BeanPostProcessors在初始化之后应用所有的BeanPostProcessors
  5. 进入applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)
    1. 里面有getBeanPostProcessors()找到所有BeanPostProcessors遍历,包括Spring系统的BeanPostProcessorApplicationContextAwareProcessorConfigurationClassPostProcessor等,然后才是自定义的MyBeanPostProcessor,依次执行beanProcessor.postProcessBeforeInitialization()
    2. 如果有执行返回null,就结束遍历,返回null,后面的处理器就不执行了(不应用后续的BeanPostProcessors了)

调用栈

  • 获取单例image
  • 创建实例Beanimage
  • 给Bean属性赋值和初始化Beanimage

完整流程

Spring底层对 BeanPostProcessor 的使用;

image

  1. 由上图可以看到,Spring中的BeanPostProcessor在实例化过程处于的位置,BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization
  2. 前者在实例化及依赖注入完成后、在任何初始化代码(比如配置文件中的init-method)调用之前调用;后者在初始化代码调用之后调用。

⭐BeanPostProcessor在Spring底层的使用

许多注解底层都是基于BeanPostProcessor

BeanPostProcessor接口实现类

image

向组件中注入IoC容器

在Bean创建过程中,初始化之前,判断是否实现了某Aware接口,如果实现了,就向Bean中注入ApplicationContext容器

  • 向Bean中注入IoC容器
    • 实现ApplicationContextAware接口,声明属性,赋值,就可以在组件中使用Ioc容器
      @Component public class Dog implements ApplicationContextAware {    //声明IoC容器  private ApplicationContext applicationContext;    public Dog(){   System.out.println("dog constructor...");  }    //对象创建并赋值之后调用  @PostConstruct  public void init(){   System.out.println("Dog....@PostConstruct...");  }    //容器移除对象之前  @PreDestroy  public void detory(){   System.out.println("Dog....@PreDestroy...");  }   //把applicationContext IoC容器赋值给属性  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {   // TODO Auto-generated method stub   this.applicationContext = applicationContext;  } } 
  • 原理是通过ApplicationContextAwareProcessor实现
    • ApplicationContextAwareProcessor实现了BeanPostProcessor接口image
    • postProcessBeforeInitialization()方法中
      1. 在Bean初始化之前,判断Bean是否实现了ApplicationContextAware接口,或其他Aware接口
      2. 如果实现了,就调用invokeAwareInterfaces(bean)给Bean注入值
      3. 判断Bean是什么类型Aware,将Bean转成对应类型调用((ApplicationContextAware)bean).setApplicationContext(this.applicationContext)注入IoC容器
      4. 于是就到了上面实现的接口的未实现方法中

数据校验

  • BeanValidationPostProcessor也实现了BeanPostProcessor接口
  • 在Bean创建完赋值后,同样调用postProcessBeforeInitialization()方法,进行数据校验
    • postProcessBeforeInitialization(){doValidate(bean)}
    • postProcessAfterInitialization(){doValidate(bean)}

自定义初始化注解

  • Bean初始化有一种方法是使用@PostConstruct注解,也是通过BeanPostProcessor实现
  • InitDestroyAnnotationBeanPostProcessor处理@PostConstruct@PreDestroy注解
    • postProcessBeforeInitialization()中找到Bean的生命周期注解所标注的方法,如initMethods、destroyMethods
    • 找到之后就执行注解标注的初始化方法metatata.invokeInitMethods(bean,beanName)element.invoke(target),利用反射执行。

自动注入注解@Autowired

  • 为什么@Autowired能够自动注入值,是通过这个AutowiredAnnotationBeanPostProcessor实现BeanPostProcessors接口
  • 在对象创建完之后,处理标注@Autowired标注的所有属性进行注入值

标签:

商匡云商
Logo
对比商品
  • 合计 (0)
对比
0
购物车