作为一个 Java 程序员 Spring 框架在我们日常工作和面试中可谓必不可少,学习和掌握好 Spring 对我们来说是很有必要的。
今天了不起就给大家介绍一下 Spring 的 Bean 的初始化和销毁的几种方式,看看你平时用的都是哪种。
初始化
由于 Spring Bean 的初始化都是 Spring 容器帮我们处理的,我们这里说的初始化是指在容器帮我们初始化的过程,我们有哪些方式可以进行手动干预,或者说初始化的时候如何运行我们自己的逻辑。
废话不多说,我们依次来看下面的几种方式
实现 InitializingBean 接口
我们可以写一个类,然后实现 InitializingBean 接口,通过覆盖其中的 afterPropertiesSet() 方法来实现我们自己的逻辑,我们写一个 case 来实现一下,如下所示
package com.example.demo.service;
import org.springframework.beans.factory.InitializingBean;
public class InitServiceImpl implements InitializingBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet...");
this.name = "Java极客技术 afterPropertiesSet";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
实现的方式很简单,直接实现 org.springframework.beans.factory.InitializingBean 这个接口然后覆盖 afterPropertiesSet 这个方法即可,在这个方法里面,我们就可以执行我们需要在初始化时候就执行的代码。
比如这里我们在初始化方法里面直接给一个属性进行赋值,后续就可以直接使用了,如下所示
package com.example.demo.controller;
@RestController
public class HelloController {
@Autowired
InitServiceImpl initService;
@GetMapping(value = "/hello")
public String hello(@RequestParam String name) {
return initService.getName();
}
}
可以看到是可以直接获取到属性值的,这个比较简单我们就不赘述了,继续看下面两个方式。
增加 @PostConstruct 注解
我们继续在 InitServiceImpl 类中增加一个方法,并且在方法上面增加 @PostConstruct 注解,如下所示
@PostConstruct
public void postConstruct() {
System.out.println("postConstruct...");
this.name = "Java极客技术 postConstruct";
}
这种写法比实现一个接口要简单一点,毕竟只要增加一个注解就行了,而不需要覆盖接口的方法,不过本质上没什么区别。
自定义 init 方法
这种方式也很简单,只不过我们做两个动作,第一个是在 InitServiceImpl
public void initMethod() {
System.out.println("initMethod...");
this.name = "Java极客技术 initMethod";
}
然后再写一个配置类,在配置类中定义一个方法,在方法上面增加一个 @Bean 注解,并且赋值一个 init-method 方法,同时这个方法需要创建对象并返回,如下所示
package com.example.demo.service;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean(initMethod = "initMethod")
public InitServiceImpl initServiceImpl() {
return new InitServiceImpl();
}
}
怎么样是不是也很简单。
小结
在这里问大家一个问题,如果我们在同一个类中同时存在这三种初始化方法,那会是什么情况呢?
我们来试一下就知道了,通过完整的代码,我们将三种方式都写进来,然后启动服务。
package com.example.demo.service;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
public class InitServiceImpl implements InitializingBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet...");
this.name = "Java极客技术 afterPropertiesSet";
}
@PostConstruct
public void postConstruct() {
System.out.println("postConstruct...");
this.name = "Java极客技术 postConstruct";
}
public void initMethod() {
System.out.println("initMethod...");
this.name = "Java极客技术 initMethod";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
可以看到,我们的服务是正常的启动和运行,并且三个方法都正常的执行了,执行的顺序依次是 postConstruct,afterPropertiesSet,initMethod,那么这里问一下小伙伴们,此时我们的 name 值是什么呢?
销毁
既然我们初始化有三种形式,可以很自然的想到销毁是不是也有三种形式呢?没错,销毁的三种方法,也是跟上面类似,分别是
- 实现 org.springframework.beans.factory.DisposableBean 接口,覆盖 destroy() 方法;
- 自定义一个方法,在方法上面增加 @PreDestroy 注解;
- 在 InitServiceImpl 中增加一个自定义销毁方法,然后在配置类中增加 Bean 的 destoryMethod;
相关的内容也比较简单,在上面的 InitServiceImpl 和 Config 基础上只要增加一点点内容就好了
public class InitServiceImpl implements InitializingBean, DisposableBean {
public void destroyMethod() throws Exception {
System.out.println("destroyMethod...");
}
@Override
public void destroy() throws Exception {
System.out.println("destroy...");
}
@PreDestroy
public void preDestroy() throws Exception {
System.out.println("preDestroy...");
}
}
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public InitServiceImpl initServiceImpl() {
return new InitServiceImpl();
}
销毁的三个方法在执行的时候也是有优先级的,依次是 preDestroy,destroy,destroyMethod。
至此完整的一个包含三个初始化和三个销毁方法的代码就完成了,我们来运行一下看看整体的流程。
总结
虽然说 Spring 给我们提供了三种初始化和三种销毁的方法,不过我们在日常的写代码中很少会把三种都写上,但是对于这几种的优先级还是有必要了解的,万一别人给你挖坑了怎么办呢?
好了,今天了不起给大家介绍了一下 Spring 的三种初始化和三种销毁对象的方式,并且通过示例案例给大家介绍了一下优先级,希望对大家有帮助。