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

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

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

这次引入的技术为Groovy。

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

什么是Gooovy

ApacheGroovy是一种功能强大可选的类型动态语言,具有静态键入和静态编译功能,适用于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;
    }
}

总结

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

(0)

相关推荐

  • jsp-解决文件上传后重启Tomcat时文件自动删除问题

    吼吼,我遇到的问题是这样的...... 我写了一个图片上传的方法,上传时,判断没有这个目录就自动建立一个.然后开始上传图片,能成功,能在服务器找到文件夹和相应的文件.但是,重启项目,或者清理缓存之后,图片和文件夹就会自动被删除,不见了. 先说解决办法吧,后面再分析: 1.把/tomcat/webapps/目录清空,删掉该文件夹的所有内容, 2.修改/tomcat/conf/web.xml文件: <servlet> <servlet-name>default</servlet-

  • Linux系统上实现定时重启Tomcat服务脚本介绍

    目录 一.创建Shell脚本 二.修改文件权限 三.建立定时任务 四.定时任务描述语法 1. 星号(*) 2. 逗号(,) 3. 斜杠(/) 4. 横杠(-) 五.其他 因为使用阿里云部署服务器应用时,Tomcat服务经常由于内存不足出现OutOfMemoryError异常的情况.经常过几天就需要重启一次服务器,更要命的是不知道什么时候会由于内存不足导致无法访问,如果重启不及时严重影响系统体验. 为了解决上述问题,一方面是对tomcat配置做一些优化,网上有很多文章讲解如何优化Tomcat内存设

  • 编写shell脚本实现tomcat定时重启的方法

    最近我在学生价买的低配服务器上部署了一个很吃内存的网页,导致 tomcat 内存经常溢出而崩溃. 于是我上网找了一些教程编写了一个简单的每天定时启动 tomcat 的脚本,特此记录一下 我的环境是 centos 7 1. 在某个目录新建一个 .sh 脚本文件 vim tomcatStart.sh 2. 在 tomcatStart.sh 文件里面写入一下代码 #!/bin/bash /etc/profile tomcatPath="/usr/local/tomcat9" binPath=

  • Linux下重启多个 tomcat 服务的脚本(推荐)

    由于修改tomcat的配置文件或手动操作数据库数据后,tomcat的缓存和redis的缓存很严重,需要经常重启tomcat来释放缓存,经常就是手动重启. # 1.查找tomcat的进程ID ps -ef | grep tomcat # 2.根据路径去查找进程ID,然后逐个杀掉(毕竟一台服务器上面是会有多个不同业务的tomcat在运行.) kill -9 [ID] 刚接触这些命令的时候,会经常的手动去敲命令然后练习加深,久而久之,感觉是在浪费时间(有时候会频繁修改数据库内容). 所以就想着,能不能

  • linux自动重启tomcat脚本分享

    复制代码 代码如下: #!/bin/bash##chkconfig: 35 88 14#description: tomcat auto start script#script by okhelpercase "$1" instart)echo "Here is start script..."JAVA_HOME=/usr/jdk1.6.0_13;export JAVA_HOMEJRE_HOME=$JAVA_HOME/jre;export JRE_HOMEexpor

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

    一招教你如何减少本地调试tomcat重启次数 当我们进行本地调试的时候,代码做了少量改动,却要重启tomcat.如果项目比较小还行,如果项目比较大这个时候重启tomcat的时间就比较长.下面我说的方法将会让你减少tomcat不必要的重启次数. 这次引入的技术为Groovy. 在groovy中书写的代码无需重启tomcat,修改之后需需要重新从入口进入就行了 什么是Gooovy ApacheGroovy是一种功能强大.可选的类型和动态语言,具有静态键入和静态编译功能,适用于Java平台,旨在通过简

  • 用python + hadoop streaming 分布式编程(一) -- 原理介绍,样例程序与本地调试

    MapReduce与HDFS简介 什么是Hadoop? Google为自己的业务需要提出了编程模型MapReduce和分布式文件系统Google File System,并发布了相关论文(可在Google Research的网站上获得: GFS . MapReduce). Doug Cutting和Mike Cafarella在开发搜索引擎Nutch时对这两篇论文做了自己的实现,即同名的MapReduce和HDFS,合起来就是Hadoop. MapReduce的Data flow如下图,原始数据

  • 详述IntelliJ IDEA远程调试Tomcat的方法(图文)

    在调试代码的过程中,为了更好的定位及解决问题,有时候需要我们使用远程调试的方法.在本文中,就让我们一起来看看,如何利用 IntelliJ IDEA 进行远程 Tomcat 的调试. 首先,配置remote: 如上图所示,点击Edit Configurations,进入如下界面: 如上图所示,我们进入了Run/Debug Configurations界面,然后点击左上角的+,选择Remote: 标注 1:运行远程 JVM 的命令行参数: 标注 2:传输方式,默认为Socket: 标注 3:调试模式

  • Dubbo本地调试的几种方式总结

    目录 前言 开发调试阶段 已发布测试阶段 总结 前言 在正常的dubbo开发迭代过程,本地调试是比较常见的情况,一般来说,主要以下两种情况我们需要本地调试 dubbo服务开发调试阶段: 这个阶段我们一般不希望服务被别人访问 dubbo服务已经发布测试环境,但是某个服务出了问题希望本地断点定位: 本地启动的应用不希望对外暴露,但是又需要对特定的服务路由到本地 开发调试阶段 一.禁止注册到配置中心 Dubbo从2.0.8开始增加了协议注册开关,我们可以通过关闭注册开关,关闭服务注册 <dubbo:r

  • 通过vue提供的keep-alive减少对服务器的请求次数

    下面看下通过vue提供的keep-alive减少对服务器的请求次数 VUE2.0中提供了一个keep-alive方法,可以用来缓存组件,避免多次加载相应的组件,减少性能的消耗.比如, 一个页面的数据包括图片.文字等用户都已经加载完了,然后用户通过点击跳转到了另外一个界面.然后从另外一个界面通过返回又回到了原先的界面.如果没有设置的话,那么原先界面的信息就要重新向服务器请求得到.而通过vue提供的keep-alive可以是页面的已经请求的数据得以保存,减少请求的次数,提高用户的体验程度. 缓存组件

  • vue+webpack dev本地调试全局样式引用失效的解决方案

    今天遇到了奇怪的问题,在main.js中引入全局样式,在组件中引用样式时,有些样式失效,有些样式生效.但是神奇的是build打包后样式是正常的. 注册两字没有变成红色..刚开始以为是class名字命名冲突之类的,网上查了很多资料,有提到说css文件中写了中文注释引起的,试过了不行.后来把所有的样式删掉,只剩一个样式,就生效了.好了,罪魁祸首就是空格符.build打包时会有压缩,所以不会有这个问题. 进入[utils.js],添加压缩就好了 const cssLoader = { loader:

  • Spring Cloud Alibaba 本地调试介绍及方案设计

    目录 1 本地调试介绍 2 框架环境 3 方案设计 4 实现要点 5. 总结 附:工具方法 1 本地调试介绍 本地调试: 这里是指在开发环境中,部署了一整套的某个项目或者产品的服务,开发人员开发时,本地会起一个或多个服务,这些服务和开发环境中部署的服务是相同的,这种情况下,一个服务就会有多个实例,大多数微服务中的默认负载均衡策略都是轮询,这些实例会轮流被调用. 为了方便 本地调试,需要提供一种策略,可以指定在负载均衡时,选择哪个实例进行调用.在使用 Nacos 作为注册中心时,可以通过 上线和下

  • 使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程

    目录 1.创建Maven 2.Maven目录和porm.xml配置 3.配置Tomcat服务器 1.创建Maven 2.Maven目录和porm.xml配置 关于java和resources文件夹需要自己创建 这个时候我们看到的只是Maven的Web项目的目录和页面,并没有Spring MVC的东西.接下来我们要做的就是来到pom.xml,编写pom.xml导入Spring MVC所使用的包.注意,我们这里没有选择使用框架支持来导入Spring MVC的包,因为使用Maven来导入更能方便管理包

  • springcloud本地调试feign调用出现的诡异404问题及解决

    目录 本地调试feign调用出现的诡异404问题 问题产生 技术框架 核心代码 诡异的404 心态 springcloud在本地调试的踩坑记录 1.在本地调试的时候 2.修改配置文件中关于eureka的配置 3.还是关于eureka的配置 本地调试feign调用出现的诡异404问题 问题产生 最近在给公司准备做分布式事务框架seata的调研,准备搭建一套demo,根据阿里云官网的案例,我准备搭建一套微服务架子,分别含有business.order.storage三个微服务组成,其中第一个微服务实

  • 如何进行微信公众号开发的本地调试的方法

    微信团队为广大的开发者提供了一个测试账号.该帐号无需公众账号,快速申请接口测试,直接体验和测试公众平台所有高级接口.这么好用的功能,只需要要你有一个手机,手机上安装了一个微信即可. 地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login 登录后,会得到一个微信号,和测试好的相关信息.appID,appsecret. 接口配置信息,js接口安全域名配置按照生产环境的配置即可. 下面重点开始了.已经有了一个可供测试的公众号,

随机推荐