怎么减少本地调试tomcat重启次数你知道吗

一招教你如何减少本地调试tomcat重启次数

当我们进行本地调试的时候,代码做了少量改动,却要重启tomcat。如果项目比较小还行,如果项目比较大这个时候重启tomcat的时间就比较长。下面我说的方法将会让你减少tomcat不必要的重启次数。

这次引入的技术为groovy。

在groovy中书写的代码无需重启tomcat,修改之后需需要重新从入口进入就行了

什么是gooovy

apache groovy是一种功能强大可选的类型动态语言,具有静态键入和静态编译功能,适用于java平台,旨在通过简洁、熟悉和易于学习的语法提高开发人员的工作效率。它与任何java程序顺利集成,并立即为您的应用程序提供强大的功能,包括脚本功能、特定域语言创作、运行时和编译时元编程以及功能编程。和java兼容性强,可以无缝衔接java代码,可以调用java所有的库。

多得不说,直接上代码

pom依赖

<dependency>
    <groupid>org.codehaus.groovy</groupid>
    <artifactid>groovy-jsr223</artifactid>
    <version>3.0.6</version>
</dependency>

controller

@controller
@slf4j
public class scriptaction {
    @autowired
    private groovyeval groovyeval;

    @requestmapping(value = "/script/test")
  	//入参:groovy脚本存放绝对路径、需要传递的参数
    public object scripttest(
            @param(value = "path", required = true) string path,
            @json("@requestbody") @requestbody map<string,object> parammap
            ) {
        try {
            bufferedreader bufferedreader = new bufferedreader(new inputstreamreader(new fileinputstream(path), standardcharsets.utf_8));
            string date;
            stringbuilder stringbuilder = new stringbuilder();
            while((date = bufferedreader.readline()) != null){
                stringbuilder.append(date).append("\n");
            }
            bufferedreader.close();
          //执行脚本获得结果,约定执行的脚本方法名字为solution
            return groovyeval.evalscript(bufferedreader.tostring() , "solution" , new object[]{parammap});
        } catch (filenotfoundexception e) {
            e.printstacktrace();
        } catch (ioexception e) {
            e.printstacktrace();
        }
        return null;
    }
}

service

import com.google.gson.gson;
import groovy.lang.groovyclassloader;
import groovy.lang.groovyobject;
import lombok.extern.slf4j.slf4j;
import org.springframework.beans.beansexception;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware;
import org.springframework.stereotype.component;
import org.springframework.util.collectionutils;
import java.util.map;
import java.util.concurrent.timeunit;

@slf4j
@component
public class groovyeval implements applicationcontextaware {
    private static groovyeval groovyeval;
    private applicationcontext applicationcontext;
    public static <t> t getbean(class<t> cls){
        return groovyeval.applicationcontext.getbean(cls);
    }
    public object evalscript(string script, string methodname, object[] args){
        object scriptobj = this.getscript(script);
        try {
          	//脚本执行入口
          	//返回的数据类型在groovy脚本中自己定义即可,我这里返回的是map
            map<string, object> resultmap = (map<string, object>)((groovyobject)scriptobj).invokemethod(methodname, args);
            if (collectionutils.isempty(resultmap)){
                return null;
            }
            return resultmap.get("data");
        } catch (throwable e) {
            log.error("script eval error !" , e);
        }
        return null;
    }

    private object getscript(string script){
      	//注意!!!本地调试可以不需要加入缓存机制,生产环境需要加入缓存
      	//加载脚本,每执行一次new一个groovycodesource
        class<?> cls = new groovyclassloader().parseclass(script);
        groovyobject groovyobject = null;
        try {
            log.info("load script!");
         groovyobject = (groovyobject)cls.newinstance();
        } catch (illegalaccessexception | instantiationexception e) {
            log.error("load script error ! script : {}" , script , e);
        }
        return groovyobject;
    }

    @override
    public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
        //静态化bean
        this.applicationcontext = applicationcontext;
        groovyeval = this;
    }
}

groovy脚本

testgroovy.groovy

class testgroovy {
    def map<string,object> solution(map<string,object> parammap){
        map<string,object> resultmap = [:];
        /** 获取上层传入的参数 */
        object shopcodes = parammap.get("param");

				//业务逻辑处理。。。。。。
				resultmap.put("data", "resultdata");
        return resultmap;
    }
}

生产环境使用

因为groovy每执行一次脚本,都会生成一个脚本的class对象,这个class对象的名字由 “script” + system.currenttimemillis() +
math.abs(text.hashcode())组成,因此应用到生产环境需要加入缓存。推荐使用高性能缓存:caffeine,

官方介绍caffeine是基于jdk8的高性能本地缓存库,提供了几乎完美的命中率。它有点类似jdk中的concurrentmap,实际上,caffeine中的localcache接口就是实现了jdk中的concurrentmap接口,但两者并不完全一样。最根本的区别就是,concurrentmap保存所有添加的元素,除非显示删除之(比如调用remove方法)。而本地缓存一般会配置自动剔除策略,为了保护应用程序,限制内存占用情况,防止内存溢出。

有兴趣的可以自己去搜索一下,我感觉蛮好用的

@component
public class groovyeval implements applicationcontextaware {
    private static final logger logger = loggerfactory.getlogger(groovyeval.class);
    private static final object source = new object();
    private static groovyeval groovyeval;
    private applicationcontext applicationcontext;
    @autowired
    private alarmthresholdsettingsitemservice alarmthresholdsettingsitemservice;
    public static <t> t getbean(class<t> cls){
        return groovyeval.applicationcontext.getbean(cls);
    }
    private static final cache<object, object> caffeine = caffeine
            .newbuilder()
            .maximumsize(30000)
            //三天不用直接 gc
            .expireafteraccess(72 , timeunit.hours)
            .build();
    public map lookup(){
        return caffeine.asmap();
    }
    public object evalscript(string script,string methodname,object[] args) {
        object scriptobj = this.getscript(script);
        if(scriptobj != null){
            try{
                //统一返回 map<string,object>   { "data" : object }
                map<string, object> resultmap = (map<string, object>) ((groovyobject) scriptobj).invokemethod(methodname, args);
                if(collectionutils.isempty(resultmap)){
                    return null;
                }
                return resultmap.get("data");
            }catch (throwable e){
                logger.error("script eval error !" , e);
            }
        }
        return null;
    }
  	//脚本加入缓存
    private object getscript(string script){
        //唯一标记
        string cachekey = digestutils.md5hex(script);
        return caffeine.get(cachekey, new function<object, object>() {
            @override
            public object apply(object key) {
                //避免变动导致并发问题
                synchronized (source){
                    class<?> cls = new groovyclassloader().parseclass(script);
                    groovyobject gobj = null;
                    try {
                        logger.info("load script !");
                        gobj = (groovyobject) cls.newinstance();
                    } catch (instantiationexception | illegalaccessexception e) {
                        logger.error("load script error ! script : {}" , script , e);
                    }
                    return gobj;
                }
            }
        });
    }
    @override
    public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
        //静态化 bean
        this.applicationcontext = applicationcontext;
        groovyeval = this;
    }
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注www.887551.com的更多内容!     

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐