Bean生命周期

Bean生命周期

针对部分同学说的不理解Bean生命周期面试题里面的长篇大论的描述,今天带大家把每个步骤都过一遍,并教会大家正确的理解其问题,以及组织自己的语言描述它。

目前网络上流行的bean生命周期描述大致为以下流程

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中
  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
  7. 如果Bean的方法上加了@PostConstruct注解,也会执行该初始化代码
  8. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
  9. 如果当前bean的 @Bean 注解的属性里面有initMethod属性指向的方法,则也会执行该方法
  10. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
  11. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
  12. 如果bean实现了@PreDestroy 注解的方法 或者 DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

乍一看,太多了,根本背不过来。还有就是为什么是这些流程呢?

生命周期的概念其实在Spring官网上就已经描述过了

大致分为5个部分

Initialization Callbacks(初始化回调)

意思是实现 InitializingBean 接口,它有个方法

void afterPropertiesSet() throws Exception;

但实际上Spring并不推荐这种方式,更推荐用@PostConstruct注释,这样可以和Spring容器进行解耦操作。

另外还可以指定POJO初始化方法。

如下代码所示

一、引导类

public class SpringBeanApp {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
        MyBean bean = context.getBean(MyBean.class);
        System.out.println(bean);
    }

}

二、配置类

@Configuration
public class MyBeanConfig {

    @Bean(initMethod = "init")
    public MyBean myBean() {
        return new MyBean();
    }

}

三、普通bean

public class MyBean {

    public MyBean() {
        System.out.println("构造方法");
    }

    @PostConstruct
    public void postConstruct(){
        System.out.println("PostConstruct");
    }

    public void init() {
        System.out.println("initMethod");
    }

}

那这段代码之后后的结果如下

在这里插入图片描述

Destruction Callbacks(销毁回调)

实现DisposableBean接口可以在上下文容器被销毁时触发bean的销毁方法的回调。

public class MyBean implements DisposableBean {

    public MyBean() {
        System.out.println("构造方法");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("spring推荐的销毁方法");
    }

    //实现接口的销毁方法
    @Override
    public void destroy() throws Exception {
        System.out.println("destroy()");
    }

    //自定义销毁方法
    public void myClose() {
        System.out.println("myClose()");
    }
}

同样的Spring也不推荐这种操作,Spring建议你使用@PreDestroy注解,同样是为了和Spring解藕。

当然你也可以自己定义销毁方法 如

@Configuration
public class MyBeanConfig {

    //自己定义销毁方法
    @Bean(destroyMethod = "myClose")
    public MyBean myBean() {
        return new MyBean();
    }

}

还有一个接口其实也能做自动销毁,就是AutoCloseable。实现它其实有2个前提条件,官网并没有说明,这里讲一下,就是不能实现DisposableBean,以及不能自定义销毁方法也就是@Bean(destroyMethod = “myClose”)

这个在Spirng源码里才有所体现

@Nullable
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
   String destroyMethodName = beanDefinition.getDestroyMethodName();.
       //这里清楚说明在自定义销毁方法没有设置
   if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
         (destroyMethodName == null && bean instanceof AutoCloseable)) {
      // Only perform destroy method inference or Closeable detection
      // in case of the bean not explicitly implementing DisposableBean
       // 并且DisposableBean接口没有实现,才会执行close方法,或者shutdown方法
      if (!(bean instanceof DisposableBean)) {
         try {
            return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
         }
         catch (NoSuchMethodException ex) {
            try {
               return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
            }
            catch (NoSuchMethodException ex2) {
               // no candidate destroy method found
            }
         }
      }
      return null;
   }
   return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}

当然你所有方法都不实现,只定义close方法,或者只定义shutdown方法也行,优先执行close。这个在上面代码中也有所体现。

Default Initialization and Destroy Methods(默认初始化和销毁方法)

每个bean都定义生命周期的初始化和销毁太麻烦了,Spring在 设置好默认的方法,这样所有bean都可以用了,比较方便。

在这里插入图片描述

并且,如果子类重新覆盖则以子类为准

Combining Lifecycle Mechanisms(结合生命周期机制)

如果你配置了多个生命周期定义在同一个方法上,那这个方法只会执行一次,例如

@Configuration
public class MyBeanConfig {

    @Bean(initMethod = "init")
    public MyBean myBean() {
        return new MyBean();
    }

}
public class MyBean {

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

    public MyBean() {
        System.out.println("构造方法");
    }
    
}

自定义初始化方法和PostConstruct注解都指向同一个方法时,只会调用一次Bean生命周期

public class MyBean {

    @PostConstruct
    public void myInit() {
        System.out.println("myInit()");
    }

    public void init() {
        System.out.println("init()");
    }

    public MyBean() {
        System.out.println("构造方法");
    }

}

分开后就可以分别执行。同样的道理也能放在@PreDestroy 和 自定义的销毁方法上

他们的执行顺序

public class MyBean implements InitializingBean , DisposableBean {

    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct spring推荐的初始化方法");
    }

    public MyBean() {
        System.out.println("构造方法");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("@PreDestroy spring推荐的销毁方法");
    }

    //自定义销毁方法
    public void myClose() {
        System.out.println("myClose() 自定义销毁方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("实现InitializingBean接口的afterPropertiesSet()");
    }

    private void myInit() {
        System.out.println("myInit() 自定义初始化方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("实现DisposableBean接口的destroy()");
    }
}
@Configuration
public class MyBeanConfig {

    @Bean(initMethod = "myInit",destroyMethod = "myClose")
    public MyBean myBean() {
        return new MyBean();
    }

}
public class SpringBeanApp {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
        MyBean bean = context.getBean(MyBean.class);
        context.close();
    }

}

初始化方法顺序

  1. @PostConstruct
  2. 实现 InitializingBean 接口
  3. 自定义初始化方法

销毁方法顺序

  1. @PreDestroy
  2. 实现 DisposableBean 接口
  3. 自定义销毁方法

在这里插入图片描述

Startup and Shutdown Callbacks (启动和停止的回调)

Lifecycle

有一个接口org.springframework.context.Lifecycle ,我们用bean去实现该接口,会有3个方法

public class MyBean implements Lifecycle {

    private boolean running = false;


    @Override
    public void start() {
        running = true;
        System.out.println("start()");
    }

    @Override
    public void stop() {
        running = false;
        System.out.println("stop()");
    }

    @Override
    public boolean isRunning() {
        System.out.println("isRunning()==" + running);
        return running;
    }

}

在我们调用上下文的start和stop方法时,会先执行isRunning() 。

如果isRunning() 返回false 则 执行 bean的start()

如果isRunning() 返回true 则 执行 bean的stop()

public class SpringBeanApp {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
        context.start();
        context.stop(); 
    }
}

执行结果

在这里插入图片描述

Spring同时也提醒你这个接口的开始方法和关闭方法跟Spring上下文的刷新和销毁并无直接关联,需要上下文手动调用start() 和 stop(),并要配合isRunning的结果才能执行。

LifecycleProcessor

它是Lifecycle的子类实现,多了2个方法,而且这个使用方法比较特别,需要将bean的name定义成lifecycleProcessor,如下图

@Configuration
public class MyBeanConfig {

    @Bean
    public MyBean lifecycleProcessor() {
        return new MyBean();
    }

}
public class MyBean implements LifecycleProcessor {

    private boolean running = false;


    @Override
    public void start() {
        running = true;
        System.out.println("start()");
    }

    @Override
    public void stop() {
        running = false;
        System.out.println("stop()");
    }

    @Override
    public boolean isRunning() {
        System.out.println("isRunning()==" + running);
        return running;
    }

    @Override
    public void onRefresh() {
        System.out.println("onRefresh");
    }

    @Override
    public void onClose() {
        System.out.println("onClose");
    }
}
public class SpringBeanApp {

    public static void main(String[] args) {
        AnnotationConfigApplicationContet context = new AnnotationConfigApplicationContet(MyBeanConfig.class);
		context.start();
        context.stop();
        context.close();
    }

}

运行结果如下

在这里插入图片描述

这会儿就不跟isRunning的结果有关系了,或者说根本没有调用isRunning。

SmartLifecycle

同样也是Lifecycle的子类,同样也多了2个方法,只不过有默认的实现。

public class MyBean implements SmartLifecycle {

    private boolean running = false;


    @Override
    public void start() {
        running = true;
        System.out.println("MyBean start()");
    }

    @Override
    public void stop() {
        running = false;
        System.out.println("MyBean stop()");
    }

    @Override
    public boolean isRunning() {
        System.out.println("MyBean isRunning()==" + running);
        return running;
    }

    // 如果返回true则不需要调用上下文的start()同样也可以开启bean的start()
    @Override
    public boolean isAutoStartup() {
        return true;
    }

    // 返回值越小最越早启动,越晚销毁,反之则越晚启动,越早销毁
    @Override
    public int getPhase() {
        return 0;
    }
}
public class MyBean2 implements SmartLifecycle {

    private boolean running = false;


    @Override
    public void start() {
        running = true;
        System.out.println("MyBean2 start()");
    }

    @Override
    public void stop() {
        running = false;
        System.out.println("MyBean2 stop()");
    }

    @Override
    public boolean isRunning() {
        System.out.println("MyBean2 isRunning()==" + running);
        return running;
    }

    // 如果返回true则不需要调用上下文的start()同样也可以开启bean的start()
    @Override
    public boolean isAutoStartup() {
        return true;
    }

    // 返回值越小最越早启动,越晚销毁,反之则越晚启动,越早销毁
    @Override
    public int getPhase() {
        return 1;
    }
}
@Configuration
public class MyBeanConfig {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

    @Bean
    public MyBean2 myBean2() {
        return new MyBean2();
    }

}
public class SpringBeanApp {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
        context.close();
    }

}

执行结果如下

在这里插入图片描述

Shutting Down the Spring IoC Container Gracefully in Non-Web Applications (非web环境如何优雅的关闭IOC容器)

public class MyBean  {

    public void close() {
        System.out.println("没有调用上下文的close,但由于注册的关闭的勾子,当应用关闭时会自动调用");
    }

}
@Configuration
public class MyBeanConfig {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

}
public class SpringBeanApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
        context.registerShutdownHook();
    }
}

被遗忘的接口

以上就是所有Spring官网对于Bean的生命周期描述。但是这好像和我们之前背的生命周期有很大出入。如 BeanNameAware 接口、 BeanFactoryAware 接口 、ApplicationContextAware 接口,还有 BeanPostProcessor 接口 。首先这些接口其实并不在官网的生命周期回调接口篇章,只不过它们确实能在生命周期过程中影响Bean。

这些Aware接口就不用一个个探究了,因为太多了,大致都是实现接口后IOC会调用其set方法将我们需要的属性或bean进行注入。

这里我唯一想说的是这个BeanPostProcessor,基本上IOC的bean管理都依赖其子类的实现,离开它基本上IOC就玩不转了。

public class MyBean implements InitializingBean {

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

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

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

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

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
        context.register(MyBeanConfig.class);
        context.refresh();
    }

}

执行结果如下

在这里插入图片描述

BeanPostProcessor会得到IOC容器里的所有Bean,并且你可以修改Bean,我们的Aware接口都是通过这个实现的。并且他的执行时机是在 执行 bean的afterPropertiesSet()方法前后。

至此,所有的方法都跟大家过了一遍。我们在日后的面试过程中,描述思路应该以Spirng官网的描述为准,说清楚有哪些生命周期,并且说清楚Aware接口和BeanPostProcessor并不应该属于生命周期包含的接口,但其作用和执行步骤在那一段可以描述清楚。

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值