Spring生命周期(二)

1. Processor和Aware

1.1 Processor

        上一篇介绍的@PostConstruct和@PreDestroy是由Spring框架来读取的,并在Bean生命周期的相应阶段调用注解标记的方法,那么Spring框架具体是如何实现这些调用的呢?想要理解这个问题的答案,需要先了解Spring的Processor。

        在Spring框架中,Processor(处理器)是一种用于定制化和拓展Spring容器的机制。它是Spring框架中重要的一环,用于增强Spring容器的功能和灵活性。Spring框架中有很多内置的Processor,如BeanPostProcessor、BeanFactoryPostProcessor等,开发者也可以通过自定义Processor来实现特定需求。

        BeanFactoryPostProcessor:是一个重要的Processor,它可以在容器实例化Bean之前读取Bean的定义(configuration metadata)并可以对Bean的定义进行一些自定义操作,如修改bean的定义、删除不必要的bean等。

        BeanPostProcessor:是一种比较常用的Processor,它的主要作用是在Bean实例化后、初始化前或初始化后对Bean进行一些操作,如实现特定接口、执行特定操作等。通过实现BeanPostProcessor接口,开发者可以自定义一些逻辑,从而达到增强Bean功能的目的。

1.2 CommonAnnotationBeanPostProcessor

        CommonAnnotationBeanPostProcessor是Spring框架中的一个BeanPostProcessor,其作用是识别和处理通用注解(Common Annotations)。这些通用注解包括@Resource、@PostConstruct、@PreDestroy等。

        CommonAnnotationBeanPostProcessor可以自动扫描Spring容器中所有的Bean,查找是否有使用上述通用注解的Bean,并自动适配和处理这些注解。其功能为:

        1、查找所有使用了通用注解的组件。

        2、根据注解中的信息进行自动注入或执行初始化和销毁方法等操作。

        声明com.obj.spring.MyBeanFactoryPostProcessor,实现BeanFactoryPostProcessor接口:

package com.obj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/*** 自定义的BeanFactoryPostProcessor Bean工厂后期处理器,* 其中使用一个方法 postProcessBeanFactory Bean工厂后置处理* 在加载了Bean定义信息以后,对Bean定义进行后续转换处理。* 原则上不建议自行处理* configurableListableBeanFactory 对象中封装了全部的 Bean定义信息*/
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {/*** postProcess 后置处理 BeanFactory Bean工厂* postProcessBeanFactory 在Spring加载全部Bean定义以后执行* @param configurableListableBeanFactory 这个对象封装了全部Bean定义信息* @throws BeansException bean定义加载失败抛出异常,如果抛出异常, 则Spring初始化失败!*/@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)throws BeansException {//获取全部的Bean定义, getBeanDefinitionNames 获取Bean定义的名称// get 获得 Bean Definition Bean的定义 Names 名字String[] beanNames =configurableListableBeanFactory.getBeanDefinitionNames();Arrays.stream(beanNames).forEach(name -> System.out.println("MBFPP: Bean Name = " + name));}
}

        声明com.obj.spring. MyBeanPostProcessor,实现BeanPostProcessor接口:

package com.obj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/*** BeanPostProcessor Bean后期处理器(BPP), 在创建了Bean对象之后对象Bean进行处理* 其中包括两个方法* postProcessBeforeInitialization:bean后期处理,在初始化之前执行* postProcessAfterInitialization:bean后期处理,在初始化之后执行*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {//创建了每个一个bean以后,执行初始化方法之前,执行//bean 就是刚刚创建的Bean对象, beanName就是这个Bean IDSystem.out.println("MBPP:初始化前置处理"+beanName +", "+bean);//方法务必返回 bean 对象,否则会干扰 执行Bean初始化方法return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {//在每个Bean初始化以后执行后置处理方法System.out.println("MBPP:初始化后置处理"+beanName +", "+bean);//方法务必返回 bean 对象,否则会干扰Bean的使用return bean;}
}

        声明com.obj.spring.ProcessorDemo,创建ApplicationContext实例即可,当Spring扫描到Processor接口的实现类时,会自动加载并使之生效。

package com.obj.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ProcessorDemo {public static void main(String[] args) {ApplicationContext context =new AnnotationConfigApplicationContext(ContextConfig.class);}
}

1.3 Aware

        Spring框架中的Aware接口是一组标记接口,用于将相应的资源注入到Bean中,以实现Bean对它们的感知(Awareness),以便于进行一些自定义的扩展操作。

        例如,BeanNameAware接口可以让Bean对它所在的容器的名称有意识。当BeanFactory检测到某个Bean实现该接口后,会自动调用它的setBeanName()方法,将该Bean的名称作为参数传入该方法。

        Spring框架提供了10余种Aware接口的子接口,每个子接口能获取到的信息不同,开发者可以根据实际情况组合这些接口。以下是其中一些较为常用的接口:

        1、ApplicationContextAware:用于获取Spring容器上下文ApplicationContext对象。可以通过ApplicationContext对象获取到各种Spring容器管理的Bean实例,或者进行其他与容器相关的操作。

        2、BeanNameAware:用于获取当前Bean的名称。这个Aware接口常用于在Bean内部需要获取自己的Bean名称时使用。

        3、ResourceLoaderAware:用于获取ResourceLoader对象。ResourceLoader是Spring内置的一个用于加载资源(例如配置文件、图片、音频、视频等)的工具类,它可以支持多种资源的加载,包括从磁盘、网络、classpath以及URL等加载。

        4、EnvironmentAware:用于获取当前应用程序所在的环境变量和系统属性。可以通过Environment对象获取当前应用程序运行的环境变量和系统属性,如当前应用程序所在的操作系统、JAVA_HOME路径、用户的home目录等。

        声明com.obj.spring.AwareBean,实现BeanFactoryPostProcessor接口:

package com.obj.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AwareBean implements BeanNameAware, ApplicationContextAware {private ApplicationContext applicationContext;public AwareBean(){System.out.println("AwareBean构造器...");}@Overridepublic void setBeanName(String name) {System.out.println("AwareBean获取BeanName:"+name);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void doSomething() {// 获取Spring容器中的另一个BeanTagService anotherBean = (TagService) applicationContext.getBean("tagService");// 执行另一个Bean的方法System.out.println(anotherBean.getTags());;}
} 

        声明com.obj.spring.AwareDemo:

package com.obj.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AwareDemo {public static void main(String[] args) {ApplicationContext context =new AnnotationConfigApplicationContext(ContextConfig.class);AwareBean awareBean = context.getBean(AwareBean.class);awareBean.doSomething();}
}

2. Bean的创建过程

2.1 整体阶段划分

        由于Spring框架的官方文档没有明确对Bean的创建过程进行阶段划分,不同的书籍和技术类博客中对阶段的划分存在一定的差异。

        下面介绍一种来自于Spring官方认证的培训文档中的划分方式。

        Bean的创建步骤可以划分为三个阶段,分别是:(1)加载并处理Bean的定义,(2)Bean的实例化和(3)Bean的初始化。如下图所示:

        上述划分方式与一些书籍或技术类博客中的版本的对比如下图所示:

        学习Spring Bean的创建步骤,归根结底是需要掌握Spring框架中具体的执行步骤,即每一步的作用及先后顺序,阶段的划分主要起到辅助记忆的作用。在实际面试中,只要能将步骤描述清楚,使用哪个阶段划分的版本不会影响面试官对应试者的评价。

2.2 加载并处理Bean的定义

        加载并处理Bean的定义阶段具体包括的步骤如下:

        1、Spring启动后,根据配置文件加载Bean的定义,包括处理@Bean和@Component 注解。

        2、找到Bean定义后,将转换应用于Bean定义,也就是可以进一步修改处理Bean定义。

        3、在处理Bean定义的过程中调用了一系列实现了BeanFactoryPostProcessor 接口的对象。

  • 其中包括处理 @PropertySource、@Value 的PropertySourcesPlaceholderConfigurer
  • 其中包括处理 @Configuration 的 ConfigurationClassPostProcessor

        4、可以自行扩展 BeanFactoryPostProcesser 接口,参与Bean工厂后期处理功能。

2.3 Bean的实例化

        Bean的实例化阶段具体包括的步骤如下:

        1、首先查找Bean的依赖关系,解决创建Bean的先后次序问题

        2、实例化Bean对象,也就是创建Bean对象,这里包含构造器注入过程

        3、然后进行属性注入(属性注入,方法注入)

2.4 Bean的初始化

        Bean的初始化阶段具体包括的步骤如下:

        1、Bean的初始化由一系列的BeanPostProcessor对象完成

        2、先执行 BPP 的前置处理方法postProcessBeforeInitialization

        3、然后执行Bean的自定义初始化方法

        4、再执行BPP的后置处理方法postProcessAfterInitialization

        这个步骤可以干预扩展,可以自行实现BeanPostProcessor。Spring的AOP代理就是在这一步添加的DefaultAdvisorAutoProxyCreator。

2.5 @Bean和 @Component

        使用@Bean注解配置的Bean和使用@Component 注解配置的Bean的后处理方式是相同的。

3. 总结

        1、在Spring框架中,Processor(处理器)是一种用于定制化和拓展Spring容器的机制。它是Spring框架中重要的一环,用于增强Spring容器的功能和灵活性。

  • BeanPostProcessor
  • BeanFactoryPostProcessor
  • 开发者也可以通过自定义Processor来实现特定需求

        2、Spring框架中的Aware接口是一组标记接口,用于将相应的资源注入到Bean中,以实现Bean对它们的感知(Awareness),以便于进行一些自定义的扩展操作。

  • ApplicationContextAware:用于获取Spring容器上下文ApplicationContext对象
  • BeanNameAware:用于获取当前Bean的名称
  • ResourceLoaderAware:用于获取ResourceLoader对象
  • EnvironmentAware:用于获取当前应用程序所在的环境变量和系统属性

        3、Bean的创建步骤可以划分为三个阶段,分别是:(1)加载并处理Bean的定义,(2)Bean的实例化和(3)Bean的初始化。

        4、加载并处理Bean的定义阶段具体包括的步骤如下:

  • Spring启动后,根据配置文件加载Bean的定义,包括处理@Bean和@Component 注解
  • 找到Bean定义后,将转换应用于Bean定义,也就是可以进一步修改处理Bean定义
  • 在处理Bean定义的过程中调用了一系列实现了BeanFactoryPostProcessor 接口的对象

        5、Bean的实例化阶段具体包括的步骤如下:

  • 首先查找Bean的依赖关系,解决创建Bean的先后次序问题
  • 实例化Bean对象,也就行创建Bean对象,这里包含构造器注入过程
  • 然后进行属性注入(属性注入,方法注入)

        6、Bean的初始化阶段具体包括的步骤如下:

  • Bean的初始化由一系列的BeanPostProcessor对象完成
  • 先执行 BPP 的前置处理方法postProcessBeforeInitialization
  • 然后执行Bean的自定义初始化方法
  • 再执行BPP的后置处理方法postProcessAfterInitialization

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/660334.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基因组坐标转换,hg19 hg38 T2T相互转

在线工具1: https://genome.ucsc.edu/cgi-bin/hgLiftOver 支持输入格式, Positions: chr8:141310715 chr8-141310715 chr8 141310715Variants: chr8:141310715 T>G chr8-141310715-T-G NM_001089.3(ABCA3):c.875A>T (p.Glu292Val)Intervals: chr8:141310715-141310…

使用numpy基于全连接层实现Minst数据集训练——待续

PS:本贴还没完全写完,全部代码直接转至文末,有时间会一点一点把细节部分解释清楚 题外话:以前习惯调包实现网络,然后发现研究新的较为复杂的网络结构会很吃力,于是回过头来垒实基础,后续会在全连…

力扣82-链表、迭代 的思考

题目解读 给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。 两个示范 思考 返回链表:返回更新链表后的头结点; 更新链表:判断重复元素,改变指针…

HTML:元素分类

HTML:元素分类 概述块级元素(Block-level Elements)内联元素(Inline Elements)替换元素(Replaced Elements)表单元素(Form Elements) 概述 HTML(HyperText M…

【Qt之OpenGL】01创建OpenGL窗口

1.创建子类继承QOpenGLWidget 2.重写三个虚函数 /** 设置OpenGL的资源和状态,最先调用且调用一次* brief initializeGL*/ virtual void initializeGL() override; /** 设置OpenGL视口、投影等,当widget调整大小(或首次显示)时调用* brief resizeGL* param w* para…

企业终端安全管理软件有哪些?终端安全管理软件哪个好?

在当今数字化时代,企业终端安全管理软件的重要性日益凸显。随着网络攻击和信息安全风险的不断增加,企业需要采取有效的措施来保护自己的数据和网络资产。终端安全管理软件正是为了满足这一需求而诞生的。那么,市面上都有哪些企业终端安全管理…

公开课—京东生产环境海量数据架构优化实战

文章目录 读多写少——主库用来写,从库用来读单库的写压力太大——数据库的垂直和水平拆分分表怎么分呢?hash分表range分表多数据源操作与分布式事务问题 ShardingSphare分库分表(京东开源)关联查询怎么办?跨多个库&am…

49. 字母异位词分组 128. 最长连续序列

49. 字母异位词分组 128. 最长连续序列 把集合里面的所有元素都放入set容器里面 定义结果最大连续数量 ans for循环遍历每个元素 先判断集合里面有没有比这个元素小1的 如果没有 说明这个元素就是序列的第一个元素 然后接着找集合里面有没有比这个元素大1的 while一直找 …

营业执照办理

2024年4月30日00:00至2024年5月6日8:00对‮统系‬进行维护升级。系统维护升‮期级‬间,将关‮系闭‬统,暂停登‮注记‬册业务线‮申上‬报;4月30日申办登‮业记‬务的,请到属‮登地‬记注册窗口办理。 由此‮来带‬不便&#xf

Linux第二节--常见的指令介绍集合(持续更新中)

点赞关注不迷路!,本节涉及初识Linux第二节,主要为常见的几条指令介绍。 Linux下基本指令 1. ls 指令 语法: ls [选项][目录或文件] 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件&#…

中国移动举办算力网络未来产业暨联合体创新论坛

4月29日,在国务院国有资产监督管理委员会的指导下,由中国移动主办的算力网络未来产业暨联合体创新论坛在苏州举办。大会以“算网一体,智领未来”为主题,旨在汇聚算力网络产学研各界领军力量,共创算力网络技术策源之路&…

《HCIP-openEuler实验指导手册》1.7 Apache虚拟主机配置

知识点 配置步骤 需求 域名访问目录test1.com/home/source/test1test2.com/home/source/test2test3.com/home/source/test3 创建配置文件 touch /etc/httpd/conf.d/vhost.conf vim /etc/httpd/conf.d/vhost.conf文件内容如下 <VirtualHost *.81> ServerName test1.c…