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

反射第二弹:用注册器动态注册(用自定义的注解标注的)策略,实现策略模式的设计

目录

引言

设计思路:

代码实现:

标注注解:@StrategyClass

扫描注解:trategyScan

注册器抽象类:

动态策略注册类:

AOP类:

总结:


引言

        曾经有人问我,假如有一个业务或者数据处理逻辑,会根据甲方客户繁杂的业务需求,而动态变化,该怎么处理,具体怎么实现?

        将所有策略strategy都写出来,然后放入一个hashMap,根据不同的业务需求,调用不同的策略就行了。

        再问:那如果我的策略动态多变,再将strategy放入Map的代码,不想写死,不想频繁的修改代码怎么实现?比如我将策略代码写入项目下某个文件夹下面某个文件里,或者直接存入数据库某张表里,策略代码用text类型字段存起来,再调用构建接口,将策略逻辑用类加载器,加载出来,动态的创建为一个个新的strategy对象呢?

        读取文件或者text字段,并解析为java代码,编译后,用类加载的方式加载,并且注册进Map,这个稍微复杂,但是我可以实现,只用在代码中添加策略,但是不用修改注册逻辑代码的方式。

设计思路:

  1. 所有需要被自动添加的策略类 Strategy 都必须加注解

  2. 再做一个扫描注解,属性包含:标明需要被扫描的包路径,@Import 标注一个注册器(实现ImportBeanDefinitionRegistrar),

  3. 定义一个注册器,实现ImportBeanDefinitionRegistrar,该注册器可以根据上述注解找到所有被注解标注的类,然后获取到标注的名称,实例化该类,并注册入指定的缓存。

        将此注解加注在springboot启动类上面就可以在项目启动的时候,按照指定的包路径去扫描指定注解的类,然后利用反射机制,获取到扫描到的(被标注注解的)类的元空间,有了元空间,不管是获取该类上的注解,注解属性,还是该类的属性,方法都是没问题的。那么就可以获取到被扫描到的策略strategy的名字,再利用反射 clazz.newInstance()  创建出实例,放入缓存,就解决了动态注册策略的目的了。

    除了对反射的利用,还需要对spring 容器有一定的理解,才能利用spring容器的environment, resourceLoader ,做出扫描器,使用resourceLoader 扫描该环境下,所有带注解的类;再根据指定的注解,过滤出目标类。

代码实现:

标注注解:@StrategyClass

import io.swagger.v3.oas.annotations.tags.Tag;
import java.lang.annotation.*;/*** @Title: StrategyClass* @Description: 用来标记需要被注册的strategy* @Author: wenrong* @Date: 2024/4/2 10:02* @Version:1.0*/@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface StrategyClass {/*** 策略名* 为空时,会尝试读取 {@link Tag#name()} 属性*/String strategyName() default "";}

扫描注解:trategyScan

@DynamicStrategyScan注解标记在springboot启动类上,在springboot启动的时候,就会扫描@StrategyClass 注解的策略类,并开始自动添加到Map 缓存。

import org.springframework.context.annotation.Import;
import java.lang.annotation.*;/*** @Title: DynamicStrategyScan* @Description: 用来扫描有动态策略注解的类,并初始化成相应的配置,注册到JVM 缓存* @Author: wenrong* @Date: 2024/4/2 15:27* @Version:1.0*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(DynamicStrategyRegister.class)
@Documented
public @interface DynamicStrategyScan {String[] value() default {};String[] basePackages() default {};
}

注册器抽象类:

因为可能不光策略需要被注册,其他的也可能需要被注册,所以这里这里做一下抽象:

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;/*** @Title: AnnotationScanAndRegister* @Description:* @Author: wenrong* @Date: 2024/4/2 15:35* @Version:1.0*/
public abstract class AnnotationScanAndRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {/*** 资源加载器*/protected ResourceLoader resourceLoader;/*** 环境*/protected Environment environment;@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);}/*** author: wenrong* date: 2024/4/2 15:36* 获取base packages*/protected static Set<String> getBasePackages(AnnotationMetadata importingClassMetadata, Class<? extends Annotation>

相关文章:

反射第二弹:用注册器动态注册(用自定义的注解标注的)策略,实现策略模式的设计

目录 引言 设计思路: 代码实现: 标注注解:@StrategyClass 扫描注解:trategyScan 注册器抽象类: 动态策略注册类: AOP类: 总结: 引言 曾经有人问我,假如有一个业务或者数据处理逻辑,会根据甲方客户繁杂的业务需求,而动态变化,该怎么处理,具体怎么实现? 将…...

【Xcode Command Line Tools】安装指南

安装指令 xcode-select --install安装 完成安装 验证 $ xcode-select -p /Library/Developer/CommandLineTools...

springboot开发网站-使用redis数据库定时特征限制指定ip的访问次数

springboot开发网站-使用redis数据库定时特征限制指定ip的访问次数。近期网站经常有人恶意访问&#xff0c;提交了很多垃圾信息。为了屏蔽这类灌水帖&#xff0c;打算屏蔽ip地址&#xff0c;限制24小时内只能访问1次某个接口。下面是测试的案例代码内容。 1&#xff1a;首先&am…...

【大模型理论篇】大模型相关的周边技术分享-关于《NN and DL》的笔记

本文所要介绍的一本书《Neural Networks and Deep Learning》&#xff0c;该书作者Michael Nielsen&#xff0c;Y Combinator Research的研究员&#xff0c;是多年之前自己看的一本基础书籍&#xff0c;很适合入门了解一些关于深度学习的概念知识&#xff0c;当然也包含了一些小…...

CSS 圆形边框与阴影

目录 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影...

Bianchi模型、python计算及ns3验证

由于项目与学习需要,最近学习了bianchi模型,并在python中进行了公式->代码的转化,仿真结果与ns3结果对比。 本文更多的是理解模型各个部分的含义、把各个简单的推导过程转化为python、ns3对比: 1 理论吞吐与传输概率、传输成功概率、包长、速率、排队时间、成功传输时…...

SQL常用语法

SQL&#xff08;Structured Query Language&#xff09;是一种用于存储、操作和检索数据库中数据的标准编程语言。以下是一些常用的 SQL 语法&#xff1a; 数据库操作 创建数据库&#xff1a;CREATE DATABASE database_name;删除数据库&#xff1a;DROP DATABASE database_name…...

计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

浏览器前端向后端提供服务

WEB后端向浏览器前端提供服务是最常见的场景&#xff0c;前端向后端的接口发起GET或者POST请求&#xff0c;后端收到请求后执行服务器端任务进行处理&#xff0c;完成后向前端发送响应。 那浏览器前端向后端提供服务是什么鬼&#xff1f; 说来话长&#xff0c;长话短说。我在人…...

文本到语音或视频的构想

₦X8s43Y1iIquVAeF₦ 在Python中&#xff0c;有几个库和模块可以用来实现文本到语音的转换&#xff0c;并且可以生成带有背景音乐的视频。以下是一些可用的库&#xff1a; 1. pyttsx3&#xff1a;这是一个离线文本到语音转换库&#xff0c;它支持多种语音引擎&#xff0c;不依…...

请解释一下数据库的分区和分片?请解释一下数据库的日志和日志的重要性?

请解释一下数据库的分区和分片&#xff1f; 数据库的分区和分片是两种用于提高数据库性能和可扩展性的技术&#xff0c;它们各自具有不同的特点和应用场景。以下是对这两种技术的详细解释&#xff1a; 一、数据库分区 定义&#xff1a; 数据库分区是将一个大型的数据库表或索…...

windows C++-创建数据流代理(二)

完整的数据流演示 下图显示了 dataflow_agent 类的完整数据流网络&#xff1a; 由于 run 方法是在一个单独的线程上调用的&#xff0c;因此在完全连接网络之前&#xff0c;其他线程可以将消息发送到网络。 _source 数据成员是一个 unbounded_buffer 对象&#xff0c;用于缓冲…...

大数据毕业设计选题推荐-个性化图书推荐系统-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…...

【Redis入门到精通九】Redis中的主从复制

目录 主从复制 1.配置主从复制 2.主从复制中的拓扑结构 3.主从复制原理 4.主从复制总结 主从复制 在分布式系统中为了解决单点问题&#xff0c;通常会把数据复制多个副本部署到其他服务器&#xff0c;满⾜故障恢复和负载均衡等需求。Redis 也是如此&#xff0c;它为我们提…...

系统架构设计师论文《论企业应用系统的数据持久层架构设计》精选试读

论文真题 数据持久层&#xff08;Data Persistence Layer&#xff09;通常位于企业应用系统的业务逻辑层和数据源层之间&#xff0c;为整个项目提供一个高层、统一、安全、并发的数据持久机制&#xff0c;完成对各种数据进行持久化的编程工作&#xff0c;并为系统业务逻辑层提…...

策略模式和模板模式的区别

目录 一、实现方式 策略模式 模板模式 二、使用场景 三、优点 四、举例 一、实现方式 策略模式 定义策略接口 Strategy创建具体策略类 OperationAdd、OperationSubtract、OperationMultiply创建一个上下文类 Context&#xff0c;包含一个策略对象的引用&#xff0c;并通…...

【ubuntu】ubuntu20.04安装conda

1.下载 安装参考&#xff1a;https://blog.csdn.net/weixin_44119391/article/details/128577681 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 2.安装 sudo chmod 777 -R ./Anaconda3-5.3.1-Linux-x86_64.sh ./Anaconda3-5.3.1-Linux-x86_64.sh Enter键确认安装…...

使用 SAP ABAP Webdynpro 实现 ABAP Push Channel 的 Web Socket 客户端

本系列前三篇文章,笔者向大家介绍了基于 ABAP Push Channel(简称 APC)的 TCP Socket 服务器端和客户端的编程,以及 Web Socket 的服务器端实现。 使用 ABAP 实现 TCP Socket 编程 (1) - 客户端部分的实现使用 ABAP 实现 TCP Socket 编程 (2) - 服务器端部分的实现使用 ABAP 实…...

15分钟学 Python 第41天:Python 爬虫入门(六)第二篇

Day41&#xff1a;Python爬取猫眼电影网站的电影信息 1. 项目背景 在本项目中&#xff0c;我们将使用 Python 爬虫技术从猫眼电影网站抓取电影信息。猫眼电影是一个知名的电影信息平台&#xff0c;提供了丰富的电影相关数据。通过这个练习&#xff0c;您将深入学习如何抓取动…...

电脑提示d3dcompiler_47.dll缺失怎么修复,仔细介绍dll的解决方法

1. d3dcompiler_47.dll 概述 1.1 定义与作用 d3dcompiler_47.dll 是 Microsoft DirectX 的一个关键组件&#xff0c;作为一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;它在 Windows 操作系统中扮演着至关重要的角色。DirectX 是一套由微软开发的用于处理多媒体…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

ubuntu22.04 安装docker 和docker-compose

首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 &#xff09; 缓存工作原理分析 在了解了本地缓存和远程缓存之后&#xff0c;我们来探究缓存是如何工作的。以计算文件的哈希串为例&#xff0c;若后续运行任务时文件哈希串未变&#xff0c;系统会直接使用对应的输出和制品文件。 2 …...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)

Name&#xff1a;3ddown Serial&#xff1a;FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名&#xff1a;Axure 序列号&#xff1a;8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...