面试题:在bean加载/销毁前后,如果想实现某些逻辑,怎么做?

文摘   2024-11-29 11:02   陕西  

今天咱们来聊聊在Spring框架中,如何在Bean的加载和销毁前后执行一些特定逻辑。这是个很实用的话题,因为无论是资源的初始化,还是清理,都直接关系到系统的性能和稳定性。

Spring提供了多种方式来让开发者自定义逻辑,可以说是非常灵活。接下来,我从常见的几种方法入手,带大家撸清楚这些用法。

首先,如果你还在用XML配置,那init-methoddestroy-method是个不错的选择。比如,我们有一个MyBeanClass需要在初始化和销毁时做点事情,可以这么写:

<bean id="myBean" class="com.example.MyBeanClass"  
      init-method="init" destroy-method="destroy"/>

对应的Java代码是这样的:

public class MyBeanClass {  
    public void init() {  
        System.out.println("Bean初始化中...");
        // 初始化逻辑
    }  
    public void destroy() {  
        System.out.println("Bean销毁中...");
        // 清理逻辑
    }  
}

这个方式简单明了,但是需要通过XML配置,显得有点老派了。如果你是个喜欢动手撸代码的开发者,那Spring的接口可能更对你的胃口。

我们可以让MyBeanClass实现InitializingBeanDisposableBean接口,分别实现afterPropertiesSetdestroy方法。这两个接口由Spring提供,专门用来处理初始化和销毁逻辑:

import org.springframework.beans.factory.DisposableBean;  
import org.springframework.beans.factory.InitializingBean;  
  
public class MyBeanClass implements InitializingBeanDisposableBean {  
    @Override  
    public void afterPropertiesSet() throws Exception {  
        System.out.println("InitializingBean接口: 初始化逻辑");
    }  
  
    @Override  
    public void destroy() throws Exception {  
        System.out.println("DisposableBean接口: 清理逻辑");
    }  
}

这种方法虽然直观,但问题也很明显:你的Bean类和Spring接口强绑定了。如果某一天你想切换到其他框架,可能得重写这些代码。

为了追求更好的解耦,Spring提供了基于注解的方式。用@PostConstruct@PreDestroy注解标注方法,简直不能更香了。比如:

import javax.annotation.PostConstruct;  
import javax.annotation.PreDestroy;  
  
public class MyBeanClass {  
    @PostConstruct  
    public void init() {  
        System.out.println("@PostConstruct: 初始化逻辑");
    }  
  
    @PreDestroy  
    public void destroy() {  
        System.out.println("@PreDestroy: 清理逻辑");
    }  
}

这个写法不仅优雅,而且和具体的框架解耦。如果你用了Spring Boot,这种方式无缝衔接。

对于偏爱Java配置的开发者,还有另一种选择:在@Bean注解里直接指定initMethoddestroyMethod。来看个例子:

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
  
@Configuration  
public class AppConfig {  
    @Bean(initMethod = "init", destroyMethod = "destroy")  
    public MyBeanClass myBean() {  
        return new MyBeanClass();  
    }  
}

和XML配置类似,但这种方式更现代化,也更适合纯Java开发。

最后,稍微深入点,Spring还提供了一个叫BeanPostProcessor的接口。这个接口可以拦截所有Bean的初始化过程,算是个更高级的工具。比如:

import org.springframework.beans.factory.config.BeanPostProcessor;  
import org.springframework.stereotype.Component;  
  
@Component  
public class MyBeanPostProcessor implements BeanPostProcessor {  
    @Override  
    public Object postProcessBeforeInitialization(Object bean, String beanName) {  
        System.out.println("初始化之前: " + beanName);
        return bean;  
    }  
  
    @Override  
    public Object postProcessAfterInitialization(Object bean, String beanName) {  
        System.out.println("初始化之后: " + beanName);
        return bean;  
    }  
}

这个场景比较适合需要全局处理逻辑的情况,比如给所有Bean打日志、性能监控之类的。需要注意的是,这不是为单个Bean定制逻辑,而是对所有Bean生效。

说到这里,总结一下:从简单的XML配置,到优雅的注解,再到更高级的接口,每种方式都有自己的适用场景。如果你问我哪个最实用,我觉得@PostConstruct@PreDestroy是日常开发中的最佳选择,理由很简单:写法简单,耦合度低。

面试官也经常会问这个问题:“Spring中如何在Bean加载和销毁时执行自定义逻辑?”回答如下:

Spring提供了多种方式来实现:

  • 使用XML中的init-methoddestroy-method配置。
  • 实现InitializingBeanDisposableBean接口。
  • 使用@PostConstruct@PreDestroy注解(推荐)。
  • 在Java配置中通过@Bean指定initMethoddestroyMethod
  • 实现BeanPostProcessor接口进行更高级的全局处理


-END-


ok,今天先说到这,老规矩,给大家分享一份不错的副业资料,感兴趣的同学找我领取。

以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言

程序员老鬼
10年+老程序员,专注于AI知识普及,已打造多门AI课程,本号主要分享国内AI工具、AI绘画提示词、Chat教程、AI换脸、Chat中文指令、Sora教程等,帮助读者解决AI工具使用疑难问题。
 最新文章