谈谈 Spring 中 Bean 的生命周期?

简介: 谈谈 Spring 中 Bean 的生命周期?

1Bean的生命周期

1.1、概括


Spring中Bean的生命周期就是Bean在Spring中从创建到销毁的整个过程,主要分为以下5个部分:


1.实例化: 给Bean分配内存空间(对应JVM中的“加载”,这里只是分配了内存);


2.设置属性: 进行Bean的注入和装配;


3.初始化:


执行各种通知;


执行初始化的前置工作;


进行初始化工作(使用注解 @PostConstruct 初始化 或者 使用(xml) init-method 初始化, 前者技术比后者技术先进~);


执行初始化的后置工作;


4.使用Bean


5.销毁Bean


值得注意的是:实例化和初始化是两个完全不同的过程,前者只是给Bean分配内存空间,而后者则是将程序执行权从系统级别转到用户级别,执行用户添加的业务代码。

1.2、图解

下图以买房、盖房、入住、卖房为栗子,方便理解~

图片

2代码示例

2.1、初始化代码

以下,我将在Spring中,演示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 {
 
    //执行各种通知
    @Override
    public void setBeanName(String s) {
        System.out.println("执行了通知");
    }
 
    //初始化的前置和后置方法不能写在这个Bean中!
 
    //执行初始化方法(注解)
    @PostConstruct
    public void postConstruct() {
        System.out.println("通过注解 @PostConstruct 执行了初始化方法");
    }
 
    //使用
    public void useBean() {
        System.out.println("使用Bean");
    }
 
    //销毁
    @PreDestroy
    public void preDestory() {
        System.out.println("执行了销毁方法");
    }
 
}


注意:


1.这里不能写出实例化过程,因为给Bean分配内存对应JVM类加载过程;


2.当前这个Bean中不能写初始化的前置方法和后置方法,否则不会执行,因为初始化的前置方法和后置方法是需要继承 BeanPostProcessor 接口,重写两个方法实现的, 并且是为所有 Bean 服务的,而非为某一个 Bean 服务的,若写在一个某一个Bean中,则不会执行。

2.2、初始化的前置方法和后置方法(重写)

另外再创建一个类(避免在一个Bean中),自定义名为 MyBeanPostProcessor ,接着继承 BeanPostProcessor 接口,重写初始化的前置方法和后置方法,如下代码:

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 {
        System.out.println("执行了初始化的前置方法");
        return bean;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("执行了初始化的后置方法");
        return bean;
    }
}


2.3、Spring启动类

最后在Spring启动类中获取Bean对象,如下代码:

import com.demo3.component.BeanLifeComponent;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
 
        //获取Bean
        BeanLifeComponent beanLifeComponent =
                context.getBean("beanLifeComponent", BeanLifeComponent.class);
        //使用Bean
        beanLifeComponent.useBean();
        //销毁Bean
        context.destroy();
    }
}


为什么这里不使用 ApplicationContext 而是使用它的子类 ClassPathXmlApplicationContext 呢?因为 ClassPathXmlApplicationContext 中有destroy销毁方法(用来销毁容器,容器销毁了,Bean自然就没了),而 ApplicationContext 中没有这个销毁方法,演示的时候,就体现不出来了。

2.4、执行结果

图片

从执行结果来看,符合咱们预期~


2.5、经典面试问题

那么是否可以先执行 初始化 再执行 设置属性 呢?不可以!想象一下,如果在初始化的方法中要用你设置的属性,就会引发空指针异常,如下代码:

@Controller
public class StudentController {
 
    //属性注入
    @Autowired
    private Student student;
 
    //初始化
    @PostConstruct
    public void init() {
        student.setName("周杰伦");
    }
 
}


如果你先执行了初始化 init() 方法,而 init() 方法中需要使用属性注入后得到的Student对象,那么此时还没有注入就进行修改,就会引发空指针异常。

3总结


Spring中Bean的生命周期就是Bean在Spring中从创建到销毁的整个过程。


主要就是由:


实例化


设置属性:进行Bean的注入和装配


初始化


使用Bean


销毁Bean


这五步构成,并且任何顺序都不可以随意调换。


Bean的执行流程属于常见面试题,一定要在理解的基础上牢记!

相关文章
|
1月前
|
XML 安全 Java
|
8天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
8天前
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
|
14天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
51 6
|
15天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
79 3
|
2月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
29天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
34 1
|
3月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
85 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
4月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
346 24
|
4月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
276 18