利用jrebel与arthas在centos7 springboot热部署

news2024/11/18 21:35:32

jrebel 热部署

jrebel在本地是可以class xml一起热部署,但是远程热部署xml不行,所以用arthas代替去热部署xml

1.jrebel 反向代理

因为jrebel是收费插件,所以要高一些小动作咱们才能‘正常’使用,当然你也可以拿别人代理好的操作,但别人跑路了你就又要找,索性自己搞吧
在这里插入图片描述
上面那个是linux,下面是win10启动自己选
win下面双击,linux的按下面命令启动

./ReverseProxy_linux_amd64 &

#默认代理8888端口,可以运行一下命令指定端口:
./ReverseProxy_linux_amd64 -l "ip:port" &

服务器安装JRebel并激活
根据的idea下载对应版本 https://www.jrebel.com/products/jrebel/download/prev-releases
我用的是idea2020.3.3,下面没有,只有2020.3.2,要是没你的idea版本,就选个近似的吧
在这里插入图片描述
centos7激活
emmmm,这个ip:port/guid,见下面方法,和idea一样

./activate.sh http://ip:port/guid 你的邮箱地址

在这里插入图片描述

2.idea插件

安装这两个插件,重启idea
在这里插入图片描述
点击 右边 change
在这里插入图片描述
ip:端口,ip就看你怎么反向代理的时候开的了,端口默认8888,后面的验证码可以在下面网站获取,下面那个邮箱随便写
https://www.guidgen.com/
在这里插入图片描述

在这里插入图片描述
有多个选择,就点一下这个,然后界面就剩它一个了,防止Jrebel本地热更新失效,开启Jrebel离线模式
在这里插入图片描述
激活成功
在这里插入图片描述

3.jrebel使用

现在界面就有这两个热启动按钮了
在这里插入图片描述
启动配置选这个
在这里插入图片描述
这个就不用重启部署了,这个按钮刷新项目快捷键Ctrl+shift+F9
在这里插入图片描述

4.jrebel远程热更新

在这里插入图片描述

在这里插入图片描述

远程服务器上安装JRebel

# 下载安装包
curl -O http://dl.zeroturnaround.com/jrebel-stable-nosetup.zip
# 解压下载文件
unzip jrebel-stable-nosetup.zip

# 将自己的激活URL和邮箱地址替换下面的指令参数 url就是ip 不用端口
bash jrebel/bin/activate.sh  url email

# 为了安全起见,防止其他人通过远程连接到JRebel篡改程序,我们为JRebel设置一个密码。
java -jar jrebel/jrebel.jar -set-remote-password 12345678

在这里插入图片描述
在这里插入图片描述

生成启动指令
根据你自己实际情况,下面那个绿的java就是要去centos7执行的命令,紫色参数根据你自己情况修改
这里有两个地方需要修改,一个是-agentpath:就是刚刚在服务器上安装的JRebel目录,另外一个就是自己的jar包名称

java "-agentpath:/root/www/jrebel/lib/libjrebel64.so" -Drebel.remoting_plugin=true -jar demo-0.0.1-SNAPSHOT.jar

在这里插入图片描述
然后在远程服务器上执行命令启动服务,启动成功,控制台会输出JRebel的信息

在这里插入图片描述
每次要远程热更新就点击这个
在这里插入图片描述
右下角出现这个就是成功了,请求接口看看是不是成功没,对xml无效
在这里插入图片描述

5.jrebel 远程调试

在这里插入图片描述
添加远程调试

在这里插入图片描述
ok,在服务器上执行这个命令,按实际自己拼接

java "-agentpath:/root/www/jrebel/lib/libjrebel64.so" -Drebel.remoting_plugin=true -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar demo-0.0.1-SNAPSHOT.jar

成功了,打断点调试吧
在这里插入图片描述

arthas 热部署

centos7 安装java
yum安装的java-1.8.0-openjdk 没有 javac ,需要安装 devel 版本。只能先卸载yum安装的jdk,重新安装devel 版本的jdk了。
没javac 用不了arthas

#查看目前系统中的jdk
rpm -qa | grep jdk

#yum卸载  将上面全部删除,删完再次查询,删到没有为止
yum -y remove xxx

yum install -y java-1.8.0-openjdk-devel.x86_64

1.idea操作

项目中随便地方,两个文件复制进去
在这里插入图片描述

package com.gao.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextProvider implements ApplicationContextAware {
    private static ApplicationContext context;

    public ApplicationContext getApplicationContext() {
        return context;
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        context = ctx;
    }
}
package com.gao.common;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * mapper xml 文件重新加载
 *
 * @author 汪小哥
 * @date 01-05-2021
 */
@Slf4j
@Component
public class MybatisMapperXmlFileReloadService {

    private List<SqlSessionFactory> sqlSessionFactoryList;


    public MybatisMapperXmlFileReloadService(List<SqlSessionFactory> sqlSessionFactoryList) {
        this.sqlSessionFactoryList = sqlSessionFactoryList;
    }

    /**
     * 重新 加载mapper xml  【这里可以使用arthas 进行调用远程增强】
     * eg  ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("mybatisMapperXmlFileReloadService").reloadAllSqlSessionFactoryMapper("/root/xxx.xml")' -c xxx
     *
     * @param mapperFilePath
     * @return
     */
    public boolean reloadAllSqlSessionFactoryMapper(String mapperFilePath) {
        if (CollectionUtils.isEmpty(sqlSessionFactoryList)) {
            log.warn("not find SqlSessionFactory bean");
            return false;
        }

        Path path = Paths.get(mapperFilePath);
        if (!Files.exists(path)) {
            log.warn("mybatis reload mapper xml not exist ={}", mapperFilePath);
            return false;
        }

        AtomicBoolean result = new AtomicBoolean(true);

        // 删除mapper 缓存 重新加载
        sqlSessionFactoryList.parallelStream().forEach(sqlSessionFactory -> {
            Configuration configuration = sqlSessionFactory.getConfiguration();
            if (!this.removeMapperCacheAndReloadNewMapperFile(path, configuration)) {
                log.warn("reload new mapper file fail {}", path.toString());
                result.set(false);
            }
        });
        return result.get();
    }


    private Object readField(Object target, String name) {
        Field field = ReflectionUtils.findField(target.getClass(), name);
        ReflectionUtils.makeAccessible(field);
        return ReflectionUtils.getField(field, target);
    }

    /**
     * 删除老的mapper 缓存 加载新的mapper 文件
     *
     * @param watchPath
     * @param configuration
     * @return
     */
    private boolean removeMapperCacheAndReloadNewMapperFile(Path watchPath, Configuration configuration) {
        try (InputStream fileInputStream = Files.newInputStream(watchPath)) {
            XPathParser context = new XPathParser(fileInputStream, true, configuration.getVariables(), new XMLMapperEntityResolver());
            XNode contextNode = context.evalNode("/mapper");
            if (null == contextNode) {
                return false;
            }
            String namespace = contextNode.getStringAttribute("namespace");
            if (namespace == null || namespace.isEmpty()) {
                throw new BuilderException("Mapper's namespace cannot be empty");
            }

            this.removeOldMapperFileConfigCache(configuration, contextNode, namespace);
            this.addNewMapperFile(configuration, watchPath, namespace);
            return true;
        } catch (Exception e) {
            log.warn("load fail {}", watchPath.toString(), e);
        }
        return false;
    }

    /**
     * 删除老的mapper 相关的配置文件
     *
     * @param configuration
     * @param mapper
     * @param namespace
     * @see XMLMapperBuilder#configurationElement
     */
    private void removeOldMapperFileConfigCache(Configuration configuration, XNode mapper, String namespace) {
        String xmlResource = namespace.replace('.', '/') + ".xml";
        ((Set<?>) this.readField(configuration, "loadedResources")).remove(xmlResource);
        for (XNode node : mapper.evalNodes("parameterMap")) {
            String parameterMapId = this.resolveId(namespace, node.getStringAttribute("id"));
            ((Map<?, ?>) this.readField(configuration, "parameterMaps")).remove(parameterMapId);
        }
        for (XNode node : mapper.evalNodes("resultMap")) {
            String resultMapId = this.resolveId(namespace, node.getStringAttribute("id"));
            ((Map<?, ?>) this.readField(configuration, "resultMaps")).remove(resultMapId);
        }
        for (XNode node : mapper.evalNodes("sql")) {
            String sqlId = this.resolveId(namespace, node.getStringAttribute("id"));
            ((Map<?, ?>) this.readField(configuration, "sqlFragments")).remove(sqlId);
        }
        for (XNode node : mapper.evalNodes("select|insert|update|delete")) {
            String statementId = this.resolveId(namespace, node.getStringAttribute("id"));
            ((Map<?, ?>) this.readField(configuration, "mappedStatements")).remove(statementId);
        }
    }

    /**
     * 加载新的mapper 文件
     *
     * @param configuration
     * @param watchPath
     * @param namespace
     */
    private void addNewMapperFile(Configuration configuration, Path watchPath, String namespace) throws IOException {
        try (InputStream fileInputStream = Files.newInputStream(watchPath)) {
            String xmlResource = namespace.replace('.', '/') + ".xml";
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(fileInputStream, configuration,
                    xmlResource,
                    configuration.getSqlFragments());
            xmlMapperBuilder.parse();
        }

    }


    private String resolveId(String namespace, String id) {
        return namespace + "." + id;
    }
}

安装插件
在这里插入图片描述
修改你自己的包
在这里插入图片描述
我选的阿里云oss的,会自动上传拉取,热更新,自己去oss申请配置吧
在这里插入图片描述
要热部署的xml选择
在这里插入图片描述
出现这个,插件自动帮你复制好了,直接去服务器上执行这个命令就可以热部署了
在这里插入图片描述

2.服务器上操作

服务器上执行以下命令,不然会失败

yum install telnet
yum install --assumeyes unzip
#查看当前用户是什么
who am i
#我的是root,ah.sh见下图
sudo su root && ./as.sh
#等下从阿里oss拉取的xml,会自动放在/root/opt/arthas下面,所以给/root 读写权限
sudo chmod -R 777 /root

#然后执行上面idea 复制的命令

在这里插入图片描述
oss拉取的xml,下面全部都是
在这里插入图片描述
执行idea复制的ml,中途要 -l回车 再执行下面
在这里插入图片描述
成功替换(ps 注意 重启项目热更新的全部失效!!!!!!!!包括jerbel的)
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

并发基础(五):ThreadPoolExecutor源码解析

尺有所短&#xff0c;寸有所长&#xff1b;不忘初心&#xff0c;方得始终。 请关注公众号&#xff1a;星河之码 在JDK提供的几种线程池技术&#xff0c;除了JDK8新加的newWorkStealingPool之外&#xff0c;其余的几种线程池都是通过ThreadPoolExecutor 来实现线程池技术&#x…

本周大新闻|FDA公布XR认证医疗名单,索尼推数字孪生平台Mapray

本周大新闻&#xff0c;AR方面&#xff0c;苹果首款MR头显或推迟至2023年下半年发布&#xff1b;FDA官网公布经过认真的AR/VR医疗方案名单&#xff1b;索尼预测AR/VR光学发展路径&#xff1b;索尼公布3D数字孪生平台Mapray&#xff1b;索尼公布ToF AR SDK。 VR方面&#xff0c…

Docker简介与安装

一、Docker 简介 1.1 为什么选择Docker? 更高效的利用系统资源更快速的启动时间一致的运行环境持续交付和部署更轻松的迁移更轻松的维护和扩展 1.2 Docker组件 1.2.1 Docker服务器与客户端 Docker是一个客户端-服务器&#xff08;cs&#xff09;架构程序。Docker客户端只…

linux下共享内存和消息队列实现多进程间数据收发

linux下进程通信的方式有很多&#xff0c;共享内存&#xff0c;消息队列&#xff0c;管道等。共享内存可以传输大量数据&#xff0c;但是多个进程同时读取共享内存就会出现脏读&#xff0c;可以借助消息队列实现多进程消息发送和接收。这种组合方式在实际开发中应用还是很多的&…

计算机网络复习(五)

考点&#xff1a;UDP 拥塞控制 TCP三次握手四次握手 P247 熟知端口号 P215 TCP报文计算5-36.假定TCP采用一种仅使用线性增大和乘法减小的简单拥塞控制算法&#xff0c;而不使用慢开始。发送窗口不采用字节为计算单位&#xff0c;而是使用分组pkt为计算单位。在一开始发送窗口为…

时序预测 | MATLAB实现VAR和GARCH时间序列预测

时序预测 | MATLAB实现VAR和GARCH时间序列预测 目录 时序预测 | MATLAB实现VAR和GARCH时间序列预测预测效果基本介绍程序设计VARGARCH参考资料预测效果 基本介绍 机器学习可其用于时间序列问题的分类和预测。在探索时间序列的机器学习方法之前,尝试统计时间序列预测方法,它列…

SQL开窗函数之percent_rank、first_value、nth的用法

开窗函数 当我们需要进行一些比较复杂的子查询时&#xff0c;聚合函数就会非常的麻烦&#xff0c;因此可以使用开窗函数进行分组再运用函数查询。窗口函数既可以显示聚集前的数据&#xff0c;也可以显示聚集后的数据&#xff0c;可以在同一行中返回基础行的列值和聚合后的结果…

微信小程序|反编译

一、下载网易模拟器 MuMu模拟器官网_安卓模拟器_网易手游模拟器 根据自己的系统选择对应的软件进行安装。 安装成功后,如下: 二、再模拟器上面安装对应的软件(微信、RE文件管理器) 1. 打开应用中心,搜索 RE文件管理器和微信,分别进行下载 2. 打开微信,输入帐号进行…

Windows 文件比较工具winmerge

今天下载了一个非常强大的文件比较工具推荐给大家。开源免费的&#xff01;&#xff01;&#xff01; 什么是WinMerge&#xff1f; WinMerge是Windows的开源差异和合并工具。WinMerge 可以比较文件夹和文件&#xff0c;以易于理解和处理的可视文本格式呈现差异。 官方下载地…

代码随想录算法训练营第六十天| LeetCode84. 柱状图中最大的矩形

一、LeetCode84. 柱状图中最大的矩形 1&#xff1a;题目描述&#xff08;84. 柱状图中最大的矩形&#xff09; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大…

学习Typescript(第二弹)

接口 对象类型接口 先用interface定义一个List接口,成员有id时number类型&#xff0c;name是string类型再定义一个Result&#xff0c;成员是List数组定义一个render函数&#xff0c;接收参数是result // 先用interface定义一个List接口 interface List {id:number,name:strin…

安卓APP源码和设计报告——个人通讯录

摘 要 随着移动设备制造技术和移动通信网络的迅猛发展,全球手机用户日益增加,手机成为了很多人日常生活中必不可少的一部分,手机业在日益发展的同时,人们对手机的功能需求和体验需求也越来越高,因此各种智能手机相继而出&#xff0c;当前市场上最流行的智能手机的操作系统非An…

RabbitMQ--重试机制

原文网址&#xff1a;RabbitMQ--重试机制_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍RabbitMQ的重试机制。 问题描述 消费者默认是自动提交&#xff0c;如果消费时出现了RuntimException&#xff0c;会导致消息直接重新入队&#xff0c;再次投递&#xff08;进入队首&am…

【iOS】—— MVVM模式

MVVM模式 文章目录MVVM模式为什么使用MVVM&#xff1f;MVVM分别代表什么含义&#xff1f;MVVM通信关系MVVM模式的优缺点优点:缺点:概括总结MVVM文件分类为什么使用MVVM&#xff1f; iOS中&#xff0c;我们使用的大部分都是MVC架构。虽然MVC的层次明确&#xff0c;但是由于功能日…

C# 11新特性之file关键字

C#11 添加了文件作用域类型功能&#xff1a;一个新的 file 修饰符&#xff0c;可以应用于任何类型定义以限制其只能在当前文件中使用。这样&#xff0c;我们可以在一个项目中拥有多个同名的类。 目录示例file不可以与其他修饰符一起使用file可以修饰的类型file 不可修饰的类型f…

主流报表开发工具FastReport.Net全新发布,邀您体验最新版试用

FastReport .Net是一款适用于 WinForms、Blazor Server、ASP.NET、MVC、.NET 6 和 .NET Core 的报告生成工具。FastReport代表着“速度”、“可靠”和“品质”&#xff0c;是当今主流的报表开发工具。 该产品在本月进行了重大版本v2023的发布&#xff0c;接下来让我们一起看看…

【OpenCV-Python】教程:4-9 特征匹配 match

OpenCV Python 特征匹配 【目标】 特征匹配Brute-Force Matcher 和 FLANN Matcher 【理论】 Brute-Force Matcher字面意思是蛮力匹配器&#xff0c;所以它的过程也很简单&#xff0c;从一个集合里取出一个特征描述子&#xff0c;然后与第二个集合里的特征逐个的进行匹配比较…

传统MES架构的智能化改进---python在Aprol上的实践

一、开题依据 MES是属于生产车间级的管理信息系统。作为生产与计划之间的信息“集线器”&#xff0c;MES 主要包括以下功能模块&#xff1a;工序详细调度、资源分配和状态管理、生产单元分配、过程管理、人力资源管理、维护管理、质量管理、文档控制、产品跟踪和产品清单管理、…

Solidworks导出为URDF用于MoveIT总结(带prismatic)

环境 Solidwoks2018 SP0 / Solidwoks2021 SP5&#xff1b;Ubuntu20.04&#xff1b;ROS1 Noetic; Solidwoks2018 SP0对于平移副有问题&#xff0c;显示不出来&#xff0c;Solidwoks2021 SP5没有问题。 官网有段话&#xff1a; There is a known STL export bug with SolidWork…

Jdk Tomcat 安装教程 — 2022.12.11

文章目录一、安装jdk教程二、tomcat 安装三、修改Tomcat端口号安装Tomcat之前要确保安装jdk一、安装jdk教程 安装vim命令包&#xff0c;此操作如果执行不了&#xff0c;需要使用root权限执行 执行如下命令&#xff1a; yum install -y vim-enhanced2. 下载jdk安装包&#xff…