笔记-字节顺序标记

字节顺序标记(Byte Order Mark,简称 BOM)是一个用于指示字节序(Byte Order)的特殊字符,具体是 Unicode 字符 U+FEFF。字节序问题主要存在于那些使用多于一个字节表示每个字符的编码方案中,比如 UTF-16 和 UTF-32。字节序是指在这些字节中哪一个字节先存储,这在不同架构的系统中可能不同,通常分为大端序(Big-Endian)和小端序(Little-Endian):

  • 大端序(Big-Endian):高位字节(more significant byte)在前,低位字节(less significant byte)在后。例如,Unicode 字符 U+1234 在大端序中存储为 12 34
  • 小端序(Little-Endian):低位字节在前,高位字节在后。同样的 U+1234 字符在小端序中存储为 34 12

由于大端序和小端序的存在,使用如 UTF-16 和 UTF-32 等编码的文本文件可能需要一个 BOM 来明确字节序。例如,如果一个文本文件以 FE FF 开头,则表明该文件采用大端序的 UTF-16 编码;如果以 FF FE 开头,则表明采用小端序。

然而,UTF-8 不受字节序问题的影响,因为它使用单个字节序列来表示每个字符,不涉及字节间的顺序问题。UTF-8 编码中的每个字节是明确的,不会根据存储顺序而改变含义。因此,UTF-8 编码不需要 BOM 来指示字节序。

在实践中,虽然 UTF-8 本身不需要 BOM,但有时会在 UTF-8 编码的文件开始处看到一个 BOM(即 EF BB BF)。这是为了与那些需要 BOM 的编码方式兼容,或者用来明确指明文件是以 UTF-8 编码的。但在很多情况下,UTF-8 BOM 是不必要的,甚至可能导致问题,比如在不期望 BOM 的上下文中解析文本时。因此,是否使用 UTF-8 BOM 往往取决于具体的应用需求和上下文。


UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode字符集的可变长度字符编码系统。它可以用来表示Unicode标准中的任何字符,并且其设计旨在兼容传统的ASCII编码。

网络中会存在大端系统和小端系统?

大端(Big-Endian)系统和小端(Little-Endian)系统的存在主要是由于不同的硬件架构和设计哲学所导致的。当计算机科学还处于起步阶段时,不同的系统设计者对于如何在内存中存储数据有不同的看法。这些看法转化成了两种主要的数据表示方法,即大端序和小端序,它们定义了多字节数据在内存中字节的顺序。

大端序(Big-Endian)

在大端序中,最高有效字节(MSB)存储在最低的内存地址上,这也意味着数字的第一个字节是最重要的字节。如果我们读取一个地址,我们首先得到的是数字的最高有效位。这种方式直观地反映了我们通常书写数字的方式,例如数值0x12345678在内存中的存储顺序将是 12 34 56 78

大端序的优点:

  • 读取数据的高位非常直接,特别是对于网络协议而言,因为协议字段经常是从高位开始定义的。
  • 更符合人类阅读数字的习惯。

小端序(Little-Endian)

而在小端序中,最低有效字节(LSB)存储在最低的内存地址上。数值0x12345678在小端序的系统中将被存储为 78 56 34 12。这种方式在内存地址增长的方向上按照数字的权重递增。

小端序的优点:

  • 在进行数值计算时,低位在低地址,有时可以简化数值增长和扩展的处理。
  • 对于可以变长的数据表示,添加新的字节不会改变现有字节的地址。

为什么同时存在

不同的处理器架构在设计时会选择适合自己的一种模式。例如,Intel的x86架构就是小端序,而许多网络协议和早期的RISC架构如SPARC则是大端序。这些选择往往是基于硬件设计时的考虑和历史遗留问题。

随着时间的推移,两种系统都已经被广泛应用,而且各有其优势和特定的使用场景。在多数现代架构中,如x86-64和许多ARM架构,支持在两种模式之间切换,给操作系统和应用程序提供了更大的灵活性。然而,由于这两种不同的存储方式在互操作性上可能导致问题,因此在网络协议设计中通常会选择使用网络字节顺序(大端序),以确保不同系统之间数据传输的一致性。

最低有效字节是什么意思?

最低有效字节(Least Significant Byte,简称 LSB)指的是在多字节数字中数值最小的那个字节。在数字表示中,最低有效字节代表着数值中的最低位(通常是最右边的数字在十进制表示中,或是最低的二进制位)。换句话说,对于数字的修改,最低有效字节中的任何改变将对整个数值产生最小的影响。

例如,对于一个32位的整数0x12345678(在十六进制表示中),其字节从最低位到最高位依次为:

  • 0x78(十六进制的120,二进制的01111000)是最低有效字节。
  • 0x56(十六进制的86)是第二字节。
  • 0x34(十六进制的52)是第三字节。
  • 0x12(十六进制的18)是最高有效字节(Most Significant Byte,简称 MSB)。

在小端序存储中,0x78作为最低有效字节会被放置在最低的地址。这意味着如果我们在小端序系统中查看地址从低到高的数据,我们会首先看到78

在计算机内存和数据处理中,了解哪个字节是最低有效字节非常重要,特别是在执行二进制算术运算时。对于小端序系统,最低有效字节的处理通常是首先进行的,尤其在涉及数值增长或者运算进位时。

Linux AMD APU 省电降温指南

安装软件

RyzenAdj 命令行控制AMD APU工具

Ryzen Controller 封装RyzenAdj的GUI工具(简单好用,而且支持中文)

同类型的封装RyzenAdj的GUI工具 还有RyzenAdjCtl它可以做到更加细粒度的控制这类工具主要是针对移动端的AMDAPU,对于桌面端的支持不是太好。

博主使用的是桌面端的5600G,测试时发现RyzenAdj只能控制CPU功耗,设置GPU频率不生效。

针对iGPU,可以使用这个工具Radeon Profile,它是Linux下AMD显卡的专用超频工具,虽然它没法对我们的核显超频,但是可以在首页控制核显运行频率来大幅度减少功耗。

RyzenAdj效果

在默认设置时,随便播放一个1080P视频,功耗在50W上下

手动设置功耗墙到10W

播放同样的1080P视频,功耗和温度显著降低,这时候打开任务管理器可以发现CPU占用提高很多,但丝毫不影响视频播放的性能。

Radeon Profile效果

功耗计实测

在没置功耗墙之前,整机待机功耗73W左右(7块硬盘+pcie网卡+pcie转sata卡+4根16G 3200内存),突然负载时功耗能飙到140W,满载功耗也在130W。设置功耗墙为10W后,整机功耗最多也就84W,这时候性能确实拉了,但是日常使用并用作NAS已经是绰绰有余了,非常满意!

Java 线程池 阻塞提交任务

场景

提交任务由单线程提交到线程池多线程处理,在线程池达到处理上线时可以在提交的线程阻塞等待。

方案

1.最常见的方案就是直接设置线程池的拒绝策略为 CallerRunsPolicy,当触发拒绝策略时,会将该任务直接在提交任务所在的线程直接运行该任务。这个方案有个小问题,当如果提交的任务负载很重导致提交任务的线程长时间阻塞,就会造成线程池的饥饿。

2.较可行但是有点恶心的方案,自定义阻塞策略在触发拒绝时获取任务队列阻塞提交。

public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    try {
        if (!executor.isShutdown()) {
            executor.getQueue().put(r);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new RejectedExecutionException("interrupted", e);
    }
}

这个方案也有问题:

如果你只有一个线程提交任务,而且任务的执行时间不可控,这个方案是我找到的算靠谱的了。

千万别这样用,你永远不知道别人会咋用你的线程池,一不小心就上当了!!!

3.较一般可行不那么恶心方案,自定义任务队列,直接让offer、and方法也阻塞

public class LimitedQueue<E> extends LinkedBlockingQueue<E> 
{
    public LimitedQueue(int maxSize)
    {
        super(maxSize);
    }

    @Override
    public boolean offer(E e)
    {
        // turn offer() and add() into a blocking calls (unless interrupted)
        try {
            put(e);
            return true;
        } catch(InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
        return false;
    }

}

这个方案其实挺完美的,但是唯一的问题就是线程池永远只会有coreSize个线程,在任务队列达到上限时就直接阻塞了=.=丧失了线程池的伸缩能力。

4.优雅比较可行的方案,自定义实现线程池,用信号量控制同时进入的线程,这个方案代码很完美,但是操蛋的是无法精确控制线程数量。

public class BoundedExecutor extends ThreadPoolExecutor{

    private final Semaphore semaphore;

    public BoundedExecutor(int bound) {
        super(bound, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
        semaphore = new Semaphore(bound);
    }

    /**Submits task to execution pool, but blocks while number of running threads 
     * has reached the bound limit
     */
    public <T> Future<T> submitButBlockIfFull(final Callable<T> task) throws InterruptedException{

        semaphore.acquire();            
        return submit(task);                    
    }


    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);

        semaphore.release();
    }
}
//这个方案也类似 他们问题也是一样的,就是任务执行完后线程并不是立马可用的,但semaphore释放了
class BlockingExecutor implements Executor {

    final Semaphore semaphore;
    final Executor delegate;

    private BlockingExecutor(final int concurrentTasksLimit, final Executor delegate) {
        semaphore = new Semaphore(concurrentTasksLimit);
        this.delegate = delegate;
    }

    @Override
    public void execute(final Runnable command) {
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return;
        }

        final Runnable wrapped = () -> {
            try {
                command.run();
            } finally {
                semaphore.release();
            }
        };

        delegate.execute(wrapped);

    }
}

这个方案的问题就是

  • afterExecute这个方法不是线程执行完任务最后做的事情,也就是说线程执行完afterExecute还会要执行一些任务才能返回线程池,但是这个时候我们已经执行了semaphore.release(),任务进来以后发现没有线程可用又得创建一个线程!!
  • 这个方案只能实现coreSize==maxSize,如果你尝试将任务队列长度修改和信号量长度修改,你会发现由于问题1,你总会莫名其妙的就触发了拒绝策略了
  • 线程池里的线程总会比bound要多,而且如果你的任务很快完成(非常快那种),有可能创建非常多的线程。

Linux上使用Selenium运行有头浏览器

通常我们服务器vps是没有安装gui显示的,但是为了避免使用无头浏览器(很容易被识别),我们可以用Xvfb。

Xvfb

Xvfb是一个实现 X11 显示服务器协议的显示服务器。该程序将允许您以“无头”模式运行任何应用程序。基本上,这个程序不会在物理屏幕上输出 GUI,而是创建一个虚拟帧缓冲区并在那里“显示”UI。

安装

sudo apt-get install xvfb

使用

先启动一个xvfb服务 指定id,然后我们启动项目时也指定这个id运行

 
export DISPLAY=:7 指定变量
Xvfb -ac $DISPLAY -screen 0 1280x1024x8 //比如这样 启动一个服务 指定虚拟id是7  
//然后直接运行就可以 会根据环境变量找到xvfb服务的
 java -jar xxxx.jar

可以尝试这个脚本使用 https://gist.github.com/tsl0922/ab8d370a85653c4354ad
最好的方式就是启动一个xvfb服务 这样就可以直接使用有头浏览器了
创建 一个脚本 xvfb.sh 内容如下
#!/bin/bash

XVFB=/usr/bin/Xvfb
XVFBARGS="$DISPLAY -ac -screen 0 1024x768x16"
PIDFILE=${HOME}/xvfb_${DISPLAY:1}.pid
case "$1" in
  start)
    echo -n "Starting virtual X frame buffer: Xvfb"
    /sbin/start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile --background --exec $XVFB -- $XVFBARGS
    echo "."
    ;;
  stop)
    echo -n "Stopping virtual X frame buffer: Xvfb"
    /sbin/start-stop-daemon --stop --quiet --pidfile $PIDFILE
    echo "."
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  *)
  echo "Usage: /etc/init.d/xvfb {start|stop|restart}"
  exit 1
esac
exit 0

启动方式 
bash xvfb.sh start

JackSon 注解笔记

超全的JackSon注解大全包含demo https://www.tutorialspoint.com/jackson_annotations/index.htm

  • @JsonProperty 属性注解 可以修改序列化别名、默认值、展示效果
  • @JsonView 属性和方法注解 可以在不同视图中显示不同的序列化
  • @JsonCreator 方法注解 控制序列化使用的构造函数
  • @JsonValue 属性注解 控制某属性作为序列化的唯一结果输出
  • @JsonUnwrapped 对象扁平化把子属性对象解构提取到根对象
  • @JsonTypeName 配合@JsonTypeInfo指定序列化时属性对应名称
  • @JsonTypeInfo 解决多态反序列化问题 这里的大佬总结的很好
  • @JsonSubTypes 解决多态序列化时,无法确认子类类型的问题
  • @JsonTypeIdResolver 多态序列化相关 这部分可以看这个大佬的总结
  • @JsonTypeId 指定序列化时的key值
  • @JsonRawValue 是否按照字面量序列化,就是序列化结果是字符”key”:”xxx”还是”key”:xxx
  • @JsonManagedReference, @JsonBackReference 解决循环引用 具体的案例看这里
  • @JsonInclude 可以实现根据条件过滤key或value值 比如隐藏所有null值不序列化
  • @JsonIgnoreType 标记在类上,所有以该类为类型的值都会被忽略
  • @JsonIgnoreProperties 标记在类上,控制该类哪些属性被隐藏,还可以控制遇到json字符串未知参数是否抛出异常 ignoreUnknown
  • @JsonIdentityReference @JsonIdentityInfo 解决循环引用问题 具体demo看这里 @JsonIdentityReference可以让第二次序列化的对象(存在循环引用的对象)序列化为它的id值,@JsonIdentityReference 设alwaysAsId=true会让对象直接序列化为它的id值
  • @JsonGetter 指定序列化时使用的方法,可用于定义非静态、无参数返回值(非 void)方法,用作逻辑属性的“getter”。它可以用作更通用 JsonProperty注释的替代方法(这是一般情况下的推荐选择)。Getter 是指在序列化具有该方法的类的 Object 实例时(可能继承自超类),通过该方法进行调用,并将返回值序列化为该属性的值。
  • @JsonFormat 序列化时指定格式,常用于各种时间格式
  • @JsonFilter 定义一个过滤器的名称 在序列化时根据该名称指定序列化器 具体demo看这里
  • @JsonAnySetter 该注解允许我们把一个可变的map属性作为标准属性, 在反序列过程中, 从Json字符串得到的属性值会加入到map属性中,可以用它来存不存在于类中的属性。
  • @JsonAnyGetter 该注解用于把可变的Map类型属性当做标准属性,和@JsonAnySetter一起使用
  • @JacksonInject 指定属性是注入的而不是从Json字符串中反序列化获取
  • @JsonAutoDetect 可以覆盖可见性,可以指定属性的可见性
  • @JacksonAnnotation,@JacksonAnnotationsInside 属于JackSon的元注解

@JsonProperty

注意:虽然官方文档说 该注解如果和@JsonIgnore一同使用,@JsonIgnore 则优先于此属性。但实际测试用发现如果两个注解同时存在,效果等同 READ_ONLY,序列化都能展示,反序化不能写入。


String value: 指定序列化key
String defaultValue: 指定key的默认值
boolean	required:是否必须,但请注意,从 2.6 开始,此属性仅用于 Creator 属性,以确保 JSON 中存在属性值:对于其他属性(使用 setter 或可变字段注入的属性),不执行验证,也就是说只和@JsonCreator一起使用时生效。
int index: 指定该字段排序
JsonProperty.Access access: 序列化权限控制 有下列四种

  • AUTO 自动确定此属性的读取和/或写入访问权限。
  • READ_ONLY 只能在序列化时读取,而在反序列化期间不能写入(设置)。
  • READ_WRITE 无论可见性规则如何,都将访问该属性以进行序列化(将值写为外部表示)和反序列化(从外部表示中读取值)。
  • WRITE_ONLY 只能被写(set)用于反序列化,而不会被读(get)在序列化时,即该属性的值不包含在序列化中。

序列化权限控制测试代码:MyTest.java

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data
public class MyTest {

    @JsonProperty(access = AUTO)
    public String myA;

    @JsonProperty(access = READ_ONLY)
    public String myB;

    @JsonProperty(access = WRITE_ONLY)
    public String myC;

    @JsonProperty(access = READ_WRITE)
    public String myD;

    public static void main(String[] args) throws JsonProcessingException {
        MyTest myTest = MyTest.builder().myA("A").myB("B").myC("C").myD("D").build();
        ObjectMapper mapper = new ObjectMapper();
        String toJson = mapper.writeValueAsString(myTest);
        System.out.println("=======预期打印======");
        System.out.println("{\"myA\":\"A\",\"myB\":\"B\",\"myC\":\"C\",\"myD\":\"D\"}");
        System.out.println("=======序列化打印=====");
        System.out.println(toJson);
        System.out.println("=======反列化打印=====");
        String fromJson = "{\"myA\":\"A\",\"myB\":\"B\",\"myC\":\"C\",\"myD\":\"D\"}";
        MyTest test = mapper.readValue(fromJson,MyTest.class);
        System.out.println(test);
    }
}
输出结果:
=======预期打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
MyTest(myA=A, myB=B, myC=C, myD=D)
=======序列化打印=====
{"myA":"A","myB":"B","myD":"D"}
=======反列化打印=====
MyTest(myA=A, myB=null, myC=C, myD=D)

@JsonCreator

JackSon默认使用无参构造方法和set方法反序列对象,使用该注解可以指定JaskSon使用指定方法进行反序列化构造对象,可以标注在构造方法和静态工厂方法上。

@JsonView

@JsonView使用方法:

  1.使用接口来声明多个视图 例如下面这个 代码来自baeldung.com

public class Views {
    public static class Public {
    }

    public static class Internal extends Public {
    }
}
public class Item {
 
    @JsonView(Views.Public.class)
    public int id;

    @JsonView(Views.Public.class)
    public String itemName;

    @JsonView(Views.Internal.class)
    public String ownerName;
}

  2.在pojo的属性上指定视图

public class Item {
 
    @JsonView(Views.Public.class)
    public int id;

    @JsonView(Views.Public.class)
    public String itemName;

    @JsonView(Views.Internal.class)
    public String ownerName;
}

  3.在Controller方法上指定视图

@JsonView(Views.Internal.class)
@RequestMapping("/items/internal/{id}")
public Item getItemInternal(@PathVariable int id) {
    return ItemManager.getById(id);
}

4.直接进行序列化或反序列化时可以指定视图

@Test
public void whenUseJsonViewToDeserialize_thenCorrect() 
  throws IOException {
    String json = "{"id":1,"name":"John"}";

    ObjectMapper mapper = new ObjectMapper();
    User user = mapper
      .readerWithView(Views.Public.class)
      .forType(User.class)
      .readValue(json);

    assertEquals(1, user.getId());
    assertEquals("John", user.getName());
}

@JsonValue

@JsonView是jackson json中的一个注解,指定属性后序列化将只使用该属性值作为序列化接口(这个注解只能作用于一个属性上)。

@JsonUnwrapped

@JsonUnwrapped 对象扁平化 如果属性序列化后是一个对象 会将该属性的对象解构提取到根对象中。

@JsonTypeName

用于绑定被注释类所具有的逻辑名称的注释。与JsonTypeInfo(特别是JsonTypeInfo.use()属性)一起使用以建立对象名称和属性之间的关系,反序列化为父类时,用于确定该对象的具体类型,与@JsonSubTypes 直接标注在父类等效。

@JsonTypeInfo

用于多态类型处理

Class<?> defaultImpl 指定默认的反序列化类型,当反序列对象无法映射到现在有的指定类型时会使用它进行反序列化。

JsonTypeInfo.As include 指定类型标识信息的展示方式。
有下列5种可选值 下面的测试结果使用的注解是@JsonTypeInfo(use= JsonTypeInfo.Id.NAME)

PROPERTY 使用单个可配置属性的包含机制,与实际数据(POJO 属性)一起作为单独的元属性包含在内。,这个属性的值由 @JsonTypeInfo注解的property确定,否则就使用不同use情况下的默认值(@class、@c、@type)。

@JsonTypeInfo(use= JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.PROPERTY )
结果:
=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印=======
{"@type":"MyTest","myA":"A","myB":"B","myC":"C","myD":"D"}

EXISTING_PROPERTY 与PROPERTY区别在于,该注解在序列化时不会输出标识符,反序列流程根PROPERTY相同。

EXTERNAL_PROPERTY 只作用于属性上,把子属性的标识符提升到根对象里,具体使用场景没搞明白。

WRAPPER_OBJECT 包裹在一个对象中,相当于在外层创建一个父对象 {标识符:{原本的对象}} 用一个大对象包住

@JsonTypeInfo(use= JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY )
结果:
=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印=======
{"MyTest":{"myA":"A","myB":"B","myC":"C","myD":"D"}}

WRAPPER_ARRAY 包裹在一个数组中。

@JsonTypeInfo(use= JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.WRAPPER_ARRAY )
结果:
=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印=======
["MyTest",{"myA":"A","myB":"B","myC":"C","myD":"D"}]

JsonTypeInfo.Id use 指定在序列化时类型标识信息展示的值。
有下列5种可选值

CLASS 意味着使用完全限定的 Java 类名作为类型标识符。

测试结果:可以看到序列化对象多了一个 @class key,而且其值为全限定类名。(若不指定property则默认为@class

=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印========{"@class":"com.example.demo.bean.MyTest","myA":"A","myB":B,"myC":"C","myD":"D"}

CUSTOM 意味着键入机制使用自定义处理,可能具有自定义配置。这个注解需结合property属性和@JsonTypeIdResolver一起使用,指定类标识符的值。

@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = "type")
@JsonTypeIdResolver(JacksonTypeIdResolver.class)
实现TypeIdResolver接口 自定义序列化流程

MINIMAL_CLASS 表示使用具有最小路径的 Java 类名作为类型标识符,多了一个”@c“字段,其值为最小路径类名。(若不指定property则默认为@c

=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印=======
{"@c":".MyTest","myA":"A","myB":"B","myC":"C","myD":"D"}

NAME 表示使用逻辑类型名作为类型信息;然后需要将名称单独解析为实际的具体类型(类),多了一个”@type”字段,其值为类名。(若不指定property则默认为@type

=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印=======
{"@type":"MyTest","myA":"A","myB":"B","myC":"C","myD":"D"}

NONE 这意味着不包含显式类型元数据,并且键入纯粹是使用上下文信息完成的,可能会增加其他注释。

=======未配置注解打印======
{"myA":"A","myB":"B","myC":"C","myD":"D"}
=======配置注解打印=======
{"myA":"A","myB":"B","myC":"C","myD":"D"}

String property 指定类标识名称,在include=JsonTypeInfo.As.PROPERTY或use=JsonTypeInfo.Id.CUSTOM生效,其他情况使用默认的识别码名称。
注意:include=JsonTypeInfo.As.PROPERTY和property同时存在有个问题,如果POJO具有相同名称的属性,会出现两个!

@JsonSubTypes

用来列出给定类的子类,只有当子类类型无法被检测到时才会使用它,也可以在子类上直接使用@JsonTypeName 实现同等效果。

Sentinel 面板数据空白解决方案

博主最近不小心买了很多吃灰服务器,正好可以拿去Java微服务相关,基于选新不选旧原则,直接开始学习SpringCloud。学习的过程中,遇到过两次sentinel面板数据空白的问题,先说解决方案

1.部署sentinel服务器和部署微服务服务器必须要开放对应端口!!sentinel的实时监控是通过调用机器Adapter获取实时监控的。

2.时间和时区要一致!!!(博主的吃灰服务器主要是欧洲和美国的,但是部署的时候发现,sentinel只有微服务启动的时候才会显示实时监控,一段时间后就不显示了,这就是时间和时区不一致导致的)

迁移tomcat10 XXX cannot be cast to jakarta.servlet.Filter 解决方案

之前公司有个老项目(struts2+ibatis)的要升级到迁移tomcat10,结果死活无法起来。

看来下日志 报错都是 XXX cannot be cast to jakarta.servlet.Filter,搜了半天终于整出了解决方案。

报错原因是坑爹的tomcat10把javax.servlet-api名叫jaraka.servlet了(这不是蛋疼吗!!!)

解决方案有俩

1.修改代码,手动把包引用从 Javax.XXX改成 Jaraka.XXX 然后编译

2.使用apache官网提供的迁移工具 tomcat-jakartaee-migration 对编译后的项目处理一下,具体使用可以去看下项目的描述,一行命令就可以执行了。

这里提供一个现成的下载

具体使用方法:

如果是linux系统,进入bin目录,bash migrate.sh 旧项目(支持文件夹和war包) 生成的新项目(支持文件夹和war包),例如 bash migrate.sh old.war new.war。

如果是window系统,进入lib目录, java -jar jakartaee-migration-1.0.0.jar old new,跟上面差不多,脚本里就是执行的jakartaee-migration-1.0.0.jar。

ps:如果还不能启动,看看原本项目中pom.xml的javax.servlet-api依赖范围scope是否改成了provided,如果没有还是会有那个报错哦。

HostHatch 独立日优惠

因为Chia币的影响,储存机型都普遍涨价了,但这次普遍流量都给的很多,特别是nvme机。

两年付的性价比依旧可以的,购买方法:

1.注册账号存入资金 https://hosthatch.com/a?id=1837

2.点击下列的购买链接下单(要先预存余额才能购买),如果是两年付,需要额外发送工单获取两年付的特惠.

Storage (only available in Chicago – and very limited quantity):

1x 2.4+ GHz
512 MB RAM
250 GB disk
1 TB bandwidth
$15 per year
Pay for two years (+$7) – get doubled RAM and +9 TB free bandwidth
https://manage.hosthatch.com/billing/order/chi-250g-storage
1x 2.4+ GHz
1 GB RAM
1 TB usable storage
3 TB bandwidth
$40 per year
Chicago
Pay for two years – get doubled RAM and +20 TB free bandwidth
https://manage.hosthatch.com/billing/order/chi-1tb-storage/


NVMe plans (Europe – Amsterdam, Stockholm, Zurich, Oslo, Vienna, Warsaw, London, Madrid and Milan)

1 CPU core (12.5% dedicated, burstable up to 100%)
1 GB RAM
10 GB RAID-10 NVMe
1 TB bandwidth
$15 per year
Pay for two years – get doubled RAM, storage, and +5 TB free bandwidth
https://manage.hosthatch.com/billing/order/nvme1-ams
https://manage.hosthatch.com/billing/order/nvme1-sto
https://manage.hosthatch.com/billing/order/nvme1-zrh
https://manage.hosthatch.com/billing/order/nvme1-osl
https://manage.hosthatch.com/billing/order/nvme1-vie
https://manage.hosthatch.com/billing/order/nvme1-waw
https://manage.hosthatch.com/billing/order/nvme1-lon
https://manage.hosthatch.com/billing/order/nvme1-mad
https://manage.hosthatch.com/billing/order/nvme1-mil
2 CPU cores (50% dedicated, burstable up to 200%)
4 GB RAM
20 GB NVMe SSD
5 TB bandwidth
$30 per year
Pay for two years – get doubled RAM, storage, and +15 TB free bandwidth
https://manage.hosthatch.com/billing/order/nvme4-ams
https://manage.hosthatch.com/billing/order/nvme4-sto
https://manage.hosthatch.com/billing/order/nvme4-zrh
https://manage.hosthatch.com/billing/order/nvme4-osl
https://manage.hosthatch.com/billing/order/nvme4-vie
https://manage.hosthatch.com/billing/order/nvme4-waw
https://manage.hosthatch.com/billing/order/nvme4-lon
https://manage.hosthatch.com/billing/order/nvme4-mad
https://manage.hosthatch.com/billing/order/nvme4-mil
3 CPU cores (100% dedicated, burstable up to 300%)
8 GB RAM
40 GB NVMe SSD
10 TB bandwidth
$60 per year
Pay for two years – get doubled RAM, storage, and +20 TB free bandwidth
https://manage.hosthatch.com/billing/order/nvme8-ams
https://manage.hosthatch.com/billing/order/nvme8-sto
https://manage.hosthatch.com/billing/order/nvme8-zrh
https://manage.hosthatch.com/billing/order/nvme8-osl
https://manage.hosthatch.com/billing/order/nvme8-vie
https://manage.hosthatch.com/billing/order/nvme8-waw
https://manage.hosthatch.com/billing/order/nvme8-lon
https://manage.hosthatch.com/billing/order/nvme8-mad
https://manage.hosthatch.com/billing/order/nvme8-mil


NVMe plans (North America – Los Angeles, Chicago and New York):

1 CPU core (12.5% dedicated, burstable up to 100%)
1 GB RAM
10 GB RAID-10 NVMe
1 TB bandwidth
$15 per year
Pay for two years – get doubled RAM, storage, and +5 TB free bandwidth
https://manage.hosthatch.com/billing/order/nvme1-lax
https://manage.hosthatch.com/billing/order/nvme1-ny
https://manage.hosthatch.com/billing/order/nvme1-chi
2 CPU cores (50% dedicated, burstable up to 200%)
4 GB RAM
20 GB NVMe SSD
5 TB bandwidth
$30 per year
Pay for two years – get doubled RAM, storage, and +15 TB free bandwidth
https://manage.hosthatch.com/billing/order/nvme4-lax
https://manage.hosthatch.com/billing/order/nvme4-ny
https://manage.hosthatch.com/billing/order/nvme4-chi
3 CPU cores (100% dedicated, burstable up to 300%)
8 GB RAM
40 GB NVMe SSD
10 TB bandwidth
$60 per year
https://manage.hosthatch.com/billing/order/ams-16g-nvme
Pay for two years – get doubled RAM, storage, and +20 TB free bandwidth
https://manage.hosthatch.com/billing/order/nvme8-lax
https://manage.hosthatch.com/billing/order/nvme8-ny
https://manage.hosthatch.com/billing/order/nvme8-chi


NVMe plans (APAC – Hong Kong and Sydney):

1 CPU core (12.5% dedicated, burstable up to 100%)
1 GB RAM
10 GB RAID-10 NVMe
500 GB bandwidth
$15 per year
Pay for two years – get doubled RAM, storage, and bandwidth
https://manage.hosthatch.com/billing/order/nvme1-hkg
https://manage.hosthatch.com/billing/order/nvme1-syd
2 CPU cores (50% dedicated, burstable up to 200%)
4 GB RAM
20 GB NVMe SSD
1 TB bandwidth
$35 per year
Pay for two years – get doubled RAM, storage, and bandwidth
https://manage.hosthatch.com/billing/order/nvme4-hkg
https://manage.hosthatch.com/billing/order/nvme4-syd
3 CPU cores (100% dedicated, burstable up to 300%)
8 GB RAM
40 GB NVMe SSD
2 TB bandwidth
$65 per year
Pay for two years – get doubled RAM, storage, and bandwidth
https://manage.hosthatch.com/billing/order/nvme8-hkg
https://manage.hosthatch.com/billing/order/nvme8-syd


Bundles:

Choose any 7 locations, 1 VM per location:

1 CPU core (12.5% dedicated, burstable up to 100%)
1 GB RAM
10 GB RAID-10 NVMe
1 TB bandwidth
$65 per year

To order, login to your account with us, top up the credit, and open a sales ticket with the 7 locations of your choosing.
All locations bundle, 1 VM per location:

1 CPU core (12.5% dedicated, burstable up to 100%)
1 GB RAM
10 GB RAID-10 NVMe
1 TB bandwidth
$110 per year

To order, login to your account with us, top up the credit, and open a sales ticket.