Groovy在Java中充当的重要角色

/ 默认分类 / 0 条评论 / 918浏览

Groovy在Java中充当的重要角色

一.介绍

随着脚本语言的兴起,类似java,go,c++这种编译型或解释型的语言再一些代码逻辑变化率较高的场景下显得力不从心.我在工作和学习过程中也遇到过类似的情况,下面给大家介绍一种简单的场景

在一些复杂的业务逻辑背景下,一些代码往往会变得很是复杂,很多的逻辑判断,开关值,字符串拆分,大小比较,类型判定等等,需求变化较小还好,如果一旦发生业务需求变化频繁,那么无疑将会是一场噩梦,作为java程序员,我深有体会,你需要不断的编译打包部署发布,如果你的团队已经是持续交付自动部署这样还好,如果是手动打包发布,那么应该不用多说了,那么这种情况下,其实我们可以想到的解决方案还是很多的,下面是我说知道的几种处理方式:

1. 规则引擎

了解过规则引擎的小伙伴应该都知道它的强大之处,我们可以将静态的业务代码写活,将一些开关值交由外部决定,还可以写一些简单的逻辑脚本来控制代码的运行,在一些场景中,尤其是企业级应用(往往会随着时间的变化而不断改变)可能会有意想不到的效果,例如Drools,这是我使用过的java中唯一的一个规则引擎库,网上也有很多关于它的文档,上手很快

2. 外部配置文件

最初使用外部配置是在启动SSM(SSH)应用程序的时候,经历过那个黑暗时代或者还出于这个黑暗时代的小伙伴应该比较清楚,我们会将一些常用的配置写在例如properties文件中,在项目启动时使用java中提供的properties解析的api来进行文件加载,当然自从2016年诞生了springboot之后,外部配置文件的方式更是被玩到了极致

3. 配置中心

配置中心真是个好东西.阿波罗,nacos,springcloudConfig,配置中心一般支持配置的热更新,拿我比较了解的nacos来说,其中的/nacos/v1/cs/configs/listener,改接口就支持配置的热更新,我们可以在程序中使用@refreshScope来更新程序中的变量,当然也可以通过编写监听器来自行刷新内存中的数据,所以借助配置中心,其实我们也可以将一些经常变化的值写在外部.这样看来,在某种程度上,Zookeeper也可以实现这样的功能(文件修改的通知机制,类似于使用zookeeper实现分布式锁)

关于nacos的实时刷新我会单独写成博客,在这之前大家可以了解下阿里的云产品,ACM+NACOS,不得不说,阿里是真的牛批

4. 脚本程序

最后一种方法,我觉得也是最适合我的,那就是通过执行脚本程序来保证代码修改的时效性,当然说到这里,我想大家能够想到的脚本很多了,反正我满脑子都是 lua,js,python,没错,java这完整的生态肯定是支持执行引擎的,但是使用的同学应该就会知道,在使用这些脚本的时候,不乏会遇到下列问题:

解决了还好,如果你没解决,并且baidu,google之后一大把的copy文章,关键是还没有解决问题,这TM就十分恼火了,这个时候应该怎么办呢?写一个java程序,然后在需要变更的时候javac,然后拷贝替换class文件,但是现在都啥时代了,咱们都是java -jar.那么这个时候我想你很需要一个工具人,Groovy正式登场, 了解过groovy的小伙伴会知道,其实这门语言早在2003年就已经诞生了,并且现在的idea本省就集成了Groovy的插件,我们可以不用安装groovy的环境便可以在本地及其上运行我们的groovy代码,比如这样:

print 'blog.whatsoft.cn'

Connected to the target VM, address: '127.0.0.1:49836', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:49836', transport: 'socket'
blog.whatsoft.cn
Process finished with exit code 0

二. Groovy上手

这里我写了一个求阶乘的程序来演示:

/**
 * @author zh@whatsoft.cn
 * @date 2020/12/19 - 14:48
 */

static BigDecimal test(BigDecimal num)
{
    BigDecimal bd1 = new BigDecimal(1)
    if(num < 0)
        throw new RuntimeException();
    if(num == 1)
        return 1;
    return num.multiply(test (num.subtract(bd1)))
}

static void main(args){

    BigDecimal inputNum = new BigDecimal(100)
    def result = test(inputNum)
    print inputNum + '的阶乘是:' + result

}

执行结果:

Connected to the target VM, address: '127.0.0.1:50003', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:50003', transport: 'socket'
100的阶乘是:93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Process finished with exit code 0

亲爱的下伙伴呀,快康康这几行代码呀,有木有惊艳到你呀,这踏马多舒服呀,没想到有朝一日我大java也能这么搞

三.Groovy在springboot项目中的运行

之前一直在做一个在线影视的项目,其中有一个业务场景是这样的,因为这些影视资源都是我写的python爬虫获取的,并且为了方便我没有统一修改得到的电影的title,但是这样也带来了一个麻烦,比如我爬去了第一个网站的资源后,名字可能是统一的,那么如果我再爬去另外一个网站的数据,那么名字可能又变了,这个时候我的数据库中就会有两种格式的电影的title,这样下去,我的数据库中的电影title的格式非常之多(是的,没错我的确爬了很多数据,嘻嘻嘻(正规电影,收集与互联网)),这个时候如果我想在网站中统一显示标题,我可以在java程序中统一处理,在取出这一步操作的时候对标题的几种情况做统一处理,但是这样的话我的代码会经常需要改动,每次改动我都需要重新打包上传发布(这里我没有搭建jeenkins环境,因为服务器资源有限,可以考虑在本地搭建)

这个时候我将这部分对标题的处理写在了外部,利用groovy文件来处理

        <dependency>
            <artifactId>groovy-all</artifactId>
            <groupId>org.codehaus.groovy</groupId>
            <version>${groovy.version}</version>
            <scope>compile</scope>
        </dependency>

下面的代码就可以帮你运行你的groovy程序

    @ApiOperation(value = "/test1", notes = "当前测试")
    @GetMapping("/test1")
    @ResponseBody
    public R<Object> test1(String id) throws IOException, IllegalAccessException, InstantiationException {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ClassLoader parent = this.getClass().getClassLoader();
        GroovyClassLoader loader = new GroovyClassLoader(parent);
        Class groovyClass = loader.parseClass(
                new File("D:/TestGroovy.groovy")
        );
        GroovyObject groovyObject= (GroovyObject)groovyClass.newInstance();
        Long result =  (Long) groovyObject.invokeMethod("test1", null);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        return R.ok().data(result);
    }

这里我们可以任意修改groovy程序,然后保存文件即可

通过多次调用并且查看耗时我发现,groovy在性能上和java基本一致,深入了解过的小伙伴应该知道,其实groovy在底层也是一个类对象,运行在jvm上的字节码文件