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

Java 投稿 43100 1 评论

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

Spring注解开发

包含Bean生命周期、自定义初始化方法、Debug BeanPostProcessor执行过程及在Spring底层中的应用

浅尝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...");
    	}
    
    }
  • 配置进容器

    @Configuration
    public class MainConfigOfLifeCycle {
    	
    	//@Scope("prototype")多实例,不管销毁
    	//指定用于初始化和销毁的方法
    	@Bean(initMethod="init",destroyMethod="destory")
    	public Car car(){
    		return new Car();
    	}
    
    }
    • 通过@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();
    	}
    
    }

    输出

    //先创建对象
    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...");
    	}
    
    }
  • 配置进容器

    //配置组件
    @Component
    public class Cat implements InitializingBean,DisposableBean {
    	//...
    }
    //扫描进容器
    @ComponentScan("com.xxx.bean")
    @Configuration
    public class MainConfigOfLifeCycle {
    	//...
    }
    • 在@Configuration配置类中使用@Bean

    • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan

  • 测试

    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...");
    	}
    }
  • 配置进容器

    @Component
    public class Dog {
    	//...
    }
    //扫描进容器
    @ComponentScan("com.xxx.bean")
    @Configuration
    public class MainConfigOfLifeCycle {
    	//...
    }
    • 在@Configuration配置类中使用@Bean

    • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan

  • 测试

    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初始化前后进行一些处理工作

  • (自定义初始化,如InitializingBean[afterPropertiesSet]、init-method等,就是上面那些自定义初始化方法)初始化之前工作(创建Bean实例之后,在自定义初始化之前)

  • 在(自定义)初始化之后工作

  • 实现后置处理器接口

    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;
    	}
        
    }
  • 配置进容器

    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        //...
    }
    //扫描进容器
    @ComponentScan("com.xxx.bean")
    @Configuration
    public class MainConfigOfLifeCycle {
    	//...
    }
    • 在@Configuration配置类中使用@Bean

    • 或在Bean类上使用@Component然后再配置类上使用@ComponentScan

  • 测试

    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...
    • 这次没有新增的Bean,只配置了一个后置处理器,

    • 这个后置处理器会对容器中的Bean起作用,包括上面三种自定义初始化Bean

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容器开始,进入构造方法,执行里面的方法刷新容器

    1. 方法里面有一个初始化所有剩余的单实例对象,进入这个方法

  2. 这个方法最后一步有一个初始化所有单实例Bean,进入这个方法

    1. 触发所有非惰性单例bean的初始化

    2. 里面调用,

    3. 进入里面再调用

    4. 进入里面有通过匿名内部类调用

  3. 此时通过匿名类进入下一个调用栈,如果是单例,调用

  4. 进入调用创建一个实例,过程如下

    1. 进入,里面调用一个初始化方法,这个方法里面就是调用的后置处理器

    2. 在这个方法上面有方法,这个方法为Bean属性赋值

    3. 进入,下面有一个执行初始化方法(就是上面的自定义初始化InitializingBean[afterPropertiesSet]、init-method)

    4. 在上面有一个下面有一个,作用是在初始化之前应用所有的在初始化之后应用所有的

  5. 进入

    1. 里面有找到所有遍历,包括Spring系统的如、等,然后才是自定义的,依次执行

    2. 如果有执行返回null,就结束遍历,返回null,后面的处理器就不执行了(不应用后续的了)

调用栈

  • 获取单例

  • 创建实例Bean

  • 给Bean属性赋值和初始化Bean

完整流程

Spring底层对 BeanPostProcessor 的使用;

  1. 由上图可以看到,Spring中的BeanPostProcessor在实例化过程处于的位置,BeanPostProcessor接口有两个方法需要实现:postProcessBeforeInitialization和postProcessAfterInitialization

  2. 前者在实例化及依赖注入完成后、在任何初始化代码(比如配置文件中的init-method)调用之前调用;后者在初始化代码调用之后调用。

BeanPostProcessor在Spring底层的使用

许多注解底层都是基于BeanPostProcessor

BeanPostProcessor接口实现类

向组件中注入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;
      	}
      }
  • 原理是通过实现

    • 实现了接口

    • 在方法中

    1. 在Bean初始化之前,判断Bean是否实现了接口,或其他Aware接口

    2. 如果实现了,就调用给Bean注入值

    3. 判断Bean是什么类型Aware,将Bean转成对应类型调用注入IoC容器

    4. 于是就到了上面实现的接口的未实现方法中

数据校验

  • 也实现了接口

  • 在Bean创建完赋值后,同样调用方法,进行数据校验



自定义初始化注解

  • Bean初始化有一种方法是使用注解,也是通过实现

  • 处理和注解

    • 在中找到Bean的生命周期注解所标注的方法,如

    • 找到之后就执行注解标注的初始化方法和,利用反射执行。

自动注入注解@Autowired

  • 为什么@Autowired能够自动注入值,是通过这个实现接口

  • 在对象创建完之后,处理标注标注的所有属性进行注入值

编程笔记 » 浅尝Spring注解开发Bean生命周期及执行过程

赞同 (65) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(1)个小伙伴在吐槽
  1. 总是能迅速采取行动。
    不朽歌者 2023-10-16 12:30 (2年前) 回复