Java 中的公共类称之为 Bean 或 Java Bean,而 Spring 中的 Bean 指的是将对象的生命周期,交个 Spring IoC 容器来治理的对象。所以 Spring 中的 Bean 对象在应用时,无需通过 new 来创建对象,只须要通过 DI(依赖注入),从 Spring 中取出要应用的对象即可。
那么 Spring 中,Bean 的生命周期又有哪些呢?接下来,咱们一起来看。
1.Bean 生命周期
Spring 中 Bean 的生命周期是指:Bean 在 Spring(IoC)中从创立到销毁的整个过程。
Spring 中 Bean 的生命周期次要蕴含以下 5 局部:
- 实例化:为 Bean 分配内存空间;
- 设置属性:将以后类依赖的 Bean 属性,进行注入和拆卸;
-
初始化:
- 执行各种告诉;
- 执行初始化的前置办法;
- 执行初始化办法;
- 执行初始化的后置办法。
- 应用 Bean:在程序中应用 Bean 对象;
- 销毁 Bean:将 Bean 对象进行销毁操作。
以上生命周期中,须要留神的是:“实例化”和“初始化”是两个齐全不同的过程,千万不要搞混,实例化只是给 Bean 调配了内存空间,而初始化则是将程序的执行权,从零碎级别转换到用户级别,并开始执行用户增加的业务代码 。
2. 代码演示
接下来咱们应用代码的形式在 Spring Boot 中,给大家演示一下 Bean 的生命周期。
PS:因为 Spring Boot 是基于 Spring 创立的,所以 Bean 在 Spring 或 Spring Boot 中的行为都是统一的,而 Spring Boot 又是目前支流的框架,所以本文应用 Spring Boot 来演示 Bean 的生命周期。
首先,咱们创立一个 Bean 对象,起名为 BeanLifeComponent(类命无所谓,可随便指定),它的具体实现代码如下:
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class BeanLifeComponent implements BeanNameAware {public void setBeanName(String s) {System.out.println("执行 BeanName 的告诉办法");
}
@PostConstruct
public void postConstruct() {System.out.println("执行初始化办法");
}
public void use() {System.out.println("应用 Bean");
}
@PreDestroy
public void preDestroy() {System.out.println("执行销毁办法");
}
}
而后,咱们再创立一个 MyBeanPostProcessor 类(类命无所谓,可随便指定),来实现初始化的前置办法和初始化的后置办法,具体实现代码如下:
import org.springframework.beans.BeansException;
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) throws BeansException {if (beanName.equals("beanLifeComponent")) {System.out.println("执行初始化前置办法");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("beanLifeComponent")) {System.out.println("执行初始化后置办法");
}
return bean;
}
}
为什么要创立一个独自的类来执行初始化的前置办法和初始化的后置办法呢?
这是因为初始化的前置办法和后置办法是为所有 Bean 服务的,而非为某一个 Bean 服务的,所以这两个办法不能写在某个具体的 Bean 中,否则(这两个办法)不会执行。
最初,在 Spring Boot 的启动类中获取 Bean,具体实现代码如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {
// 失去上下文对象,并启动 Spring Boot 我的项目
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
// 获取 Bean
BeanLifeComponent component = context.getBean(BeanLifeComponent.class);
// 应用 Bean
component.use();
// 进行 Spring Boot 我的项目
context.close();}
}
以上程序最终的执行后果如下图所示:
从下面的执行后果能够看出,代码执行程序合乎 Bean 生命周期的执行程序:
- 实例化:为 Bean 分配内存空间;
- 设置属性:将以后类依赖的 Bean 属性,进行注入和拆卸;
-
初始化:
- 执行各种告诉;
- 执行初始化的前置办法;
- 执行初始化办法;
- 执行初始化的后置办法。
- 应用 Bean:在程序中应用 Bean 对象;
- 销毁 Bean:将 Bean 对象进行销毁操作。
那么问题来了,能不能先执行初始化再执行设置属性呢?也就是将生命周期中的步骤 2 和步骤 3 的执行程序替换一下?
答案是否定的。设想一个场景,如果在初始化办法中要用到被注入对象的某个办法,比方以下代码:
@Controller
public class UserController {
@Resource
private UserService userService;
@PostConstruct // 初始化办法
public void postConstruct() {userService.sayHi();
}
}
此时如果先执行步骤 2,先将 UserService 注入到以后类,再调用步骤 3 执行初始化,那么程序的执行是失常的。然而如果将交互步骤 2 和步骤 3 的执行程序,那么程序执行就会报错(空指针异样),所以 Bean 的生命周期的程序必须是:
1. 实例化:为 Bean 分配内存空间;
2. 设置属性:将以后类依赖的 Bean 属性,进行注入和拆卸;
3. 初始化:
- 执行各种告诉;
- 执行初始化的前置办法;
- 执行初始化办法;
- 执行初始化的后置办法。
4. 应用 Bean:在程序中应用 Bean 对象;
5. 销毁 Bean:将 Bean 对象进行销毁操作。
总结
Bean 的生命周期指的是 Bean 在 Spring(IoC)中从创立到销毁的整个过程。Bean 的生命周期次要蕴含以下 5 个流程:
1. 实例化:为 Bean 分配内存空间;
2. 设置属性:将以后类依赖的 Bean 属性,进行注入和拆卸;
3. 初始化:
- 执行各种告诉;
- 执行初始化的前置办法;
- 执行初始化办法;
- 执行初始化的后置办法。
4. 应用 Bean:在程序中应用 Bean 对象;
5. 销毁 Bean:将 Bean 对象进行销毁操作。
是非审之于己,毁誉听之于人,得失安之于数。
公众号:Java 面试真题解析
面试合集:https://gitee.com/mydb/interview