把java接口写在数据库里(groovy)

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

  1. 引入依赖

xml

代码解读

复制代码

<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.5.16</version> <type>pom</type> </dependency>

  1. 创建测试接口

csharp

代码解读

复制代码

public interface InterfaceA { /** * 执行规则 */ void testMethod(); }

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

java

代码解读

复制代码

@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()) } }

  1. mysql数据库中建个表groovy_script

整理了一份Java面试题。包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

 需要全套面试笔记的【点击此处】即可免费获取

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

swift

代码解读

复制代码

@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); } }

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

typescript

代码解读

复制代码

@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; } } }

  1. 测试
 

less

代码解读

复制代码

@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"; } }

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

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

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值