Spring(11) Bean的生命周期

这篇具有很好参考价值的文章主要介绍了Spring(11) Bean的生命周期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

首先,为什么要学习 Spring 中 Bean 的生命周期呢?

虽然不了解 Bean 的生命周期,并不影响日常工作中的开发。但是如果我们了解了 Bean 的生命周期,可以帮助我们更好地掌握 Spring 框架,并且能够让我们更好地去理解 Spring 容器是如何管理和创建 Bean 示例的。如果以后遇到 Bean 的相关问题(比如 Spring 的循环依赖问题),就可以方便我们去调试和解决这些问题。同时也让我们可以编写出更健壮、灵活、易维护的应用程序。所以说,理解 Bean 的生命周期对掌握 Spring 框架来说是至关重要的。

这里我们主要分两部分去说明:

  1. 先从整体上去介绍 Bean 创建的整个流程 -> Bean的流程;
  2. 然后再用代码的方式去验证流程 -> 代码验证。

二、Bean的流程

1.BeanDefinition

BeanDefinition:Bean 的定义信息。Spring 容器在进行实例化时,会将 xml 配置中 <bean> 的信息(注解也是如此)封装成一个 BeanDefinition 对象,Spring 根据 BeanDefinition 来创建 Bean 对象,里面有很多用来描述 Bean 的属性。

有了 BeanDefinition 之后,再去创建 Bean 对象的时候,就可以通过反射去创建。

<bean id="userDao" class="com.demo.dao.impl.UserDaoImpl" lazy-init="true"/>
<bean id="userService" class="com.demo.service.UserServiceImpl" scope="singleton">
	<property name="userDao" ref="userDao"></property>
</bean>
Spring(11) Bean的生命周期,Spring,spring,java,后端
  • beanClassName:bean 的类名。
  • initMethodName:初始化方法名称。
  • propertyValues:bean 的属性值。
  • scope:作用域。
  • lazyInit:延迟初始化。

以上这些属性都被封装到 BeanDefinition 中备用。那具体什么时候用呢?这就是下面要说的 Bean 的生命周期。

2.Bean 的生命周期

目前我们已经有了 BeanDefinition 这个对象了,那第一步就是要去创建对象。

Spring(11) Bean的生命周期,Spring,spring,java,后端

  • 第1步,调用 Bean 的构造函数。 来去实例化当前 Bean 的对象。

  • 第2步,依赖注入。 像是一些 @Autowired 或者 @Value 标明的属性,这些都是在依赖注入中完成。

  • 第3步,Aware接口。 比较常见的有三个,它们都是以 Aware 结尾的接口,如果 Bean 实现了这些接口,就要重写里面的方法:

    BeanNameAware:在初始化过程中可以获取到 Bean 的名称。

    BeanFactoryAware:在初始化过程中可以获取到 Bean 工厂。

    ApplicationContextAware:在初始化过程中可以获取到应用上下文。

    以上这些内容都是为了方便对 Bean 进行扩展。

  • 第4步,BeanPostProcessor#before。 BeanPostProcessor 是 Bean 的后置处理器,用来增强 Bean 的功能的,在初始化方法调用之前(before)进行回调。这个 BeanPostProcessor 后置处理器在 Bean 的生命中其中占有非常重要的作用,需要重点记忆。

  • 第5步,调用初始化方法。 里面有两部分:

    InitializingBean:这是一个接口类,如果当前 Bean 实现了这个接口的话,就要重写里面的方法,这一步就是来执行重写之后的方法。

    自定义init方法:比如在 Bean 中的某一个方法使用了注解 @PostConstruct,这里就会去执行标明了注解的方法。其实自定义init方法也是从 BeanDefinition 中读取到的信息。

  • 第6步,BeanPostProcessor#after。 还是在 Bean 的后置处理器中执行,但是是在初始化方法之后(after)执行。在 Spring 中对 Bean 进行增强的话,都是用到这个初始化方法之后执行的后置处理器。其实在 Spring 内部就使用到了很多的后置处理器,比较典型的就是:当一个类被曾倩了,使用到了 AOP,那这个类通常都是使用后置处理器(BeanPostProcessor#after)来增强的。我们知道 AOP 的底层使用的是动态代理,有两种:JDK动态代理CGLIB动态代理

    到这一步之后,基本上这个对象就创建完成了,现在就可以从 Spring 容器中去获取和使用这个 Bean 对象了。

    注意:依赖注入 开始到 BeanPostProcessor#after 完成之后,都是针对当前的 Bean 进行初始化赋值,当然也做了一些增强。这里需要注意,Spring 中 Bean 的创建是一步一步完成的,也就是说 Bean 的创建和初始化赋值是分开的。调用构造函数就是创建 Bean 对象,但是这里创建好后是一个空对象,里面没有值,下面就是初始化赋值的过程。

  • 第6步,销毁Bean。 当 Spring 容器关闭之后,这个 Bean 对象就要执行销毁的操作了。比较典型的是,如果在某个方法上使用了 @PreDestroy 这个注解,那这个方法就是一个销毁的方法,Spring 容器关闭的时候就会执行这个销毁的方法。

以上就是 Bean 的生命周期,里面的步骤还是挺多的。为了方便加深印象,我们可以用代码的方式去验证一下。

三、代码验证

1.User 实体类

User.java

继承了 BeanNameAwareBeanFactoryAwareApplicationContextAwareInitializingBean 接口。

package com.demo.lifecycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Component
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {

    public User() {
        System.out.println("User类的构造方法被调用了...");
    }

    /**
     * 姓名
     */
    private String name;

    @Value("张三")
    public void setName(String name) {
        System.out.println("setName方法被调用了...");
        this.name = name;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("BeanNameAware接口的setBeanName方法被调用了,bean的名字是:" + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware接口的setBeanFactory方法被调用了...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware接口的setApplicationContext方法被调用了...");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("InitializingBean接口的afterPropertiesSet方法被调用了...");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("PreDestroy注解的destroy方法被调用了...");
    }
}

2.MyBeanPostProcessor 后置处理器

MyBeanPostProcessor.java

定义了 #before#after 方法的增强实现。

package com.demo.lifecycle;

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("BeanPostProcessor接口的postProcessBeforeInitialization方法被调用了 -> user对象初始化方法前开始增强....");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (Objects.equals(beanName, "user")) {
            System.out.println("BeanPostProcessor接口的postProcessAfterInitialization方法被调用了 -> user对象初始化方法后开始增强....");
            // cglib代理对象
            /*Enhancer enhancer = new Enhancer();
            // 设置需要增强的类
            enhancer.setSuperclass(bean.getClass());
            // 执行回调方法,增强方法
            enhancer.setCallback(new InvocationHandler() {
                @Override
                public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                    // 执行目标方法
                    return method.invoke(bean, objects);
                }
            });
            // 创建代理对象
            return enhancer.create();*/
        }
        return bean;
    }
}

3.SpringConfig 扫描包配置

SpringConfig.java

配置了扫描包位置,只扫描 User 实体类和 MyBeanPostProcessor 后置处理器。

package com.demo.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.demo.lifecycle")
public class SpringConfig {
}

4.UserTest 测试类

UserTest.java

main 方法执行,使用 SpringConfig 配置创建上下文,并从容器中获取 user 的 Bean 对象。

package com.demo.test;

import com.demo.config.SpringConfig;
import com.demo.lifecycle.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class UserTest {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        User user = ctx.getBean(User.class);
        System.out.println(user);
    }
}

5.测试结果

由于我使用的是 SpringBoot 项目进行的测试,会多打印一些日志,其中不带时间前缀的是我们手动 println 的日志。

Connected to the target VM, address: '127.0.0.1:61642', transport: 'socket'
20:03:56.949 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@9660f4e
20:03:56.985 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
20:03:57.100 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\IdeaProjects\SpringBootExamples\springboot-demo\target\classes\com\demo\lifecycle\MyBeanPostProcessor.class]
20:03:57.105 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\IdeaProjects\SpringBootExamples\springboot-demo\target\classes\com\demo\lifecycle\User.class]
20:03:57.266 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
20:03:57.270 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
20:03:57.272 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
20:03:57.275 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
20:03:57.281 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myBeanPostProcessor'
20:03:57.304 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'springConfig'
BeanPostProcessor接口的postProcessBeforeInitialization方法被调用了 -> user对象初始化方法前开始增强....
20:03:57.305 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
User类的构造方法被调用了...
setName方法被调用了...
BeanNameAware接口的setBeanName方法被调用了,bean的名字是:user
BeanFactoryAware接口的setBeanFactory方法被调用了...
ApplicationContextAware接口的setApplicationContext方法被调用了...
BeanPostProcessor接口的postProcessBeforeInitialization方法被调用了 -> user对象初始化方法前开始增强....
InitializingBean接口的afterPropertiesSet方法被调用了...
BeanPostProcessor接口的postProcessAfterInitialization方法被调用了 -> user对象初始化方法后开始增强....
User类的构造方法被调用了...
com.demo.lifecycle.User@2235eaab
Disconnected from the target VM, address: '127.0.0.1:61642', transport: 'socket'

Process finished with exit code 0

可以看到日志是按照我们梳理的 Bean 的生命周期顺序打印的,验证完毕。

6.模拟AOP增强

MyBeanPostProcessor.javapostProcessAfterInitialization() 方法中注释了 AOP 底层 CGLIB 动态代理的演示代码的,可以在 UserTestmain 方法中获取到 user 的 Bean 对象后,将鼠标放到 user 上看下,打开和关闭 CGLIB 代理的注释生成的 user Bean 会不同:

关闭 CGLIB 代理:

Spring(11) Bean的生命周期,Spring,spring,java,后端

打开 CGLIB 代理:

Spring(11) Bean的生命周期,Spring,spring,java,后端

三、总结

问: Spring 中 Bean 的生命周期是什么样的?

答:

① 通过 BeanDefinition 获取 Bean 的定义信息;
② 调用构造函数实例化 Bean;
③ Bean 的依赖注入;
④ 处理 Aware 接口(BeanNameAware、BeanFactoryAware、ApplicationContextAware);
⑤ Bean 的后置处理器 BeanPostProcessor-前置;
⑥ 初始化方法(InitializingBean、init-method);
⑦ Bean 的后置处理器 BeanPostProcessor-后置;
⑧ 销毁 Bean。

整理完毕,完结撒花~ 🌻





参考地址:

1.框架篇-05-Spring-bean的生命周期,https://www.bilibili.com/video/BV1yT411H7YK/?p=39&spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=cf16f2e5f7c4612add10f9f9268a2c8a文章来源地址https://www.toymoban.com/news/detail-630032.html

到了这里,关于Spring(11) Bean的生命周期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring】Spring的Bean的生命周期

    作者简介:大家好,我是五度鱼,一个普通的Java领域博主,不停输出Java技术博客和干货 。 座右铭:锲而不舍,金石可镂 。 个人主页:五度鱼学Java的主页 在 Java 中, Bean 是一个重要的概念,它代表了应用程序中的一个对象。在开发中,我们经常使用 Bean 来管理对象的生命

    2024年01月16日
    浏览(58)
  • Spring整理-Spring Bean的生命周期

    Spring Bean的生命周期涉及多个阶段,从Bean的定义到其销毁。在这个过程中,Spring容器负责创建、初始化、使用和最终销毁Bean。了解这个生命周期有助于更好地管理Bean的行为和资源使用。 实例化(Instantiation): 容器首先创建Bean的实例。 填充属性(Populate Properties): 容器

    2024年01月21日
    浏览(53)
  • 【Spring】Bean的作用域与生命周期详情:请简述Spring的执行流程并分析Bean的生命周期?

     我们都知道,Spring框架为开发人员提供了很多便捷,这使得开发人员能够更加专注于应用程序的核心业务逻辑,而不需要花费大量时间和精力在技术细节上。作为一个包含众多工具方法的IoC容器,存取JavaBean是其极为重要的一个环节。本文就对Spring中的Bean的作用域和生命周

    2024年02月12日
    浏览(48)
  • Spring Bean的生命周期

    Bean生命周期的整个执行过程描述如下: 1、根据配置情况调用Bean构造方法或工厂方法实例化 Bean。 2、利用依赖注入完成Bean中所有属性值的配置注入。 3、如果Bean 实现了BeanNameAware 接口,则 Spring调用Bean的setBeanName()方法传入当前Bean的id值。 4、如果Bean实现了BeanFactoryAware 接口

    2023年04月22日
    浏览(65)
  • Spring -- Bean的生命周期

    Spring容器在进行实例化时,会将xml配置的bean的信息封装成一个BeanDefinition对象,Spring根据BeanDefinition来创建Bean对象,里面有很多的属性用来描述Bean   BeanDefinition 中几个重要方法如下 beanClassName:bean 的类名 initMethodName:初始化方法名称 properryValues:bean 的属性值 scope:作用域

    2024年02月15日
    浏览(54)
  • Spring Bean的生命周期 -- Spring入门(三)

    为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。 (博客的参考源码以及可以在我主页的资源里找到,如果在学

    2024年02月15日
    浏览(37)
  • 【Spring】Spring之Bean生命周期源码解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何销毁的; spring创建对象的过程,就是IOC(控制反转)的过程; JFR Java Flight Record,java飞行记录,类似于飞机的黑匣子,是JVM内置的基于事件的JDK监控记录框架,主要用于问题定位和持续监控; 入口代码: Spring启动的时

    2024年02月15日
    浏览(46)
  • Spring源码:Bean生命周期(五)

    在上一篇文章中,我们深入探讨了 Spring 框架中 Bean 的实例化过程,该过程包括从 Bean 定义中加载当前类、寻找所有实现了 InstantiationAwareBeanPostProcessor 接口的类并调用实例化前的方法、进行实例化、调用 applyMergedBeanDefinitionPostProcessors 方法等多个步骤,最终生成了一个真正的

    2024年02月04日
    浏览(44)
  • Spring中 Bean的生命周期

    如果把Spring看做一个大型工厂,则Spring容器中的Bean就是该工厂的产品。要想使用这个工厂生产和管理Bean,就需要在配置文件中告诉它需要哪些Bean,以及需要使用何种方式将这些Bean装配到一起。 Bean的本质就是Java中的类,而Spring中的Bean其实就是对实体类的引用,来生产Java类

    2024年01月24日
    浏览(41)
  • Spring源码:Bean生命周期(终章)

    本系列前面讲解了Spring的bean定义、bean实例化、bean初始化等生命周期。这些步骤使我们能够了解bean从创建到准备好使用所经历的过程。但是,除了这些步骤,bean的销毁也是非常重要的一步。在本系列的最后,我们将深入探讨bean的销毁过程,包括在什么情况下会发生销毁、销

    2024年02月06日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包