前言
现在要支持 MS 的 Thrfit 协议,因为 MS 是集成的 jmeter,所以要开发 MS 插件其实就是开发 Jmeter 插件,然后再进行封装。


一、JMeter 介绍

1. JMeter

JMeter 是 Apache 基金会旗下的一款完全基于 Java 的开源软件,主要用作性能测试,通过模拟并发负载来测试并分析应用的性能状况。JMeter 最初被用于测试部署在服务器端的 Web 应用程序,现在发展到了更广泛的领域。目前 JMeter 已成为主流的性能测试工具。

1.1 功能特性

  1. JMeter 作为优秀的开源项目,拥有开放、强大且活跃的社区支持。
  2. JMeter 支持多种类型的应用、服务及协议,官方支持包括:HTTP Web 应用、HTTPS Web 应用、SOAP、REST、FTP、TCP、LDAP、Java 对象、JDBC 方式连接的数据库等。扩展后可支持更多协议。
  3. JMeter 具备跨平台特性,可运行于 Linux、Windows、Mac OSX 等多种操作系统平台上。测试人员通过 JMeter GUI 界面创建 JMeter 脚本,或通过录制的方式生成脚本,然后通过 GUI 界面或命令行方式来运行测试。
  4. JMeter 具有高可扩展性,测试人员可基于 JMeter 开发自定义的插件,由 JMeter 装载后运行。

由此可见,JMeter 可以支持自定义第三方插件的。

2. 本地安装 JMeter

参考链接:
https://www.jianshu.com/p/0e4daecc8122

二、开发 Thrift 协议插件

2.1 Thrift

Thrift 是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、and OCaml 等等编程语言间无缝结合的、高效的服务。

Thrift 最初由 facebook 开发,07 年四月开放源码,08 年 5 月进入 Apache 孵化器。Thrift 允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成 RPC 客户端和服务器通信的无缝跨编程语言。

官方链接:https://thrift.apache.org/

2.2 MAC 安装 Thrift 环境

  1. Thrift 是一个 rpc 的框架,所以,要想编译 Thrift 的 IDL 语言,首先要安装编辑器。
  2. Mac 安装还是比较方便的直接通过 brew 的方式安装

    brew install thrift 
    
  3. 安装成功之后看下版本信息,出现版本即为成功。

    thrift -version
    
![](/uploads/photo/2023/5b76161a-6760-41c5-9a1c-1b05c8a21db7.png!large)


## 2.3  IDEA中编写Thrift 脚本

1. 首先需要安装支持Thrift IDL语言的插件。(Thrift Support)
2. 这个插件对idea的版本有限制,安装的时候需要注意下。
3.  当然也可以直接在任何文本编辑器中进行编写,保存文件的时候保存为.thrift为结尾的就行。

插件地址:[https://plugins.jetbrains.com/plugin/7331-thrift-support](https://plugins.jetbrains.com/plugin/7331-thrift-support)



![](/uploads/photo/2023/f4c831ec-52ee-4103-aa79-3e49aa176798.png!large)


3. 下载完之后就可以编写IDL脚本了。
### 2.3.1 Thrift IDL 语法对应如下:

- 基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:utf-8 编码的字符串,对应 Java 的 String
- 结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
- 容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
- 异常类型:
exception:对应 Java 的 Exception
- 服务类型:
service:对应服务的类。 
### 2.3.2 服务端编码基本步骤

1. 实现服务处理接口 impl
2. 创建 TProcessor
3. 创建 TServerTransport
4. 创建 TProtocol
5. 创建 TServer
6. 启动 Server
### 2.3.3 客户端编码基本步骤

1. 创建 Transport
2. 创建 TProtocol
3. 基于 TTransport 和 TProtocol 创建 Client
4. 调用 Client 的相应方法
### 2.3.4 数据传输协议

1. TBinaryProtocol 二进制格式
2. TCompactProtocol 压缩格式
3. TJSONProtocol JSON 格式
4. TSimpleJSONProtocol 提供 JSON 只写协议,生成的文件很容易通过脚本语言解析

**提示**: 客户端和服务端的协议要一致
### 2.3.5 编写Thrift脚本  

1. 创建一个maven或者java 项目都可以



![](/uploads/photo/2023/79af314a-531b-43fa-a9e5-a400b3fe5a91.png!large)


2. 编写Thrift脚本
```csharp
namespace  java com.thrift.demo  // 使用java 语言定义 package 

service ThriftHelloService{  // 定义一个service  相当于java当中的接口

    string sayHello(1:string username)  // 输入一个参数,返回string类型参数。

}
  1. 注意名字必须要以.thrift 结尾的。
  2. idea 没有.thrift 文件,直接创建 text 修改名字即可。 ### 2.3.6 编译 Thrift 脚本

  1. 通过 thrift -gen java 文件名.thrift 进行编译.
  2. 编译成功之后会在当前项目里面看到.

  3. 可以看到报错不用管,因为这个项目就是我们用来使用生成 java 类的项目。可以看到这个类中,有很多代码,

简单分析一下这个类:生成的类主要有 5 个部分

  1. 接口类型,默认名称都是 Iface。这个接口类型被服务器和客户端共同使用。服务器端使用它来做顶层接口,编写实现类。客户端代码使用它作为生成代理的服务接口。

自动生成的接口有两个,一个是同步调用的 Iface,一个是异步调用的 AsyncIface。异步调用的接口多了一个回调参数。

  1. 客户端类型,一个同步调用的客户端 Client,一个异步调用的客户端 AsyncClient
  2. Processor,用来支持方法调用,每个服务的实现类都要使用 Processor 来注册,这样最后服务器端调用接口实现时能定位到具体的实现类。 一个同步调用 Processor,一个异步调用 AsyncProcessor
  3. 方法参数的封装类,以"方法名_args"命名
  4. 方法返回值的封装类,以"方法名_result"命名

详细的源码分析参考:https://www.kancloud.cn/digest/thrift/118986

2.3.7 编写服务器端

  1. 在 idea 中新建一个 maven 项目,报名要与刚刚在 Thrift 当中生成的 namespace 一样,并且把刚刚生成好的 java 类给复制过来

  1. 添加 pom 依赖
<dependencies>
  <!--      thrift 集成-->
  <dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.16.0</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
  </dependency>

  <!--        jmeter 集成-->
  <dependency>
    <groupId>org.apache.jmeter</groupId>
    <artifactId>ApacheJMeter_core</artifactId>
    <version>5.5</version>
  </dependency>
  <dependency>
    <groupId>org.apache.jmeter</groupId>
    <artifactId>ApacheJMeter_java</artifactId>
    <version>5.5</version>
  </dependency>

</dependencies>
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.3</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <encoding>utf-8</encoding>
      </configuration>
    </plugin>
      <!--       完整依赖打包 集成-->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
      <executions>
        <execution>
          <id>assemble-all</id>
          <phase>package</phase>
          <goals>
            <goal>single</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

  1. 写接口的实现类

    public class ThriftHelloServiceImpl implements ThriftHelloService.Iface {
    @Override
    public String sayHello(String username) throws TException {
        return "Hello Thrift :" + username;
    }
    }
    
  2. 写服务端 main 方法

    public static void main(String[] args) throws Exception {
        try {
            // 实现处理接口impl
            ThriftHelloServiceImpl thriftHelloService = new ThriftHelloServiceImpl();
            // 创建TProcessor
            TProcessor processor = new ThriftHelloService.Processor<>(thriftHelloService);
            // 创建TServerTransport,非阻塞式I/O,服务端和客户端需要TFramedTransport 数据传输方式
            TNonblockingServerSocket tNonblockingServerSocket = new TNonblockingServerSocket(9099);
            // 创建TProtocol
            TThreadedSelectorServer.Args args1 = new TThreadedSelectorServer.Args(tNonblockingServerSocket);
            args1.transportFactory(new TFramedTransport.Factory());
            // 二进制格式反序列化
            args1.protocolFactory(new TBinaryProtocol.Factory());
            args1.processor(processor);
            args1.selectorThreads(16);
            args1.workerThreads(32);
            System.out.println("computer service server on port:" + 9099);
            TThreadedSelectorServer tThreadedSelectorServer = new TThreadedSelectorServer(args1);
            System.out.println("启动 Thrift 服务端");
            tThreadedSelectorServer.serve();
        } catch (Exception e) {
            System.out.println("启动 Thrift 服务端失败" + e.getMessage());
        }
    }
    

    2.3.8 编写客户端

public static void main(String[] args) {

        TTransport transport = null;
        try {
            // 要跟服务器端的传输方式一致
            transport = new TFramedTransport(new TSocket("127.0.0.1", 9099, 6000));
            TProtocol protocol = new TBinaryProtocol(transport);
            ThriftHelloService.Client client = new ThriftHelloService.Client(protocol);
            transport.open();
            String result = client.sayHello("thrift-1");
            System.out.println(result);
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }
  1. 启动验证
  2. 服务端

验证成功,说明没有问题。

2.4 编写 JMeter 插件

  1. 因为我们目的是要写 jmeter 插件,所以要集成 JMeter 对应的依赖包,详细参考上面的 pom 文件。
  2. 两种方式:
    1. 一种是继承 AbstractJavaSamplerClient ,此方式集成之后,直接打包,在 jmeter 当中选择,java 请求即可验证功能。偏向于验证功能。
    2. 一种是继承 AbstractSampler 和 继承 AbstractSamplerGui 此方式可以通过 GUI 的方式,实现 JMeter 的调用。

ThriftClient(封装公用 client)

ThriftHelloService.Client client = null;

    private TTransport tTransport = null;


    public ThriftClient(String ip, int port, int timeout) {
        try {
            // 注意传输协议要跟服务器端一致
            tTransport = new TFramedTransport(new TSocket(ip, port, timeout));
            TProtocol tProtocol = new TBinaryProtocol(tTransport);
            client = new ThriftHelloService.Client(tProtocol);
            tTransport.open();
        } catch (TTransportException e) {
            e.printStackTrace();
        }
    }

    public String getResponse(String str) {
        try {
            return client.sayHello(str);
        } catch (TException e) {
            e.printStackTrace();
            return null;
        }
    }

    public void close() {
        if (tTransport != null && tTransport.isOpen()) {
            tTransport.close();
        }
    }

2.4.1 继承 AbstractJavaSamplerClient

private ThriftClient thriftClient;

   /**
    * 方法为性能测试时的线程运行体;
    *
    * @param javaSamplerContext
    * @return
    */
   @Override
   public SampleResult runTest(JavaSamplerContext javaSamplerContext) {

       SampleResult sampleResult = new SampleResult();
       // 开始统计响应时间标记
       sampleResult.sampleStart();
       try {
           StopWatch stopWatch = new StopWatch();
           stopWatch.start();
           String response = thriftClient.getResponse("哈哈我是性能调试");
           stopWatch.stop();
           System.out.println(response + "总计花费:" + stopWatch.getTime());
           if (StringUtils.isNotBlank(response)) {
               sampleResult.setSuccessful(true);
               sampleResult.setResponseMessage(response);
           } else {
               sampleResult.setSuccessful(false);
               sampleResult.setResponseMessage("请求失败....");
           }
       } catch (Exception e) {
           sampleResult.setSuccessful(false);
           sampleResult.setResponseMessage("请求失败....");
       } finally {
           // 结束统计响应时间标记
           sampleResult.sampleEnd();
       }
       return sampleResult;
   }


   /**
    * 方法为初始化方法,用于初始化性能测试时的每个线程;
    *
    * @param context
    */
   @Override
   public void setupTest(JavaSamplerContext context) {
       String ip = context.getParameter("ip");
       String port = context.getParameter("port");
       String timeout = context.getParameter("timeout");
       // 初始化客户端
       thriftClient = new ThriftClient(ip, Integer.valueOf(port), Integer.valueOf(timeout));
       super.setupTest(context);
   }


   /**
    * 方法为测试结束方法,用于结束性能测试中的每个线程。
    *
    * @param context
    */
   @Override
   public void teardownTest(JavaSamplerContext context) {
       if (thriftClient != null) {
           thriftClient.close();
       }
       super.teardownTest(context);
   }

   /**
    * 方法主要用于设置传入界面的参数,初始化默认参数
    *
    * @return
    */
   @Override
   public Arguments getDefaultParameters() {
       Arguments jMeterProperties = new Arguments();
       jMeterProperties.addArgument("ip", "127.0.0.1");
       jMeterProperties.addArgument("port", "9099");
       jMeterProperties.addArgument("timeout", "6000");
       return jMeterProperties;
   }

  1. 写完之后直接打成 jar 包 。 mvn clean install
  2. 然后会看到生成两个包。 然后把对应的 jar 包放到 jmeter 的 lib/ext/ 下面.
  3. 注意: 如果打的是源码包要放源码包: 即 ThriftDemo-1.0-1-jar-with-dependencies.jar
  4. jmeter 下面 lib 和 lib/ext 的区别: 一般我们自定义协议的包都会放到 lib/ext 下面,当我们自定义里面的包有依赖第三方的依赖包,并且此时我们没有打成源码包的情况下,会将所依赖的第三方依赖包放置到 lib 当中。
  5. 比如: 我在 lib/ext 下面放置的是 ThriftDemo-1.0-1.jar 包,这个并不是源码包。所以,还需要将项目当中 pom 文件所依赖的 org.apache.libthrift 的 jar 包放置到 lib 目录下面才行。否则在调用的时候,会提示找不到对应类 (classNotFountException) 的错误信息。

服务端启动,即可验证成功。

2.4.2 继承 AbstractSampler 和 AbstractSamplerGui

  1. 这种方式的效果如下:

就是在 jmeter 当中写一个自己的 sampler ,并且有对应 ui 页面。

2.4.2.1 ThriftSamplerUI

继承 AbstractSamplerGui 编写 gui 的页面,跟 java 当中 swing 一样。

package com.thrift.demo.gui;

import com.thrift.demo.jmeterTest.ThriftSampler;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.gui.JLabeledTextField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;


/**
 * @author fit2cloudzhao
 * @date 2022/8/2 18:58
 * @description:
 */
public class ThriftSamplerUI extends AbstractSamplerGui {


    Logger log = LoggerFactory.getLogger(ThriftSamplerUI.class);
    private final JLabeledTextField serverIp = new JLabeledTextField("ServerIp");
    private final JLabeledTextField port = new JLabeledTextField("Port");
    private final JLabeledTextField param = new JLabeledTextField("Param");
    private void init() {
        log.info("Initializing the UI.");
        setLayout(new BorderLayout());
        setBorder(makeBorder());

        add(makeTitlePanel(), BorderLayout.NORTH);
        JPanel mainPanel = new VerticalPanel();
        add(mainPanel, BorderLayout.CENTER);

        JPanel DPanel = new JPanel();
        DPanel.setLayout(new GridLayout(3, 2));
        DPanel.add(serverIp);
        DPanel.add(port);
        DPanel.add(param);

        JPanel ControlPanel = new VerticalPanel();
        ControlPanel.add(DPanel);
        ControlPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.gray), "Parameters"));
        mainPanel.add(ControlPanel);
    }

    public ThriftSamplerUI() {
        super();
        this.init();
    }

    @Override
    public String getStaticLabel() {
        return "Thrift Sampler";
    }
    @Override
    public String getLabelResource() {
        throw new IllegalStateException("This shouldn't be called");
    }

    /**
     * 该方法创建一个新的Sampler,然后将界面中的数据设置到这个新的Sampler实例中。
     * @return
     */
    @Override
    public TestElement createTestElement() {
        ThriftSampler sampler = new ThriftSampler();
        this.setupSamplerProperties(sampler);
        return sampler;
    }


    private void setupSamplerProperties(ThriftSampler sampler) {
        this.configureTestElement(sampler);
        sampler.setServerIp(serverIp.getText());
        sampler.setPort(Integer.valueOf(port.getText()));
        sampler.setParam(param.getText());
    }


    /**
     * 这个方法用于把界面的数据移到Sampler中。
     * @param testElement
     */
    @Override
    public void modifyTestElement(TestElement testElement) {
        ThriftSampler sampler = (ThriftSampler) testElement;
        this.setupSamplerProperties(sampler);
    }


    /**
     * 界面与Sampler之间的数据交换
     * @param element
     */
    @Override
    public void configure(TestElement element) {
        super.configure(element);
        ThriftSampler sampler = (ThriftSampler) element;
        this.serverIp.setText(sampler.getServerIp());
        this.port.setText(sampler.getPort().toString());
        this.param.setText(sampler.getParam());
    }


    /**
     * 该方法会在reset新界面的时候调用,这里可以填入界面控件中需要显示的一些缺省的值(就是默认显示值)
     */
    @Override
    public void clearGui() {
        super.clearGui();
        this.serverIp.setText("服务端ip");
        this.port.setText("9099");
        this.param.setText("参数");
    }
}

2.4.2.2 ThriftSampler

package com.thrift.demo.jmeterTest;

import com.thrift.demo.client.ThriftClient;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.jmeter.samplers.AbstractSampler;
import org.apache.jmeter.samplers.Entry;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestStateListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author fit2cloudzhao
 * @date 2022/8/2 21:45
 * @description:
 */
public class ThriftSampler extends AbstractSampler implements TestStateListener {

    Logger log = LoggerFactory.getLogger(ThriftSampler.class);
    private ThriftClient thriftClient;

    private static final String SERVER_IP = "server_ip";
    private static final String PORT = "port";

    private static final String PARAM = "request_param";


    public ThriftSampler() {
        setName("Thrift sampler");
    }

    @Override
    public SampleResult sample(Entry entry) {

        SampleResult sampleResult = new SampleResult();
        // 开始统计响应时间标记
        sampleResult.sampleStart();
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            String param = getParam();
            String response = "";
            System.out.println("入参:" + param);
            log.info("入参:" + param);
            thriftClient = getThriftClient();
            if (StringUtils.isNotBlank(param)) {
                response = thriftClient.getResponse(param);
            } else {
                response = thriftClient.getResponse("我是空的");
            }
            System.out.println("response==>" + response);
            log.info("response==>" + response);
            stopWatch.stop();
            System.out.println(response + "总计花费:" + stopWatch.getTime());
            log.info(response + "总计花费:" + stopWatch.getTime());
            if (StringUtils.isNotBlank(response)) {
                sampleResult.setSuccessful(true);
                sampleResult.setResponseMessage(response);
                sampleResult.setResponseData(("请求成功:"+response).getBytes());
                sampleResult.setResponseCode("200");
            } else {
                sampleResult.setSuccessful(false);
                sampleResult.setResponseMessage("请求失败....请求参数:" + param);
                sampleResult.setResponseCode("500");
                sampleResult.setResponseData("请求失败".getBytes());
            }
        } catch (Exception e) {
            sampleResult.setSuccessful(false);
            sampleResult.setResponseMessage("请求失败...." + e.getMessage());
            sampleResult.setResponseCode("500");
            sampleResult.setResponseData(("请求失败...." + e.getMessage()).getBytes());
        } finally {
            // 结束统计响应时间标记
            sampleResult.sampleEnd();
        }
        return sampleResult;
    }


    public ThriftClient getThriftClient() {
        if (thriftClient == null) {
            thriftClient = new ThriftClient(getServerIp(), getPort(), 10000);
        }
        return this.thriftClient;
    }

    public String getServerIp() {
        return getPropertyAsString(SERVER_IP);
    }

    public Integer getPort() {
        return getPropertyAsInt(PORT);
    }


    public void setServerIp(String serverIp) {
        setProperty(SERVER_IP, serverIp);
    }

    public void setPort(Integer port) {
        setProperty(PORT, port);
    }

    public void setParam(String param) {
        setProperty(PARAM, param);
    }


    public String getParam() {
        return getPropertyAsString(PARAM);
    }

    @Override
    public void testStarted() {

    }

    @Override
    public void testStarted(String s) {

    }

    @Override
    public void testEnded() {
        this.testEnded("local");
    }

    @Override
    public void testEnded(String s) {

    }
}

  1. 这里的 sample 方法跟继承 AbstractJavaSamplerClient 里面的 runTest 方法差不多,都是写执行逻辑的,请求客户端的逻辑可以写在这里。
  2. 写完之后,进行打包,跟之前打包一样,需要把源码包放到 jmeter lib/ext 下面。
  3. 重启 jmeter ,选择自己写的 sampler ,就会看到下面的效果。
  4. 注意:如果打包完之后,看不到自己写的 sampler,需要看下 jmeter 日志。会有错误日志的,根据错误信息进行进一步处理。

2.5 编写 MS 的插件

  1. 因为 MS 集成的 JMeter,所以首先必须是 JMeter 支持的插件,其次在封装成 MS 的插件。
  2. 前面已经写了一个 JMeter 支持的 Thrift 插件了,现在只需要把这个插件给集成到 MS 插件里面就好了。
  3. 看一下我们要实现的效果。

2.5.1 MeterSphere 接口自动化插件基础开发教程

参考链接:
https://wiki.fit2cloud.com/pages/viewpage.action?pageId=67671925

metersphere-plugin-DummySampler

2.5.2 编写 MS 的 Thrift 插件

  1. 新建一个 maven 项目 ,目录结构如下:

  1. 然后参考以上文章直接去改自己的逻辑就行。
  2. 这边有一点要注意:要把自己写的 Thrfit 的 jar 给依赖进来。一定要是源码包!!!否则集成到 MS 当中会报错。跟在 JMeter 当中错误一样。
  3. 在 resource 创建 lib 文件夹,然后把集成的第三方 jar 放进来,并且在 pom 文件中添加依赖。

  1. 然后进行打包就行。mvn clean install 打完包之后,一个 MS 的插件就封装好了,然后直接在 MS 的插件管理上传插件就行。

  1. 上传完插件之后,检查下后面的小眼睛,看下自己编写的表单内容是否有添加上来。如果没有,检查打包问题。
  2. 注意:MS 删除插件必须重启 ms-server 服务才行,否则依赖的还是上一次的 jar 包。
  3. 上传完成之后在接口自动化会看到自己添加的插件信息

  1. 这个时候客户端写好了,如果是本地部署的,本地服务端直接启动就好。因为我这个是放到服务器上的,所以在把刚才的服务端给封装成 docker 镜像给放上去。
  2. 打开刚刚写的服务端的代码,打成 jar 包。具体方式如下:
    1. 打开 Project Structure

  1. 选择 Artifacts 添加一个 jar 包。

选择 resource 之后,就会看到下面生成的 MANIFEST.MF 文件,打开会看到很多 class,说明选择成功。

然后再 build 一下

build 完之后会看到当前项目当中有一个 out 的文件夹

找到

这个也就是我们打的 jar 包。到此,jar 已经打包完成了,放置到有 jdk 的环境当中 java -jar 就可以起来了。

我们这边封装成 docker 镜像的方式,方便启动。

2.5.2.1 封装 Dockerfile

FROM fabric8/java-alpine-openjdk11-jre:latest  // 注意arm/amd 的区别

MAINTAINER FIT2CLOUD <support@fit2cloud.com>

RUN mkdir -p /opt/apps

ADD out/artifacts/ThriftDemo_jar /opt/apps

WORKDIR /opt/apps

EXPOSE 9099

CMD ["java","-jar","ThriftDemo.jar"]

然后执行打成镜像, 并上传到服务器当中。

docker build -t ms-thrift-server:1.0 .

docker save -o ms-thrift-server.tar ms-thrift-server:1.0

上传服务器,加载镜像并启动

docker load -i ms-thrift-server.tar  

docker run --name ms-thrift-server  -d -p 9099:9099 ms-thrift-server:1.0

docker ps  // 查看状态

docker logs -f ms-thrift-server  // 出现启动Thrift 服务端,即启动成功。

2.5.3 调试

万事俱备了,只欠最后一哆嗦。

  1. 填写对应的服务器的地址和端口,然后随便传一个参数,可以看到返回 200 即链接成功。


↙↙↙阅读原文可查看相关链接,并与作者交流