java多变接口

业务复杂多变?那把接口写在数据库里吧,修改随改随用!本文使用了Groovy脚本,不了解的可以自行了解,直接上菜。

引入依赖
org.codehaus.groovy groovy-all 2.5.16 pom
创建测试接口

public interface InterfaceA {

/*** 执行规则*/
void testMethod();

}

resource目录下创建.groovy实现上面的接口

@Slf4j
class GroovyInterfaceAImpl implements InterfaceA {

@Override
void testMethod() {log.info("我是groovy编写的InterfaceA接口实现类中的接口方法")GroovyScriptService groovyScriptService = SpringUtils.getBean(GroovyScriptService.class)GroovyScript groovyScript = Optional.ofNullable(groovyScriptService.getOne(new QueryWrapper<GroovyScript>().eq("name", "groovy编写的java接口实现类").eq("version", 1))).orElseThrow({ -> new RuntimeException("没有查询到脚本") })log.info("方法中进行了数据库查询,数据库中的groovy脚本是这个:{}", "\n" + groovyScript.getScript())
}

}

mysql数据库中建个表groovy_script

image.png 5. 将刚才编写的.groovy文件内容存入数据库

@RunWith(SpringRunner.class)
@SpringBootTest
public class GroovyTest {

@Resource
private GroovyScriptService groovyScriptService;@Test
public void test01() {GroovyScript groovyScript = new GroovyScript();groovyScript.setScript("package groovy\n" +"\n" +"import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper\n" +"import com.demo.groovy.entity.GroovyScript\n" +"import com.demo.groovy.service.GroovyScriptService\n" +"import com.demo.groovy.service.InterfaceA\n" +"import com.demo.groovy.util.SpringUtils\n" +"import groovy.util.logging.Slf4j\n" +"\n" +"\n" +"@Slf4j\n" +"class GroovyInterfaceAImpl implements InterfaceA {\n" +"\n" +"    @Override\n" +"    void testMethod() {\n" +"        log.info("我是groovy编写的InterfaceA接口实现类中的接口方法")\n" +"        GroovyScriptService groovyScriptService = SpringUtils.getBean(GroovyScriptService.class)\n" +"        GroovyScript groovyScript = Optional.ofNullable(groovyScriptService.getOne(new QueryWrapper<GroovyScript>()\n" +"                .eq("name", "groovy编写的java接口实现类")\n" +"                .eq("version", 1))).orElseThrow({ -> new RuntimeException("没有查询到脚本") })\n" +"        log.info("方法中进行了数据库查询,数据库中的groovy脚本是这个:{}", "\n" + groovyScript.getScript())\n" +"    }\n" +"}");groovyScript.setVersion(1);groovyScript.setName("groovy编写的java接口实现类");groovyScriptService.save(groovyScript);
}

}

从数据读取脚本,GroovyClassLoader加载脚本为Class(注意将Class对象进行缓存)

@Service(“groovyScriptService”)
@Slf4j
public class GroovyScriptServiceImpl extends ServiceImpl<GroovyScriptServiceMapper, GroovyScript> implements GroovyScriptService {

private static final Map<String, Md5Clazz> SCRIPT_MAP = new ConcurrentHashMap<>();@Override
public Object getInstanceFromDb(String name, Integer version) {//查询脚本GroovyScript groovyScript = Optional.ofNullable(baseMapper.selectOne(new QueryWrapper<GroovyScript>().eq("name", name).eq("version", version))).orElseThrow(() -> new RuntimeException("没有查询到脚本"));//将groovy脚本转换为java类对象Class<?> clazz = getClazz(name + version.toString(), groovyScript.getScript());Object instance;try {instance = clazz.newInstance();} catch (Exception e) {throw new RuntimeException(e);}return instance;
}private Class<?> getClazz(String scriptKey, String scriptText) {String md5Hex = DigestUtil.md5Hex(scriptText);Md5Clazz md5Script = SCRIPT_MAP.getOrDefault(scriptKey, null);if (md5Script != null && md5Hex.equals(md5Script.getMd5())) {log.info("从缓存获取的Clazz");return md5Script.getClazz();} else {CompilerConfiguration config = new CompilerConfiguration();config.setSourceEncoding("UTF-8");GroovyClassLoader groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(), config);try {Class<?> clazz = groovyClassLoader.parseClass(scriptText);SCRIPT_MAP.put(scriptKey, new Md5Clazz(md5Hex, clazz));groovyClassLoader.clearCache();log.info("groovyClassLoader parseClass");return clazz;} catch (Exception e) {throw new RuntimeException(e);} finally {try {groovyClassLoader.close();} catch (IOException e) {log.error("close GroovyClassLoader error", e);}}}
}@Data
private static class Md5Clazz {private String md5;private Class<?> clazz;public Md5Clazz(String md5, Class<?> clazz) {this.md5 = md5;this.clazz = clazz;}
}

}

测试

@RestController
@RequestMapping(“/test”)
@Slf4j
public class GroovyTestController {

@Resource
private GroovyScriptService groovyScriptService;@GetMapping("")
public String testGroovy() {InterfaceA interfaceA = (InterfaceA) groovyScriptService.getInstanceFromDb("groovy编写的java接口实现类", 1);interfaceA.testMethod();return "ok";
}

}

接口方法被执行。想要修改接口的话在idea里面把groovy文件编辑好更新到数据库就行了,即时生效。

image.png

本文简单给大家提供一种思路,希望能对大家有所帮助,如有不当之处还请大家指正。本人之前在项目中用的比较多的是Groovyshell,执行的是一些代码片段,而GroovyClassLoader则可以加载整个脚本为Class,Groovy对于java开发者来说还是比较友好的,上手容易。

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

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

相关文章

设计模式基础概念(行为模式):责任链模式(Chain Of Responsibility)

概述 责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链进行发送。 收到请求后&#xff0c; 每个处理者均可对请求进行处理&#xff0c; 或将其传递给链上的下个处理者。 该模式建议你将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于…

centos7 安装python3.9.4,解决import ssl异常

本篇文章介绍如何在centos7中安装python3.9.4(下文简称python3)&#xff0c;解决python3安装后import ssl模块失败问题&#xff0c;为什么我要在centos7中安装python呢&#xff0c;因为我需要在服务器中跑python数据处理脚本。 安装python3同时解决import ssl模块失败问题总共包…

【分布式技术】分布式序列算法Snowflake深入解读

文章目录 概述Snowflake算法的构成&#xff1a;Snowflake算法的特点&#xff1a;Snowflake算法存在的问题&#xff1a; &#x1f50d; 雪片算法在分布式系统中是如何保证ID的唯一性和有序性的&#xff1f;唯一性&#xff08;Uniqueness&#xff09;有序性&#xff08;Orderline…

纯CSS实现UI设计中常见的丝带效果(5)

原文传送门&#xff1a;纯CSS实现UI设计中常见的丝带效果 网页中的丝带效果在设计中扮演着多重角色&#xff0c;其作用可以归纳为以下几个方面&#xff1a; 视觉吸引与装饰 增强视觉吸引力&#xff1a;丝带效果以其独特的形态和色彩&#xff0c;能够迅速吸引用户的注意力&…

TP41Y阀套式排污阀

在现代工业领域中&#xff0c;阀门作为一种关键的控制元件&#xff0c;广泛应用于各种流体系统中。其中&#xff0c;TP41Y阀套式排污阀以其独特的设计和优异的性能&#xff0c;在石油、天然气、化工等行业中占据了重要的地位。本文将对TP41Y阀套式排污阀进行详细的专业解析&…

Python | Leetcode Python题解之第522题最长特殊序列II

题目&#xff1a; 题解&#xff1a; class Solution:def findLUSlength(self, strs: List[str]) -> int:def is_subseq(s: str, t: str) -> bool:pt_s pt_t 0while pt_s < len(s) and pt_t < len(t):if s[pt_s] t[pt_t]:pt_s 1pt_t 1return pt_s len(s)ans …

Flink SQL中Changelog事件乱序处理原理

本文围绕Flink SQL实时数据处理中的Changelog事件乱序问题&#xff0c;分析了Flink SQL中Changelog事件乱序问题的原因&#xff0c;并提供了解决方案以及处理Changelog事件乱序的建议。以帮助您更好地理解Changelog的概念和应用&#xff0c;更加高效地使用Flink SQL进行实时数据…

HTML CSS

目录 1. 什么是HTML 2. 什么是CSS ? 3. 基础标签 & 样式 3.1 新浪新闻-标题实现 3.1.1 标题排版 3.1.1.1 分析 3.1.1.2 标签 3.1.1.3 实现 3.1.2 标题样式 3.1.2.1 CSS引入方式 3.1.2.2 颜色表示 3.1.2.3 标题字体颜色 3.1.2.4 CSS选择器 3.1.2.5 发布时间字…

Open3D(C++) 基于法线微分的点云分割

目录 一、算法原理二、代码实现三、结果展示1、原始点云2、分割结果本文由CSDN点云侠原创,原文链接,首发于:2024年11月1日。 一、算法原理 使用C++版本Open3D复现的PCL里边基于法线微分的分割算法。PCL 基于法线微分(DoN)的点云分割【2024最新版】。网上有大量相关算法介…

Xcode 15.4 运行flutter项目,看不到报错信息详情?

Xcode升级后&#xff0c;遇到了奇怪的事情&#xff1a; 运行flutter项目&#xff0c;左侧栏显示有报错信息&#xff0c;但是点击并没有跳转出具体的error详情。【之前都会自己跳转出来的&#xff0c;升级后真的是无厘头】 方案&#xff1a; 点击左侧导航栏最右边的图标——>…

Java基础(8)异常

目录 1.前言 2.正文 2.1异常的引入 2.2异常的类型 2.2.1编译时异常 2.2.2运行时异常 2.3区分Exception与Error 2.4异常的声明&#xff0c;抛出与捕获 2.4.1throw 2.4.2throws 2.4.2try-catch与finally 2.6自定义异常 3.小结 1.前言 哈喽大家好啊&#xff0c;Java…

解决rabbitmq-plugins enable rabbitmq_delayed_message_exchange :plugins_not_found

问题&#xff1a;我是在docker-compose环境部署的 services:rabbitmq:image: rabbitmq:4.0-managementrestart: alwayscontainer_name: rabbitmqports:- 5672:5672- 15672:15672environment:RABBITMQ_DEFAULT_USER: rabbitRABBITMQ_DEFAULT_PASS: 123456volumes:- ./rabbitmq/…

JavaScript语法基础——变量,数据类型,运算符和程序控制语句(小白友好篇,手把手教你学会!)

一、JavaScript概述 JavaScript是一种高级编程语言&#xff0c;常用于网页开发和服务器端应用程序。它是一种动态类型语言&#xff0c;可以在浏览器中直接解释执行&#xff0c;而不需要编译。 脚本&#xff08;Script&#xff09;是一种与计算机程序相关的指令集或代码块&…

Android 中View.post的用法

View.post 是 Android 中 View 类的一个方法&#xff0c;它允许我们在视图 (View) 完成其布局 (Layout) 阶段后&#xff0c;将一个任务放到主线程的消息队列中&#xff0c;以便稍后执行。这种方式通常用于确保在 View 的尺寸、位置等布局属性已经计算完成后执行某些操作。 基本…

健康之路押注医药零售:毛利率下滑亏损扩大,医疗咨询人次大幅减少

《港湾商业观察》黄懿 2024年9月13日&#xff0c;健康之路股份有限公司&#xff08;下称“健康之路”&#xff09;再次递表港交所&#xff0c;建银国际为独家保荐人。健康之路国内运营主体为健康之路&#xff08;中国&#xff09;信息技术有限公司和福建健康之路信息技术有限公…

在pycharm中使用sqllite

在pycharm中使用sqllite sqllite 简介 SQLite 是一个开源的、轻量级的、关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它设计用于嵌入到应用程序中&#xff0c;并且可以在无需外部服务器进程的情况下运行。SQLite 提供了完整的 SQL 语言支持&#xff0c;允…

游戏启动失败:8种修复xinput1_3.dll错误的几种方法教程,轻松解决xinput1_3.dll错误

当你准备好在一天的工作后放松一下&#xff0c;启动你最爱的游戏&#xff0c;却突然收到一个“xinput1_3.dll 丢失”的错误消息&#xff0c;这无疑是令人沮丧的。幸运的是&#xff0c;xinput1_3.dll丢失问题通常可以通过几个简单的步骤来解决。本文将详细介绍这些步骤&#xff…

多线程和线程同步基础篇学习笔记(Linux)

大丙老师教学视频&#xff1a;10-线程死锁_哔哩哔哩_bilibili 目录 大丙老师教学视频&#xff1a;10-线程死锁_哔哩哔哩_bilibili 线程概念 为什么要有线程 线程和进程的区别 在处理多任务的时候为什么线程数量不是越多越好? Linux提供的线程API 主要接口 线程创建 pth…

DDRPHY数字IC后端设计实现系列专题

在对 LPDDR3 物理层接口模块进行后端设计之前&#xff0c;需要对该模块的功能结 构以及后端物理设计流程的相关理论进行深入的分析和研究。本章第一节详细分 析了本次 LPDDR3 物理层接口模块的结构&#xff0c;为该模块的布图布局的合理规划奠 定了理论基础&#xff0c;并且分析…

【笔记】数据结构与算法

参考链接&#xff1a;数据结构(全) 参考链接&#xff1a;数据结构与算法学习笔记 一些PPT的整理&#xff0c;思路很不错&#xff0c;主要是理解角度吧&#xff0c;自己干啃书的时候结合一下会比较不错 0.总论 1.数据 注&#xff1a;图是一种数据结构&#xff01;&#xff01;…