SpringBoot中动态注册Bean的方式

测试环境,本文源码

  • Java:8
  • SpringBoot:2.5.14
  • 示例场景:动态注册ProxyServlet,间接实现类似于Nginx的反向代理功能

先理解如何实现动态注册 Bean

由于在 SpringBoot 中,先进行 Bean 的定义,再根据定义进行 Bean 的实例化,所以实现动态 Bean ,我们只需要动态注册 Bean 定义即可。

这就用到了 BeanDefinitionRegistryPostProcessorpostProcessBeanDefinitionRegistry 这个方法。

源码注释

Modify the application context’s internal bean definition registry after its standard initialization. All regular bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for adding further bean definitions before the next post-processing phase kicks in.

所有常规的Bean都已经定义但尚未实例化时,这时候,你可以再新增 Bean 定义

一、通用方式

先说一个小插曲,建议搭配源码食用。假如三个类,他们分别实现且只实现了以下三个接口

  • BeanDefinitionRegistryPostProcessor
  • ApplicationContextAware
  • EnvironmentAware

这时候,这三个 Bean 的默认加载顺序如下。

并且,这三个 Bean 的方法执行顺序也是跟加载顺序相同。

但是,如果 Bean 实现了一个比 ApplicationContextAware 或者 EnvironmentAware 更先加载的 Bean ,那么就会出现先执行 setApplicationContext 或者 setEnvironment 的方法,为啥嘞?

是因为在 Bean 初始化前,先判定有没有实现 Aware 接口,如果实现过了,那么就直接优先调用 Aware 中的方法。如图。

既然明白了这个流程,那我们就可以实现功能了。

该通用方式是适用于 SpringBoot 框架中通用动态注册 Bean 的做法。主要是通过 BeanDefinitionRegistryPostProcessor 动态注册 Bean 定义。

import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;import java.util.HashMap;
import java.util.Map;/*** 动态配置bean** @author chenchuancheng* @since 2024/07/11 22:50*/
@Configuration
public class DynamicBeanConfig implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {private Environment environment;@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ServletRegistrationBean.class);builder.addConstructorArgValue(new ProxyServlet());builder.addConstructorArgValue(environment.getProperty("proxy.servletUrl"));Map<String, String> initParams = new HashMap<>();initParams.put("targetUri", environment.getProperty("proxy.targetUrl"));initParams.put("log", "true");builder.addPropertyValue("initParameters", initParams);builder.addPropertyValue("name", environment.getProperty("proxy.name"));registry.registerBeanDefinition("proxyServlet", builder.getBeanDefinition());}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}
}

除了实现 Aware 接口,也可以通过构造函数注入,也可以保证调用方法时有值了。

二、特定方式

这个是使用 ServletContext 动态注册 Servlet 的方式。

import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import java.util.HashMap;
import java.util.Map;@Configuration
public class ProxyServletInitializer implements ServletContextInitializer {private final Environment environment;public ProxyServletInitializer(Environment environment) {this.environment = environment;}@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {registerProxyServlet(servletContext,environment.getProperty("proxy.name"),environment.getProperty("proxy.targetUrl"));}private void registerProxyServlet(ServletContext servletContext, String name, String targetUri) {ProxyServlet proxyServlet = new ProxyServlet();ServletRegistration.Dynamic registration = servletContext.addServlet(name + "ProxyServlet", proxyServlet);registration.setLoadOnStartup(1);registration.addMapping("/" + name + "/*");Map<String, String> initParameters = new HashMap<>();initParameters.put("targetUri", targetUri);initParameters.put("log", "true");registration.setInitParameters(initParameters);}
}

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

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

相关文章

企业全历史行为数据助ToB企业决策层开启营销的上帝视角

“上帝视角”是每个企业家都渴望拥有的。上帝视角的能力有多么吸引人呢&#xff1f;通常&#xff0c;一个企业家在技术、产品、营销中的任何一个领域拥有上帝视角的能力&#xff0c;就足可以让他的企业大杀四方&#xff0c;甚至创造历史。 在技术或产品领域&#xff0c;靠“上…

沙袋装袋机的原理和特点_鼎跃安全

在现代工业和建筑领域&#xff0c;沙子等散状物料的包装是一个必不可少的环节。传统的手工包装方式效率低下且劳动强度大&#xff0c;而沙袋装袋机的出现则极大地提高了包装效率和质量。 一、沙袋装袋机的工作原理 沙子通过输送系统从储料仓输送到装袋机的料斗中。输送系统设计…

Eureka——Spring Cloud中的服务注册与发现组件

目录 1. 前言2. Eureka的概述2.1 Eureka的核心功能2.2 Eureka的角色与特点2.3 Eureka的使用优势 3. 创建 Spring Cloud 的注册中心3.1 创建一个父项目3.2 创建Spring Cloud的注册中心Eureka 4. 创建服务提供者5. 创建一个消费者Consumer&#xff0c;调用服务提供者Provider 1. …

java链表常见简单面试算法题

头插法、尾插法 头插法&#xff1a;先待插入指向头结点的next&#xff0c;后头结点的next指向待插入。 尾插法&#xff1a;借助尾指针&#xff0c;直接插入 /*** 头插法* param head* return*/public static Node head_insert(Node head, int t){Node nodenew Node(t);node.set…

C++设计模式(装饰器模式)

装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许在不改变原有对象结构和功能的基础上&#xff0c;动态地给对象添加额外的职责或功能。 装饰器模式的主要特点包括&#xff1a; 1. 保持了被装饰对象的核心职责不变。2. 能够透明地…

【Diffusion学习】【生成式AI】Stable Diffusion、DALL-E、Imagen 背後共同的套路

文章目录 图片生成Framework 需要3个组件&#xff1a;相关论文【Stable Diffusion&#xff0c;DALL-E&#xff0c;Imagen】 具体介绍三个组件1. Text encoder介绍【结论&#xff1a;文字的encoder重要&#xff0c;Diffusion的模型不是很重要&#xff01;】评估指标&#xff1a;…

Webpack看这篇就够了

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

React@16.x(57)Redux@4.x(6)- 实现 bindActionCreators

目录 1&#xff0c;分析1&#xff0c;直接传入函数2&#xff0c;传入对象 2&#xff0c;实现 1&#xff0c;分析 一般情况下&#xff0c;action 并不是一个写死的对象&#xff0c;而是通过函数来获取。 而 bindActionCreators 的作用&#xff1a;为了更方便的使用创建 action…

补充.IDEA的使用

首先我们要了解在idea中Java工程由项目&#xff08;project&#xff09;、模块&#xff08;module&#xff09;包&#xff08;package&#xff09;、类&#xff08;class&#xff09;组成。 他们之间的关系是project包含module包含package包含class。 所以我们要按照先建一个pr…

AutoMQ 社区双周精选第十二期(2024.06.29~2024.07.12)

本期概要 欢迎来到 AutoMQ 第十一期双周精选&#xff01;在过去两周里&#xff0c;主干动态方面&#xff0c;AutoMQ 跟进了 Apache Kafka 3.4.x BUG 修复&#xff0c;并进行了CPU & GC 性能优化&#xff0c;另外&#xff0c;AutoBalancing 的 Reporter 和 Retriever 也将支…

Linux的相关命令

Linux 1. 什么是Linux系统 Linux&#xff0c;全称GNU/Linux&#xff0c;是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年10月5日首次发布&#xff0c;它主要受到Minix和Unix思想…

浏览器缓存:强缓存与协商缓存实现原理有哪些?

1、强缓存&#xff1a;设置缓存时间的&#xff0c;那么在这个时间内浏览器向服务器发送请求更新数据&#xff0c;但是服务器会让其从缓存中获取数据。 可参考&#xff1a;彻底弄懂强缓存与协商缓存 - 简书 2、协商缓存每次都会向浏览器询问&#xff0c;那么是怎么询问的呢&…

wordpress 调用另外一个网站的内容 按指定关键词调用

要在WordPress中调用另一个网站的内容并根据指定关键词进行筛选&#xff0c;你可以使用以下代码。这段代码使用了WordPress内置的wp_remote_get函数来获取远程网站的内容&#xff0c;然后使用PHP的DOMDocument和DOMXPath类来解析HTML并筛选出包含指定关键词的内容。 首先&…

H2数据库启动时,设置非“全零监听”

全零监听 全零监听&#xff08;即将监听地址设置为全零地址&#xff0c;如IPv4中的0.0.0.0或IPv6中的::&#xff09;在网络服务配置中确实存在一定的安全风险。以下是全零监听可能带来的安全风险&#xff1a; 1. 暴露服务到不安全网络 全网段监听&#xff1a;将监听地址设置…

中介者模式(行为型)

目录 一、前言 二、中介者模式 三、总结 一、前言 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;又成为调停者模式&#xff0c;用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地互相引用&#xff0c;从而使其耦合…

2024最新超详细SpringMvc常用注解总结

SpringMVC常用注解 控制器&#xff08;Controller&#xff09;相关注解&#xff1a; 1.Controller Controller 注解用于标识一个类为 Spring MVC 的控制器&#xff0c;它能够处理用户的请求并返回相应的视图或数据。通常与 RequestMapping 注解一起使用&#xff0c;以定义请求…

解决NodeJS控制台输出中文乱码

前言 不知道是系统升级还是Nodejs升级的原因,我从NodeJS19.x升级到20.x后,项目输出的中文就变成了乱码.经测试chcp 65001指令不能有效的解决问题. 于是在AI的加持下得到了这条指令(好用): [Console]::OutputEncoding [System.Text.Encoding]::UTF8在powershell中执行如上指…

JavaScript基础(十三)

Math对象 方法&#xff0b;说明 ceil() 对数进行上舍入 例&#xff1a;Math.ceil(12.5)返回13&#xff1b; Math.ceil(-12.5)返回-12 &#xff08;简单点来记就是ceil返回的值要比传入的大&#xff09; var…

CP Process2

CP Process2 信贷流程&#xff0c;概念&#xff0c;分类&#xff0c;五级十二类

docker镜像命令容器命令

docker镜像命令 1、docker images //查看所有本地的主机上的镜像 2、docker search mysql //搜素镜像 2、docker pull mysql:5.7 //指定版本拉取mysql镜像 3、docker pull mysql //不指定版本拉取mysql镜像 4、docker rmi -f 镜像id //删除指定镜像 5、4、docker rmi -f 镜像…