草庐IT

JAVA采用S7通信协议访问西门子PLC

XS_YOUYOU 2023-08-23 原文

简介

采用java的方式实现西门子S7协议

链接地址iot-communication
github: https://github.com/xingshuangs/iot-communication
gitee: https://gitee.com/xingshuang/iot-communication

  • 支持单数据读写,多数据读写,大数据量自动分包读写
  • 支持序列化批量多地址且地址不连续的读写
  • 支持读取DB区,I区,Q区,M区,V
  • 支持读取西门子S1200,200Smart
  • 支持PLC自动重连

引入依赖包

<dependency>
    <groupId>com.github.xingshuangs</groupId>
    <artifactId>iot-communication</artifactId>
    <version>1.2.7</version>
</dependency>

简单入门示例

class Demo {
    public static void main(String[] args) {
		// 创建PLC对象
		S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
		// 读写boolean
		s7PLC.writeBoolean("DB1.2.0", true);
		boolean boolData = s7PLC.readBoolean("DB1.2.0");
		// 读写字节
		s7PLC.writeByte("DB2.1", (byte) 0x11);
		byte byteData = s7PLC.readByte("DB2.1");
    }
}

知识点1:地址读写格式以及对应含义(兼容大小写)

简写区域字节索引位索引PLC
DB1.1.2DB1区121200
DB2DB2区001200
DB3.3DB3区301200
D1.1.2DB1区121200
Q1.6Q区161200
Q1Q区101200
I2.5I区251200
I2I区201200
M3.2M区321200
M3M区301200
V2.1V区21200Smart
V2V区20200Smart

知识点2:访问数据类型与JAVA数据类型和PLC数据类型对应关系

访问数据类型数据类型名称数据大小(位)数据大小(字节)对应JAVA数据类型对应PLC数据类型示例
boolean布尔类型11/8BooleanBOOLtrue
byte字节类型81ByteBYTE0x11
uint16无符号2字节整型162IntegerWORD/UINT65535
int16有符号2字节整型162ShortWORD/INT-32760
uint32无符号4字节整型324LongDWORD/UDINT70000
int32有符号4字节整型324IntegerDWORD/DINT-70000
float324字节浮点型324FloatREAL3.14
float648字节浮点型648DoubleLREAL3.14
string字符型81StringStringABC

多种方式PLC数据访问示例

1. 单地址数据读写

// 创建PLC对象
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");

// read boolean
boolean boolData = s7PLC.readBoolean("DB1.2.0");
// read byte
byte byteData = s7PLC.readByte("DB14.0");
byte iByteData = s7PLC.readByte("I0");
byte qByteData = s7PLC.readByte("Q0");
byte mByteData = s7PLC.readByte("M0");
byte vByteData = s7PLC.readByte("V0"); // 200smart有V区
// read byte
byte[] byteDatas = s7PLC.readByte("DB14.0", 4);
// read UInt16
int intData = s7PLC.readUInt16("DB14.0");
// read UInt32
long int32Data = s7PLC.readUInt32("DB1.0");
// read float32
float float32Data = s7PLC.readFloat32("DB1.0");
// read float64
double float64Data = s7PLC.readFloat64("DB1.0");
// read String
String strData = s7PLC.readString("DB14.4");

// write boolean
s7PLC.writeBoolean("DB2.0.7", true);
s7PLC.writeBoolean("Q0.7", true);
s7PLC.writeBoolean("M1.4", true);
// write byte
s7PLC.writeByte("DB2.1", (byte) 0x11);
s7PLC.writeByte("M1", (byte) 0x11);
s7PLC.writeByte("V1", (byte) 0x11); // 200smart有V区
// write UInt16
s7PLC.writeUInt16("DB2.0", 0x2222);
// write UInt32
s7PLC.writeUInt32("DB2.0", 0x11111122);
// write float32
s7PLC.writeFloat32("DB2.0", 12);
// write float64
s7PLC.writeFloat64("DB2.0", 12.02);
// write String
s7PLC.writeString("DB14.4", "demo");

2. 多地址数据读写

// 创建PLC对象
S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");

// read boolean
List<Boolean> boolDatas = s7PLC.readBoolean("DB1.2.0", "DB1.2.1", "DB1.2.7");
List<Boolean> iDatas = s7PLC.readBoolean("I0.0", "I0.1", "I0.2", "I0.3", "I0.4", "I0.5");
List<Boolean> qDatas = s7PLC.readBoolean("Q0.0", "Q0.1", "Q0.2", "Q0.3", "Q0.4", "Q0.5", "Q0.6", "Q0.7");
List<Boolean> mDatas = s7PLC.readBoolean("M1.0", "M1.1", "M1.2", "M1.3", "M1.4", "M1.5", "M1.6", "M1.7");
List<Boolean> vDatas = s7PLC.readBoolean("V1.0", "V1.1", "V1.2", "V1.3", "V1.4", "V1.5", "V1.6", "V1.7"); // 200smart有V区
// read UInt16
List<Integer> intDatas = s7PLC.readUInt16("DB1.0", "DB1.2");
// read UInt32
List<Long> int32Datas = s7PLC.readUInt32("DB1.0", "DB1.4");
// read float32
List<Float> float32Datas = s7PLC.readFloat32("DB1.0", "DB1.4");
// read float64
List<Double> float64Datas = s7PLC.readFloat64("DB1.0", "DB1.4");
// read multi address
MultiAddressRead addressRead = new MultiAddressRead();
addressRead.addData("DB1.0", 1)
           .addData("DB1.2", 3)
           .addData("DB1.3", 5);
List<byte[]> multiByte = s7PLC.readMultiByte(addressRead);

// write multi address
MultiAddressWrite addressWrite = new MultiAddressWrite();
addressWrite.addByte("DB2.0", (byte) 0x11)
            .addUInt16("DB2.2", 88)
            .addBoolean("DB2.1.0", true);
s7PLC.writeMultiData(addressWrite);

3. 序列化方式小数据量批量读写

小数据量是指单次数据请求的报文中PDU大小未超过指定PLC的最大值限制,例如单次请求PDULength小于240,不同PLC的限制各有不同,有240,480,960

先构建数据对象

@Data
public class DemoBean {

    @S7Variable(address = "DB1.0.1", type = EDataType.BOOL)
    private boolean bitData;

    @S7Variable(address = "DB1.1", type = EDataType.BYTE, count = 3)
    private byte[] byteData;

    @S7Variable(address = "DB1.4", type = EDataType.UINT16)
    private int uint16Data;

    @S7Variable(address = "DB1.6", type = EDataType.INT16)
    private short int16Data;

    @S7Variable(address = "DB1.8", type = EDataType.UINT32)
    private long uint32Data;

    @S7Variable(address = "DB1.12", type = EDataType.INT32)
    private int int32Data;

    @S7Variable(address = "DB1.16", type = EDataType.FLOAT32)
    private float float32Data;

    @S7Variable(address = "DB1.20", type = EDataType.FLOAT64)
    private double float64Data;
}

然后构建序列化对象,接着数据读写

class Demo {
    public static void main(String[] args) {
        S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
        S7Serializer s7Serializer = S7Serializer.newInstance(s7PLC);
        // 小数据量批量读取
        DemoBean bean = s7Serializer.read(DemoBean.class);
        // 修改指定数据内容
        bean.setBitData(true);
        bean.setByteData(new byte[]{(byte) 0x01, (byte) 0x02, (byte) 0x03});
        bean.setUint16Data(42767);
        bean.setInt16Data((short) 32767);
        bean.setUint32Data(3147483647L);
        bean.setInt32Data(2147483647);
        bean.setFloat32Data(3.14f);
        bean.setFloat64Data(4.15);
        // 小数据量批量写入
        s7Serializer.write(bean);
    }
}

4. 序列化方式大数据量批量读写

大数据量是指单次数据请求的报文中PDU大小超过指定PLC的最大值限制,例如单次请求PDULength不得超过240,不同PLC的限制各有不同,有240,480,960

先构建数据对象

@Data
public class DemoLargeBean {

    @S7Variable(address = "DB1.0.1", type = EDataType.BOOL)
    private boolean bitData;

    @S7Variable(address = "DB1.10", type = EDataType.BYTE, count = 50)
    private byte[] byteData1;

    @S7Variable(address = "DB1.60", type = EDataType.BYTE, count = 65)
    private byte[] byteData2;

    @S7Variable(address = "DB1.125", type = EDataType.BYTE, count = 200)
    private byte[] byteData3;

    @S7Variable(address = "DB1.325", type = EDataType.BYTE, count = 322)
    private byte[] byteData4;

    @S7Variable(address = "DB1.647", type = EDataType.BYTE, count = 99)
    private byte[] byteData5;

    @S7Variable(address = "DB1.746", type = EDataType.BYTE, count = 500)
    private byte[] byteData6;

    @S7Variable(address = "DB1.1246", type = EDataType.BYTE, count = 44)
    private byte[] byteData7;
}

然后构建序列化对象,接着数据读写

class Demo {
    public static void main(String[] args) {
        S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
        S7Serializer s7Serializer = S7Serializer.newInstance(s7PLC);
        // 大数据量批量读取
        DemoLargeBean bean = s7Serializer.read(DemoLargeBean.class);
        // 指定地址数据更改
        bean.getByteData2()[64] = (byte) 0x02;
        bean.getByteData3()[199] = (byte) 0x03;
        bean.getByteData4()[321] = (byte) 0x04;
        bean.getByteData5()[98] = (byte) 0x05;
        bean.getByteData6()[499] = (byte) 0x06;
        bean.getByteData7()[43] = (byte) 0x07;
        // 大数据量批量写入
        s7Serializer.write(bean);
    }
}

5. 自定义读写方式(开发效率低)

class Demo {
    public static void main(String[] args) {
        S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
        // bit数据读写
        byte[] expect = new byte[]{(byte) 0x00};
        this.s7PLC.writeRaw(EParamVariableType.BIT, 1, EArea.DATA_BLOCKS, 1, 0, 3,
                EDataVariableType.BIT, expect);
        byte[] actual = this.s7PLC.readRaw(EParamVariableType.BIT, 1, EArea.DATA_BLOCKS, 1, 0, 3);
		// byte数据读写
        expect = new byte[]{(byte) 0x02, (byte) 0x03};
        this.s7PLC.writeRaw(EParamVariableType.BYTE, 2, EArea.DATA_BLOCKS, 1, 1, 0,
                EDataVariableType.BYTE_WORD_DWORD, expect);
        actual = this.s7PLC.readRaw(EParamVariableType.BYTE, 2, EArea.DATA_BLOCKS, 1, 1, 0);
    }
}

6. 控制指令

class Demo {
    public static void main(String[] args) {
        S7PLC s7PLC = new S7PLC(EPlcType.S1200, "127.0.0.1");
        // hot restart
        s7PLC.hotRestart();
        // cold restart
        s7PLC.coldRestart();
        // plc stop
        s7PLC.plcStop();
        // copy ram to rom
        s7PLC.copyRamToRom();
        // compress
        s7PLC.compress();
    }
}

字节数据解析

当采集的数据量比较大且都是字节数组数据时,需要将字节数据转换成所需的数据,可以采用ByteReadBuff工具;
该工具采用大端模式,4字节数据解析采用DCBA,可根据需求自行修改;

1. boolean数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x55});
// 直接字节解析获取,内部索引自动后移
boolean b1 = buff.getBoolean(0);
// 指定字节索引地址后解析获取
boolean b2 = buff.getBoolean(0, 1);

2. byte数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x55, (byte) 0x33, (byte) 0x22});
// 先提取第一个字节
buff.getByte();
// 再提取后两个字节
byte[] actual = buff.getBytes(2);
assertArrayEquals(new byte[]{(byte) 0x33, (byte) 0x22}, actual);

buff = new ByteReadBuff(new byte[]{(byte) 0x55, (byte) 0x33, (byte) 0x22});
// 先提取第一个字节
buff.getByte();
// 再提取剩余所有字节
actual = buff.getBytes();
assertArrayEquals(new byte[]{(byte) 0x33, (byte) 0x22}, actual);

3. uint16数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x5F, (byte) 0xF5});
int actual = buff.getUInt16();
assertEquals(24565, actual);

4. int16数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x5F, (byte) 0xF5});
short actual = buff.getInt16();
assertEquals(24565, actual);

5. uint32数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 0x37, (byte) 0x36});
long actual = buff.getUInt32();
assertEquals(2111286L, actual);

6. int32数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x00, (byte) 0x20, (byte) 0x37, (byte) 0x36});
int actual = buff.getInt32();
assertEquals(2111286, actual);

7. float32数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x42, (byte) 0x04, (byte) 0xA3, (byte) 0xD7});
float actual = buff.getFloat32();
assertEquals(33.16f, actual, 0.001);

8. float64数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x41, (byte) 0x03, (byte) 0x1F, (byte) 0xCA, (byte) 0xD6, (byte) 0x21, (byte) 0x39, (byte) 0xB7});
double actual = buff.getFloat64();
assertEquals(156665.35455556, actual, 0.001);

9. string数据类型

ByteReadBuff buff = new ByteReadBuff(new byte[]{(byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33});
String actual = buff.getString(4);
assertEquals("0123", actual);

Springboot中简单使用

1. 普通模式

先构建Springboot的工程,添加maven依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.xingshuangs/iot-communication -->
        <dependency>
            <groupId>com.github.xingshuangs</groupId>
            <artifactId>iot-communication</artifactId>
            <version>1.2.6</version>
        </dependency>
    </dependencies>

添加PLC相关配置,主要是对连接对象实例化,创建bean

package com.github.xingshuangs.s7.demo.config;

import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author xingshuang
 */
@Configuration
public class S7Config {

    @Bean
    public S7PLC s7PLC() {
        return new S7PLC(EPlcType.S1200, "127.0.0.1");
    }
}

添加控制层业务

package com.github.xingshuangs.s7.demo.controller;

import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;

/**
 * @author xingshuang
 */
@RestController
@RequestMapping("/normal")
public class S7NormalComController {
    Random random = new Random();

    @Autowired
    private S7PLC s7PLC;

    @GetMapping("/uint16")
    public ResponseEntity uint16() {
        this.s7PLC.writeUInt16("DB1.0", random.nextInt(255));
        int res = this.s7PLC.readUInt16("DB1.0");
        return ResponseEntity.ok(res);
    }

    @GetMapping("/boolean")
    public ResponseEntity booleanTest() {
        this.s7PLC.writeBoolean("DB1.0.0", random.nextInt(255) % 2 == 0);
        boolean res = this.s7PLC.readBoolean("DB1.0.0");
        return ResponseEntity.ok(res);
    }

    @GetMapping("/float32")
    public ResponseEntity float32Test() {
        this.s7PLC.writeFloat32("DB1.0", random.nextFloat());
        float res = this.s7PLC.readFloat32("DB1.0");
        return ResponseEntity.ok(res);
    }

    @GetMapping("/string")
    public ResponseEntity stringTest() {
        this.s7PLC.writeString("DB1.0", String.valueOf(random.nextInt(20)));
        String res = this.s7PLC.readString("DB1.0");
        return ResponseEntity.ok(res);
    }
}

2. 序列化模式

添加S7序列化对象

package com.github.xingshuangs.s7.demo.config;


import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author xingshuang
 */
@Configuration
public class S7Config {

    @Bean
    public S7PLC s7PLC() {
        return new S7PLC(EPlcType.S1200, "127.0.0.1");
    }

    @Bean
    public S7Serializer s7Serializer(S7PLC s7PLC) {
        return new S7Serializer(s7PLC);
    }
}

添加数据采集类,添加注解配置

package com.github.xingshuangs.s7.demo.model;

import com.github.xingshuangs.iot.protocol.common.enums.EDataType;
import com.github.xingshuangs.iot.protocol.s7.serializer.S7Variable;
import lombok.Data;

/**
 * 测试对象
 *
 * @author xingshuang
 */
@Data
public class DemoBean {

    @S7Variable(address = "DB1.0.1", type = EDataType.BOOL)
    private boolean bitData;

    @S7Variable(address = "DB1.4", type = EDataType.UINT16)
    private int uint16Data;

    @S7Variable(address = "DB1.6", type = EDataType.INT16)
    private short int16Data;

    @S7Variable(address = "DB1.8", type = EDataType.UINT32)
    private long uint32Data;

    @S7Variable(address = "DB1.12", type = EDataType.INT32)
    private int int32Data;

    @S7Variable(address = "DB1.16", type = EDataType.FLOAT32)
    private float float32Data;

    @S7Variable(address = "DB1.20", type = EDataType.FLOAT64)
    private double float64Data;

    @S7Variable(address = "DB1.28", type = EDataType.BYTE, count = 3)
    private byte[] byteData;
}

添加控制层业务

package com.github.xingshuangs.s7.demo.controller;

import com.github.xingshuangs.iot.protocol.s7.serializer.S7Serializer;
import com.github.xingshuangs.s7.demo.model.DemoBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author xingshuang
 */
@RestController
@RequestMapping("/serializer")
public class S7SerializerComController {

    @Autowired
    private S7Serializer s7Serializer;

    @GetMapping("/bean")
    public ResponseEntity<DemoBean> demoBean() {
        DemoBean bean = this.s7Serializer.read(DemoBean.class);
        return ResponseEntity.ok(bean);
    }
}

有关JAVA采用S7通信协议访问西门子PLC的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  5. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  6. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  9. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  10. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

随机推荐