欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-02 18:42:07
一招教你如何减少本地调试tomcat重启次数当我们进行本地调试的时候,代码做了少量改动,却要重启tomcat。如果项目比较小还行,如果项目比较大这个时候重启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;
    }
}

总结

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