深入Spring底层透析后置处理器之豁然开朗篇

news2025/7/19 20:45:18

目录

  • 前言
  • Spring的后置处理器
    • Bean工厂后置处理器
    • Bean后置处理器
  • 自定义@Component实现注解开发

前言

看这篇文章之前,需要了解Bean创建的过程,本篇文章是接着bean创建的基本流程的续写
Bean创建的基本过程:http://t.csdn.cn/1lK2d


Spring的后置处理器

熟悉Bean创建的基本流程是前提

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行

那Spring的后置处理器有什么用处呢?
不知道你看到它可以动态注册BeanDefinition时有什么想法,对,你想的没错,注解开发原理中就是用Spring的后置处理器来动态创建Bean对象的,别眨眼,接下来就时见证奇迹的时刻


Bean工厂后置处理器

Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;也就是当把xml中所有bean配置信息封装成BeanDefinition对象,装到BeanDefinitionMap集合后,但还没有反射创建bean对象时,再往map中注册BeanDefinition对象,后续反射就会创建出新的xml中未定义的对象


Bean工厂后处理器 – BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,在BeanDefinitionMap填充完毕后,Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

所以它的使用分以下几步

  • 创建一个处理器类实现BeanFactoryPostProcessor接口
  • 重写BeanFactoryPostProcessor的方法
  • 交给Spring容器管理(配置到xml中或加注解)

使用方式如下

在这里插入图片描述


由于BeanDefinition是接口,我们要new 一个BeanDefinition对象,就要new 它的一个实现类RootBeanDefinition对象

在这里插入图片描述


其中需要强转为DefaultListableBeanFactory是因为,ConfigurableListableBeanFactory的对象无法把beanDefinition注册到map中,BeanDefinitionMap是DefaultListableBeanFactory中定义的集合,而DefaultListableBeanFactory又是实现了ConfigurableListableBeanFactory的接口,所以强转一下。

在这里插入图片描述

不得不说,这个源码自己也需要多看,不然这些接口名类名是什么,继承了什么,有什么关键成员变量都不清楚,看这些调用关系自然就云里雾里


Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作

public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {
	//这个方法是BeanFactoryPostProcessor接口的方法,重写一下就不用管了
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {}

	
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
			BeanDefinition beanDefinition = new RootBeanDefinition();
			beanDefinition.setBeanClassName("com.dao.UserDaoImpl");//要创建的bean的位置
			//注册beanDefinition
			beanDefinitionRegistry.registerBeanDefinition("userDao",beanDefinition);
		}
}

最后main方法中调用时

UserDao userDao = applicationContext.getBean(UserDao.class)

在这里插入图片描述


Bean后置处理器

Bean后处理器 – BeanPostProcessor

Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。


bean后处理器的使用步骤和bean工厂后处理器基本类似,只是处理时机不一样,bean工厂后处理器在填充map后,实例化前;bean后处理器在实例化后,添加单例池前

  • 创建后处理器类(自己随便创建一个就行)
  • 实现 BeanPostProcessor接口,重写它的方法
  • 把后处理器类交由bean管理

BeanPostProcessor的接口定义如下(模板):

public interface BeanPostProcessor {
	@Nullable//表示该方法可以不写
	//在属性注入完毕,init初始化方法执行之前被回调
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	//在初始化方法执行之后,被添加到单例池singletonObjects之前被回调
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

在这里插入图片描述


自定义@Component实现注解开发

  • 自定义@MyComponent注解,使用在类上;
  • 使用包扫描器工具BaseClassScanUtils 完成指定包的类扫描;
  • 自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析后最终被Spring管理。(注意实现BeanFactoryPostProcessor接口的类需要交由Spring管理)

原理大概就是用包扫描工具类,指定包及其子包下的类上加了自定义注解的类名获取并添加到一个map集合中,然后遍历依次对它们进行包装成一个个BeanDefinition对象,然后再它们注册到BeanDefinitionMap集合中,后续反射创建bean时,这些注解添加的bean也会被创建。

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		//指定要扫描的包
        String basePackage = "com";
		//调用扫描工具BaseClassScanUtils扫描指定包及其子包下的@MyComponent
        Map<String, Class> myComponentClassMap = BaseClassScanUtils.scanMyComponentAnnotation(basePackage);
		//遍历Map集合,创建BeanDefinition对象进行注册
        myComponentClassMap.forEach((beanName,clazz)->{
            try {
                BeanDefinition beanDefinition = new RootBeanDefinition();
                beanDefinition.setBeanClassName(clazz.getName());
                registry.registerBeanDefinition(beanName,beanDefinition);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });}

不得不说有那味了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python3 命名空间和作用域实例及演示

命名空间 先看看官方文档的一段话&#xff1a; 命名空间(Namespace)是从名称到对象的映射&#xff0c;大部分的命名空间都是通过 Python 字典来实现的。 A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries…

凌恩生物经典文章:孟德尔诞辰200周年,Nature Genetics礼献豌豆高质量精细图谱

本期为大家分享的文章是2022年发表在《Nature Genetics》上的一篇文章“Improved pea reference genome and pan-genome highlight genomic features and evolutionary characteristics”&#xff0c;作者通过结合三代pacbio测序、染色体构象捕获&#xff08;Hi-C&#xff09;测…

Meta分析在生态环境领域里的应用

Meta分析&#xff08;Meta Analysis&#xff09;是当今比较流行的综合具有同一主题的多个独立研究的统计学方法&#xff0c;是较高一级逻辑形式上的定量文献综述。20世纪90年代后&#xff0c;Meta分析被引入生态环境领域的研究&#xff0c;并得到高度的重视和长足的发展&#x…

企业什么要建设自有即时通讯软件系统

随着科技的不断发展&#xff0c;各种即时通讯软件也不断发展进步&#xff0c;而这也与企业的发展息息相关&#xff0c;因为每个人&#xff0c;每个企业都有属于自己的机密&#xff0c;属于自己的隐私。 钉钉&#xff0c;企业微信&#xff0c;等公有的即时通讯软件给企业带来便利…

微信社区小程序/h5/圈子论坛贴吧交友/博客/社交/陌生人社交/宠物/话题/私域/同城交友

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 小程序/app/H5多端圈子社区论坛系统,交友/博客/社交/陌生人社交,即时聊天,私域话题,社区论坛圈子,信息引流小程序源码,广场/微校园/微小区/微同城/ 圈子论坛社区系统&#xff0c;含完整…

扬帆优配|3300点半日游!上证指数冲高回落;再迎重磅利好!

今天早盘&#xff0c;A股冲高回落&#xff0c;上证指数3300点得而复失&#xff0c;深证成指也于12000点无功而返。 盘面上&#xff0c;煤炭、钢铁、房地产、才智政务等板块涨幅居前&#xff0c;酿酒、酒店餐饮、日用化工、IT设备等板块跌幅居前。北上资金净流入7.77亿元。 房地…

UML中常见的9种图

UML是Unified Model Language的缩写&#xff0c;中文是统一建模语言&#xff0c;是由一整套图表组成的标准化建模语言。UML用于帮助系统开发人员阐明&#xff0c;展示&#xff0c;构建和记录软件系统的产出。通过使用UML使得在软件开发之前&#xff0c; 对整个软件设计有更好的…

【数据库】Redis数据类型

目录 一&#xff0c; Key操作 1&#xff0c; 相关命令 2&#xff0c; 示例演示 二&#xff0c;字符串 String 1&#xff0c; 结构图 2&#xff0c;相关命令 3&#xff0c;示例演示 三&#xff0c; 列表 List 1&#xff0c; 结构图 2&#xff0c; 相关命令 3&#xf…

VO、DTO、BO、PO、DO区别

VO、DTO、BO、PO、DO区别 VO&#xff1a;&#xff08;View Object&#xff09;视图对象&#xff0c;一般位于Controller层&#xff0c;用于展示视图。DTO&#xff1a;&#xff08;Data Transfer Object&#xff09;数据传输对象&#xff0c; 即RPC 接口请求或传输出去的对象&a…

PMP值得考吗?含金量如何?

关于哪些证书可以考&#xff0c;这里我也不说其他的证书因为术业有专攻&#xff0c;其他证书的含金量估计我也没有更加专业的人士懂&#xff0c;我就推荐一下关于项目管理pmp证书的一些含金量吧&#xff01;对于想备考PMP的朋友或许有一些帮助。 一&#xff0c;PMP证书的价值体…

简易高并发内存池

文章目录从零实现一个高并发的内存池定长内存池定长内存池设计申请内存池用户申请用户归还&#xff08;释放&#xff09;总体代码测试对比&#xff08;malloc&#xff09;高并发内存池框架简介thread cache的设计申请部分释放部分第一层的测试central cache的设计申请部分释放部…

【Kubernetes】【十九】安全认证

第九章 安全认证 本章节主要介绍Kubernetes的安全认证机制。 访问控制概述 ​ Kubernetes作为一个分布式集群的管理工具&#xff0c;保证集群的安全性是其一个重要的任务。所谓的安全性其实就是保证对Kubernetes的各种客户端进行认证和鉴权操作。 客户端 在Kubernetes集群…

【Kubernetes】【十七】数据存储 基本存储 EmptyDir HostPath NFS

第八章 数据存储 ​ 在前面已经提到&#xff0c;容器的生命周期可能很短&#xff0c;会被频繁地创建和销毁。那么容器在销毁时&#xff0c;保存在容器中的数据也会被清除。这种结果对用户来说&#xff0c;在某些情况下是不乐意看到的。为了持久化保存容器的数据&#xff0c;ku…

2023只会“点点点”,被裁只是时间问题,高薪的自动化测试需要掌握那些技能?

互联网已然是存量市场了&#xff0c;对人员规模的需求正在放缓。在存量市场里&#xff0c;冗余人员和低效人员会被淘汰、被外包。而优秀的人才也会一直受到招聘方的青睐。所以我们就看到了近期行业里冰火两重天的一幕&#xff0c;一边是大量的低端测试工程师被淘汰、求职屡屡碰…

ssh设置:免密登入、修改默认端口、禁止root登入、限制错误登入次数

服务器&#xff1a; 客户端&#xff1a; 在下面不再说明服务器和客户端。 1.修改ssh默认端口 是在服务器中设置。 该设置涉及三部分&#xff1a;sshd配置文件修改/增加新端口、Selinux添加新端口、Firewall开放新端口。 vim /etc/ssh/sshd.config&#xff0c;找到#Port行&…

使用PHP+yii2调用asmx服务接口

一.创建服务端 1&#xff1a;创建一个ASP.NET web应用程序 2:选择空的模板 3&#xff1a;系统生成项目目录 4&#xff1a;右键项目-添加项-新建项 5&#xff1a;选择Web 服务&#xff08;ASMX&#xff09; 6&#xff1a;选择之后项目中会有一个Test.asmx服务程序&#xff0c;…

【闲聊杂谈】深入剖析SpringCloud Alibaba之Nacos源码

Nacos核心功能点 服务注册 Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务&#xff0c;提供自身的元数据&#xff0c;比如ip地址、端口等信息。Nacos Server接收到注册请求后&#xff0c;就会把这些元数据信息存储在一个双层的内存Map中&#xff1b; 服…

(十八)、首页点赞高亮显示的功能实现【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1&#xff0c;首页点赞高亮显示的逻辑 思路&#xff1a;首先&#xff0c;查询所有在首页index页面中展示的文章id&#xff0c;存为一个id数组&#xff1b;然后利用dbcloud command命令和文章id数组&#xff0c;统一查询文章点赞表&#xff1b;其中加上两个筛选条件&#xff08…

阿里巴巴内网 Spring Cloud Alibaba 强势来袭,开创微服务的新时代

Spring Cloud 发展史 Spring Cloud 从 15 年的 3 月份推出之后&#xff0c;迅速在 Java 微服务生态中&#xff0c;成为开发人员的首选技术栈。 Spring Cloud 在 Spring Boot 的基础上&#xff0c;保留 Java 开发习惯&#xff0c;加入分布式特性&#xff0c;提供了一系列通用工…

0/1 nodes are available: 1 node(s) didn‘t match Pod‘s node affinity.

主要是需要确认你的yaml文件中是否有nodeSelector的配置&#xff0c;一般是因为k8s集群中没有相应的node节点匹配导致 这个错误消息表明您正在尝试在不符合Pod的节点亲和性规则的节点上运行Pod。这通常是由于节点选择器或节点亲和性规则设置不正确引起的。 以下是一些可能导致…