文章目录
  1. 1. Bean初始化
    1. 1.1. 通过@PostConstruct注解对Bean进行初始化
    2. 1.2. 通过实现InitializingBean接口对Bean进行初始化
    3. 1.3. 通过自定义初始化方法进行初始化
    4. 1.4. 测试三种初始化方式的优先级
  2. 2. Bean销毁
    1. 2.1. 通过@PreDestroy注解销毁Bean
    2. 2.2. 实现接口DisposableBean接口
    3. 2.3. 自定义销毁方式
    4. 2.4. 测试三种销毁方式的优先级
  3. 3. 小结

Spring框架以Bean为核心,为开发者提供了一系列的特性和能力。其中最为核心的就是IOC特性,而IOC中又以Bean定义及其初始化/销毁为核心。

本文我们对Bean的初始化和销毁进行较为深入的整理与学习。

Bean初始化

一般而言,Bean初始化有三种方式:

  • 通过@PostConstruct注解对Bean进行初始化
  • 通过实现InitializingBean接口的afterPropertiesSet()方式对Bean进行初始化
  • 通过自定义初始化方法实现
    • 通过XML配置中的 指定
    • 通过@Bean属性initMethod=”自定义初始化方法名” 指定
    • 通过编程方式实现:使用AbstractBeanDefination#setInitMethodName(String) 实现,方法参数为自定义的初始化方法名

这三种方式还存在优先级,从高到低依次是:

@PostConstruct注解 > InitializingBean接口 > 自定义初始化方法

接下来我们就详细进行说明。

通过@PostConstruct注解对Bean进行初始化

在一个Spring环境下,定义一个Bean名为BeanInitDemo,为其添加@PostConstruct标注的初始化方法,注意 该初始化方法不能有返回值(即:需要放回void)

public class BeanInitDemo {

    private String name;

    public BeanInitDemo(String name) {
        this.name = name;
    }

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

}

init()方法此时就是一个初始化方法

通过实现InitializingBean接口对Bean进行初始化

还是上面的BeanInitDemo类,我们让其实现接口InitializingBean,并实现afterPropertiesSet回调方法

public class BeanInitDemo implements InitializingBean {

    private String name;

    public BeanInitDemo(String name) {
        this.name = name;
    }

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

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean方式初始化");
    }
}

我们可以在afterPropertiesSet()方法中实现bean初始化逻辑。

通过自定义初始化方法进行初始化

通过bean定义时显式指定初始化方法,实现自定义初始化。

我们在上面的BeanInitDemo类上添加自定义方法:initMethod(),BeanInitDemo类现在如下所示

public class BeanInitDemo implements InitializingBean {

    private String name;

    public BeanInitDemo(String name) {
        this.name = name;
    }

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

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean方式初始化");
    }

    public void initMethod() {
        System.out.println("自定义init方式");
    }
}

测试三种初始化方式的优先级

想要实现对三种方式优先级的测试还需要对bean进行装配,这里使用javaConfig方式对BeanInitDemo进行装配。

编写一个配置类BeanInitConfig,对BeanInitDemo这个bean进行装配:

@Configuration
public class BeanInitConfig {

    @Bean(initMethod = "initMethod")
    public BeanInitDemo beanInitDemo() {
        return new BeanInitDemo("BeanInitDemo");
    }
}

通过@Configuration标记BeanInitConfig为配置bean,通过@Bean声明一个BeanInitDemo类型的bean,beanName就是方法名。通过属性initMethod指定初始化方法为initMethod()

声明一个main方法对bean初始化方式优先级进行测试:

public class Client {

    public static void main(String[] args) {
        // 注解驱动应用上下文
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册Configuration
        applicationContext.register(BeanInitConfig.class);
        // 启动应用上下文
        applicationContext.refresh();
        // 关闭应用上下文
        applicationContext.close();
    }
}

具体过程在注解中已经表明,这里主要关注一下refresh()方法,它的实现在 org.springframework.context.support.AbstractApplicationContext 类中,通过模板模式对bean进行了加载,感兴趣可以自行查看。

通过 applicationContext.register(BeanInitConfig.class);对配置bean进行加载,接着启动了应用上下文,运行该main方法,查看控制台:

@PostConstruct方式初始化
InitializingBean方式初始化
自定义init方式

从输出我们能够明确看出,三种初始化方式的优先级为:

@PostConstruct注解 > InitializingBean接口 > 自定义初始化方法

Bean销毁

我们接着学习Bean的销毁方式。

与Bean初始化类似,Bean的销毁也有三种方式:

  • 通过@PreDestroy注解标记方法
  • 实现接口DisposableBean的destroy()方法
  • 自定义销毁方式:
    • 通过XML方式:
    • 通过Java注解:@Bean(destroy=”自定义的destroy方式名”)
    • 通过编程方式实现:使用AbstractBeanDefination#setDestroyMethodNames(String) 实现,方法参数为自定义的初始化方法名

上述三种方式的优先级:

@PreDestroy注解 > DisposableBean接口 > 自定义销毁方式

我们编写代码验证一下这三种方式:

通过@PreDestroy注解销毁Bean

在上文中的BeanInitDemo类中,添加方法preDestory()并添加注解@PreDestroy

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

此时preDestory()就是一个销毁方法

实现接口DisposableBean接口

我们让BeanInitDemo实现接口DisposableBean,并实现回调方法destroy()

public class BeanInitDemo implements InitializingBean, DisposableBean {

    private String name;

    public BeanInitDemo(String name) {
        this.name = name;
    }

    ......

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

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean方式销毁");
    }

}

BeanInitDemo此时就是一个DisposableBean实例,它会在Context关闭时回调destroy()从而实现对资源的回收操作。

自定义销毁方式

通过bean定义时显式指定销毁方法,实现自定义销毁。

我们在上面的BeanInitDemo类上添加自定义方法:destroyMethod(),BeanInitDemo类现在如下所示

public class BeanInitDemo implements InitializingBean, DisposableBean {

    private String name;

    public BeanInitDemo(String name) {
        this.name = name;
    }

    ......

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

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean方式销毁");
    }

    public void destroyMethod() {
        System.out.println("自定义destroy方式");
    }
}

修改配置类BeanInitConfig,在BeanInitDemo装载方法上,添加属性destroyMethod

@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public BeanInitDemo beanInitDemo() {
    return new BeanInitDemo("BeanInitDemo");
}

通过destroyMethod显式地指定自定义bean销毁方法:destroyMethod,注意没有括号。

测试三种销毁方式的优先级

运行测试类,观察控制台输出:

@PreDestroy方式销毁
DisposableBean方式销毁
自定义destroy方式

可以看到三种销毁方式的优先级确实满足如下顺序:

@PreDestroy注解 > DisposableBean接口 > 自定义销毁方式

小结

到此,我们对Spring框架中涉及到Bean的初始化及销毁的主要方式进行了学习总结,并对每种方式的优先级进行了测试。

在后续的开发中,如果涉及到对Bean进行初始化或者容器销毁时需要对Bean进行一些收尾工作,就可以使用本文中提到的方式进行操作。

在下文中,我们将对这些方式具体的源码实现进行探究。最后祝各位读者,鼠年大吉,工作顺利。



版权声明:

原创不易,洗文可耻。除非注明,本博文章均为原创,转载请以链接形式标明本文地址。

文章目录
  1. 1. Bean初始化
    1. 1.1. 通过@PostConstruct注解对Bean进行初始化
    2. 1.2. 通过实现InitializingBean接口对Bean进行初始化
    3. 1.3. 通过自定义初始化方法进行初始化
    4. 1.4. 测试三种初始化方式的优先级
  2. 2. Bean销毁
    1. 2.1. 通过@PreDestroy注解销毁Bean
    2. 2.2. 实现接口DisposableBean接口
    3. 2.3. 自定义销毁方式
    4. 2.4. 测试三种销毁方式的优先级
  3. 3. 小结
Fork me on GitHub