当前位置: 首页 > news >正文

系列十六、Spring IOC容器的扩展点

一、概述

        Spring IOC容器的扩展点是指在IOC加载的过程中,如何对即将要创建的bean进行扩展。

二、扩展点

2.1、BeanDefinitionRegistryPostProcessor

2.1.1、概述

        BeanDefinitionRegistryPostProcessor是bean定义的后置处理器,在BeanDefinition加载后,实例化bean之前,调用 invokeBeanFactoryPostProcessors时进行扩展,通过改变BeanDefinition的定义信息进行扩展,源码如下:

2.1.2、继承结构

2.1.3、案例

2.1.3.1、ATM
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:06* @Description:*/
@Slf4j
@Component(value = "atm")
public class ATM {public int withdrawMoney(int money) {log.info("取钱方法正在执行...");if (money == 100) {throw new RuntimeException("自定义的异常");}return money;}}
2.1.3.2、MySpringConfig
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:29* @Description:*/
@Configuration
@ComponentScan(basePackages = {"org.star"})
public class MySpringConfig {}
 2.1.3.3、MyBeanDefinitionRegistryPostProcessor 
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/25 17:38* @Description:*/
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {/*** 作用:动态注册BeanDefinition* 调用时机:IOC加载时注册BeanDefinition的时候会调用* @param registry the bean definition registry used by the application context* @throws BeansException*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {RootBeanDefinition definition = new RootBeanDefinition(ATM.class);// 设置ATM bean为多实例definition.setScope("prototype");registry.registerBeanDefinition("atm",definition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition beanDefinition = beanFactory.getBeanDefinition("atm");// 将atm设置为懒加载,这样在容器启动时将不会创建bean,只有在getBean时才会创建对象beanDefinition.setLazyInit(true);}
}
2.1.3.4、AopFullAnnotationMainApp 
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);ATM atm1 = context.getBean("atm", ATM.class);ATM atm2 = context.getBean("atm", ATM.class);log.info("atm1:{},atm2:{},(atm1 == atm2):{}", atm1,atm2,(atm1 == atm2));}}

 

2.2、xxxAware接口

2.2.1、概述

        Spring中存在着大量的xxxAware接口实现类,用于在bean初始化完成之前做一些前置操作,程序员可以自己实现xxxAware接口,重写里边的方法修改bean的定义信息,进行扩展。

2.2.2、继承结构

2.2.3、案例

2.2.3.1、ATM

同上。

2.2.3.2、MySpringConfig

同上。

2.2.3.3、MyApplicationContextAware
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/25 18:51* @Description:*/
@Component
public class MyApplicationContextAware implements ApplicationContextAware {public ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;AnnotationConfigApplicationContext context = (AnnotationConfigApplicationContext) applicationContext;ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();BeanDefinition beanDefinition = beanFactory.getBeanDefinition("atm");beanDefinition.setScope("prototype");}}
2.2.3.4、AopFullAnnotationMainApp

同上。

2.2.3、调用链路

2.2.4、注意事项

        通过观察 2.1.3.4和 2.2.3.4的执行结果,不能发现xxxAware接口中配置的扩展覆盖了BeanDefinitionRegistryPostProcessor中的配置,说明xxxAware的优先级更高,这个也很好理解,对于同样的一个bean,后边的配置肯定会覆盖掉前边的配置。

2.3、生命周期回调时进行扩展

2.3.1、概述

        bean的生命周期回调主要分为两种,一种是初始化进行调用,另外一种是销毁时进行调用,但是不管是初始化还是销毁,都对应着三种方式,即:

        a、@PostConstruct @PreDestroy
        b、实现接口 InitializingBean, DisposableBean的方式
        c、@Bean(initMethod = "init",destroyMethod = "destroy")的方式

2.4、初始化后实例化前进行扩展

2.4.1、bean创建完成的标识

        当循环完所有的DeanDefinition后,bean就创建完了。

2.4.2、大致流程

启动IOC容器 ===> refresh() ===>finishBeanFactoryInitialization(beanFactory)===>beanFactory.preInstantiateSingletons()

2.4.3、源码解析

#1、启动IOC容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);#2、refresh()
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {this();register(componentClasses);refresh();
}# 3、finishBeanFactoryInitialization(beanFactory)
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}
}# 4、beanFactory.preInstantiateSingletons();
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Register a default embedded value resolver if no bean post-processor// (such as a PropertyPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.beanFactory.freezeConfiguration();// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();
}# 5、beanFactory.preInstantiateSingletons();
@Override
public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}
}

2.4.4、通过监听器扩展

2.4.4.1、Computer
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 11:52* @Description:*/
@Getter
@Setter
@Accessors(chain = true)
@Component
public class Computer {/*** 电脑名称*/private String name;/*** 品牌*/private String brand;}
2.4.4.2、 MyContextRefreshedEvent 
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 11:48* @Description: 监听器*/
@Component
public class MyContextRefreshedEvent {@EventListener(ContextRefreshedEvent.class)public void onContextRefreshedEvent(ContextRefreshedEvent event) {System.out.println(event);// bean初始化完成后做扩展,扩展代码写在这里ConfigurableApplicationContext context = (ConfigurableApplicationContext) event.getApplicationContext();DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();BeanDefinition beanDefinition = factory.getBeanDefinition("computer");beanDefinition.setScope("prototype");factory.registerBeanDefinition("computer",beanDefinition);System.out.println("all singleton beans loaded,onContextRefreshedEvent execute success!");}}
2.4.4.3、MySpringConfig(同上)
2.4.4.4、AopFullAnnotationMainApp 
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);Computer computer1 = context.getBean(Computer.class);Computer computer2 = context.getBean(Computer.class);log.info("computer1:{},computer2:{},(computer1 == computer2 ?) : {}",computer1,computer2,(computer1 == computer2));}
}

2.4.5、通过接口扩展

2.4.5.1、Computer
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 11:52* @Description:*/
@Getter
@Setter
@Accessors(chain = true)
@Component
@Slf4j
public class Computer {/*** 电脑名称*/private String name;/*** 品牌*/private String brand;public void init() {Computer computer = new Computer().setName("OptiPlex7010MT Plus13").setBrand("戴尔");log.info("Computer's init was invoked! computer:{}", JSON.toJSONString(computer));}}
2.4.5.2、MySmartInitializingSingleton
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 13:04* @Description:*/
@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {@Resourceprivate ApplicationContext applicationContext;@Overridepublic void afterSingletonsInstantiated() {ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();BeanDefinition beanDefinition = factory.getBeanDefinition("computer");beanDefinition.setInitMethodName("init");beanDefinition.setScope("prototype");factory.registerBeanDefinition("computer",beanDefinition);System.out.println("all singleton beans loaded,afterSingletonsInstantiated execute success!");}
}
2.4.5.3、MySpringConfig(同上)
2.4.5.4、AopFullAnnotationMainApp(同上) 

相关文章:

系列十六、Spring IOC容器的扩展点

一、概述 Spring IOC容器的扩展点是指在IOC加载的过程中&#xff0c;如何对即将要创建的bean进行扩展。 二、扩展点 2.1、BeanDefinitionRegistryPostProcessor 2.1.1、概述 BeanDefinitionRegistryPostProcessor是bean定义的后置处理器&#xff0c;在BeanDefinition加载后&a…...

eclipse项目移到idea上部署运行

1.配置web模块 另外&#xff0c;模块这里&#xff0c;也要加上Spring 2.配置Artifact &#xff08;用于tomcat&#xff09; 就是从上面配置的web模块&#xff0c;产生的工件 3.添加lib 一般是在web-inf/lib &#xff0c; 遇到的坑&#xff1a; jdk版本问题&#xff0c;这里…...

支持向量机的算法原理

支持向量机&#xff08;Support Vector Machine&#xff0c;简称SVM&#xff09;是机器学习领域中一种常用的分类算法&#xff0c;它基于统计学习理论和结构风险最小化原则&#xff0c;具有很强的理论基础和良好的分类性能。本文将详细介绍支持向量机的算法原理&#xff0c;并解…...

gitlab 12升级14(解决各种报错问题)

1.这里是从自己公司的源下载的rpm包&#xff0c;需要换成自己的 2.从12的最后一个版本升级到14的最后一个版本 # 停服务 [rootdocker test]# gitlab-ctl stop puma && gitlab-ctl stop sidekiq && gitlab-ctl stop nginx && gitlab-ctl status# 进入…...

给element plus中动态form-item增加校验的可行方法

element plus中的form组件自带校验机制。在常规使用场景中&#xff0c;表单项是固定的、明确的&#xff0c;且数量不会太多。校验规则的使用也如下&#xff1a; <template><div class"edit-page"><el-form :model"formModel" ref"for…...

C++学习之值传递

c/c中存在三种传值方式&#xff0c;在局部函数中&#xff0c;对这三种传值方式传入的参数进行修改&#xff0c;会得到不同的结果。具体见下例&#xff1a; #include <stdlib.h> #include <stdio.h>static int dummny 10000;// 传值(传过来的是原始值的副本&#…...

网络视频播放卡顿原因分析

一、问题描述 某项目通过拉摄像机rtsp流转rtmp/http-flv/ws-flv的方案&#xff0c;使用户可以在网页中观看摄像机的视频画面。在 观看视频时偶发出现卡顿现象。 二、卡顿现象分析和解决 此问题涉及的原因较多&#xff0c;所以得考虑各环节的问题可能性&#xff0c;并根据现场实…...

Android 相机库CameraView源码解析 (二) : 拍照

1. 前言 这段时间&#xff0c;在使用 natario1/CameraView 来实现带滤镜的预览、拍照、录像功能。 由于CameraView封装的比较到位&#xff0c;在项目前期&#xff0c;的确为我们节省了不少时间。 但随着项目持续深入&#xff0c;对于CameraView的使用进入深水区&#xff0c;逐…...

计算机缺少d3dx9_43.dll怎么办?5个方法快速修复d3dx9_43.dll文件

在计算机使用过程中&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“d3dx9_43.dll丢失”。这个问题可能会影响到我们的游戏体验或者软件运行。为了解决这个问题&#xff0c;我查阅了一些资料并尝试了多种方法。在这里&#xff0c;我想分享一下我对d3dx9_43.d…...

2023亚太杯数学建模C题思路分析 - 我国新能源电动汽车的发展趋势

1 赛题 问题C 我国新能源电动汽车的发展趋势 新能源汽车是指以先进技术原理、新技术、新结构的非常规汽车燃料为动力来源( 非常规汽车燃料指汽油、柴油以外的燃料&#xff09;&#xff0c;将先进技术进行汽车动力控制和驱动相结 合的汽车。新能源汽车主要包括四种类型&#x…...

c语言新龟兔赛跑

以下是一个使用C语言编写的新的龟兔赛跑游戏&#xff1a; #include <stdio.h>#include <stdlib.h>#include <time.h>int main() { int distance, turtle_speed, rabbit_speed, turtle_time, rabbit_time, rabbit_lead; srand(time(NULL)); // 随机数种…...

Linux驱动开发——网络设备驱动(理论篇)

目录 一、前言 二、网络层次结构 三、网络设备驱动核心数据结构和函数 一、前言 网络设备驱动是 Linux 的第三大类驱动&#xff0c;也是我们学习的最后一类 Linux 驱动。这里我们首先简单学习一下网络协议层次结构&#xff0c;然后简单讨论 Linux 内核中网络实现的层次结构。…...

simulink仿真

1&#xff09;系统问题 连续系统&#xff0c;离散系统&#xff08;采样周期问题&#xff09; 系统分析问题 2&#xff09;求解器问题 变步长&#xff0c;定步长&#xff0c;步长时间与采样周期问题、 3&#xff09;积分器问题 连续积分&#xff0c;离散积分问题&#xff…...

PC端页面进去先出现加载效果

自定义指令v-loading&#xff0c;只需要绑定Boolean即可 v-loading“loading” <el-table :data"list" border style"width: 100%" v-loading"loading"><el-table-column align"center" label"序号" width"5…...

磁盘清理在哪里?学会这4个方法,快速清理内存!

“在使用电脑的过程中&#xff0c;我可能经常会保存一些文件到电脑上&#xff0c;这也导致电脑经常出现内存不足的情况。我想问问磁盘清理在哪里呀&#xff1f;我应该如何打开呢&#xff1f;” 随着使用电脑的时间增长&#xff0c;用户可能经常会遇到磁盘空间不足的情况&#x…...

Error opening terminal: xterm.”的解决方法

主要是看下面这两个变量是否设置正确 $ echo $TERM $ echo $TERMINFO 通常TERM的默认值为xterm-265color, 要查看支持的term&#xff0c;可以ls -al /lib/terminfo/x/ 如果TERM是xterm-265color的话&#xff0c;TERMINFO设置为/usr/lib/terminfo make menuconfig时提示“Err…...

C#常见的设计模式-结构型模式

引言 设计模式是软件工程中用于解决常见问题的可复用解决方案。在C#编程中&#xff0c;常见的设计模式具有广泛的应用。本篇博客将重点介绍C#中常见的结构型设计模式&#xff0c;包括适配器模式、装饰器模式、代理模式、组合模式和享元模式。 目录 引言1. 适配器模式(Adapter …...

Redis分片备库切换操作

Redis分片备库切换操作 场景描述&#xff1a; 分片集群&#xff1a; 1.ipa:5001-ipa:5002 2.ipb:5001-ipb:5002 需将两个分片备库互置完成灾备 操作步骤 准备工作 主机密码&#xff1a;1qaz!QAZ 获取节点信息命令 /redispath/bin/redis-cli -a password -h ip -p port red…...

二叉树:leetcode1457. 二叉树中的伪回文路径

给你一棵二叉树&#xff0c;每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的&#xff0c;当它满足&#xff1a;路径经过的所有节点值的排列中&#xff0c;存在一个回文序列。 请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。 给定二叉树的节点数目…...

【【Linux下的Petallinux 以及其他的配置】】

Linux下的Petallinux 以及其他的配置 sudo apt-get install iproute2 gawk python3 python build-essential gcc git make net-tools libncurses5-dev tftpd zlib1g-dev libssl-dev flex bison libselinux1 gnupg wget git-core diffstat chrpath socat xterm autoconf libtoo…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...