Jasper Ji

博观而约取,厚积而薄发。

乔布斯去世十周年

2021-10-06 15:12

移动市场发展缓慢

经过十年的发展,移动市场的机会似乎越来越少了。我也从iOS开发者,转做服务端开发了。iPhone是越来越贵了,我的6s已经扛过了第五个年头了。随着个人开发技能的提高,我现在反而喜欢纯粹的Linux手机。不过这类手机太少了,淘宝上购买的PinePhone自从6月中旬购买后,到现在也没有到货,只能寄希望于国庆后了。

移动设备的性能已经高过了需求,有些东西正在朝着另外一些方向转移,比如物联网。不过我观察了半天感觉这块市场太碎了,不好插手。

乙川弘文

十年间乔布斯相关的书籍出版不少,即使连给乔布斯做过寿司的老板也出书了,可是关于乙川弘文的书籍却没有出版,早期确实是没有的,不过后来有人根据他生前的录音整理了一本关于他的书籍《kobun-sesshin-talks》,后来16年出版后叫《Embracing Mind》。不过这么些年过去了,此书的中文版一直没有面世,我买过此书的英文版,大略的毒了一遍,觉得这事一本跟《禅者的初心》不太一样的书籍,对于打坐修行的人来说是非常有参考价值,从去年开始我就利用机器翻译加人工校对的形式在整理此书,最近终于把剩余的给全部弄完了。已经放到了GitHub上《kobun-sesshin-talks》,喜欢的可以去看看,欢迎共同完善。

养猫日记

2021-10-01 22:20

最近养了只NY11的金渐层妹妹,大概已经半个多月了,谈谈一些感受。

猫毛和灰尘,戴森吸尘器

猫毛无处不在,关键会有一些比较小的绒毛很容易飞在空气中,搞不好就回吸进去,所以也能理解有些人猫过敏。灰尘弥漫,猫经常会发疯似得满屋子狂奔,床底平时不太打扫得到,很容易被猫带出来,养猫后灰尘感觉弥漫在空气一样。面对这两个问题,我狠心买了个戴森吸尘器V10,首先这个确实可以把地板上散落的猫毛和灰尘以及一些杂质给收集起来,另外对于椅子上的猫毛也能清理,但还是有照顾不到的地方,总的来说解决一些问题。

危险

防止猫触发水龙头,一般的水龙不太会有问题,不过类似面盆之类的水龙头只需要简单的抬起和按下,这类水龙会有隐患。

Virtualbox CentOS 8扩容'

2021-09-26 15:28

本来想在虚拟机上安装TDengine试试,经过一番折腾后发现磁盘容量不足,当时创建虚拟机时选择的是8G,这就尴尬了,最后还是一番折腾后终于扩容成功。

VirtualBox

先关闭虚拟机,在虚拟机运行目录下执行。

VBoxManage modifyhd /Users/jasperji/VirtualBox\ VMs/centos8/centos8.vdi --resize 15360 

这里我把容量扩展为15G,记住路径中空格的问题。

CentOS

查看磁盘容量情况

df -h

操作分区,选项n,创建新分区。

fdisk /dev/sda

创建PV(物理卷)

pvcreate /dev/sda3

扩展到卷组,我们vgdisplay命令查看一下自己所在的卷组:

pvdisplay

看到VG Name是cl,所以进一步扩展到卷组:

vgextend cl /dev/sda3

扩展到逻辑分区,使用lvextend(logical volume extend逻辑卷扩展)

lvextend /dev/cl/root /dev/sda3

我们df -h查看一下文件系统的磁盘空间占用情况:

df -h

这里我们发现磁盘没有按照预期的扩容,因为我们没有刷新逻辑分区的容量。

于是,刷新逻辑分区的容量,使用xfs_growfs(同步文件系统)命令,注意上面的Mounted on是挂载点,这里我们的挂载点就是根目录:

xfs_growfs /

最后就扩容成功了。

总结

其实之前阿里云正式服务器的时候,也记得有挂载过当时购买的云硬盘。不过时间久了,当时也没有记录一些东西,也就忘了。

参考

CentOS8扩容
VirtualBox虚拟机硬盘扩容及LVM命令介绍
VirtualBox文件系统已满–磁盘扩容

学习Java字节码

2021-09-08 09:21

Java字节码只是简单的了解,感觉缺乏深入的了解,特写此篇记录下。

准备一个HelloWorld的测试类。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

编译生成HelloWorld.class文件

javac HelloWorld.java

我们使用javap命令来查看class文件

javap -v HelloWorld.class

输出结果

Classfile /Users/jasperji/eclipse-workspace/maventest/src/main/java/com/jasper/ji/maven/test/HelloWorld.class
  Last modified 2021-9-8; size 452 bytes
  MD5 checksum 1f346aeb85559b06180507b8838406dd
  Compiled from "HelloWorld.java"
public class com.jasper.ji.maven.test.HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #18            // Hello, World!
   #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #21            // com/jasper/ji/maven/test/HelloWorld
   #6 = Class              #22            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               HelloWorld.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = Class              #23            // java/lang/System
  #17 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;
  #18 = Utf8               Hello, World!
  #19 = Class              #26            // java/io/PrintStream
  #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V
  #21 = Utf8               com/jasper/ji/maven/test/HelloWorld
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/String;)V
{
  public com.jasper.ji.maven.test.HelloWorld();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello, World!
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 5: 0
        line 6: 8
}
SourceFile: "HelloWorld.java"

另外也可以直接查看二进制,这里使用hexdump。

hexdump HelloWorld.class

不过感觉还是javap提供的这个比较人性化,更好的阅读。

总结

字节码作为一种中间形式,Java可以编译成字节码,Scala也可以编译成字节码,但是从语言层面他们又是不一样的。这个也让我重新再读了下《Java程序员修炼之道》这本书,原来对于书中第三部分JVM上的多语言编程,不是很感冒。但字节码并不是机器码,所以在理解某些问题时最终还是要落到汇编语言级别的。

参考

字节码增强技术探索

学习JNI的使用

2021-09-07 13:40

JNI(Java Native Interface)意为Java本地接口,虽然使用Java有段时间了,但对这个并不太了解。这个是基于网上老外的一篇文章的总结,环境是Mac OS

public class HelloWorldJNI {
	static {
        System.loadLibrary("native");
    }
    
    public static void main(String[] args) {
        new HelloWorldJNI().sayHello();
    }

    // Declare a native method sayHello() that receives no arguments and returns void
    private native void sayHello();
}

使用命令生成头文件

javac -h . HelloWorldJNI.java

生成如下的com_jasper_ji_maven_test_HelloWorldJNI.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jasper_ji_maven_test_HelloWorldJNI */

#ifndef _Included_com_jasper_ji_maven_test_HelloWorldJNI
#define _Included_com_jasper_ji_maven_test_HelloWorldJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_jasper_ji_maven_test_HelloWorldJNI
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_jasper_ji_maven_test_HelloWorldJNI_sayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

我们再创建一个同名cpp文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "com_jasper_ji_maven_test_HelloWorldJNI.h"
#include <iostream>
/*
 * Class:     com_jasper_ji_maven_test_HelloWorldJNI
 * Method:    sayHello
 * Signature: ()V
 */
void JNICALL Java_com_jasper_ji_maven_test_HelloWorldJNI_sayHello (JNIEnv *env, jobject obj)
{
    std::cout << "Hello from C++ !!" << std::endl;
}

编译文件,生成com_jasper_ji_maven_test_HelloWorldJNI.o的文件

g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_jasper_ji_maven_test_HelloWorldJNI.cpp -o com_jasper_ji_maven_test_HelloWorldJNI.o

生成动态库

g++ -dynamiclib -o libnative.dylib com_jasper_ji_maven_test_HelloWorldJNI.o -lc

运行Java,这里需要注意的是-Djava.library.path路径我是把libnative.dylib这个文件路径放在com的根目录下的,也就是当前目录。

java -cp . -Djava.library.path=. com.jasper.ji.maven.test.HelloWorldJNI

总结

平时不太写C/C++的代码,所以有点生,不过之前对C的研究还是起了不少的帮助。JNI虽然提供了调用其他语言的功能,但是这是比较麻烦的,不同的平台需要编译对应的库。早前在做安卓的时候,倒是有简单的运行过NDK的例子,不过那会并没有专门研究下JNI。

参考

Guide to JNI (Java Native Interface)

MySQL实践

2021-08-13 13:18

记录一些实际工作中MySQL的使用问题和新的。

给新增字段设置为NULL的问题

字段不为NULL,原来的表新增一个字段,但这个字段又是不能为空,如果设置字段不为NULL,因为之前的是空,所以会报错。

开源仓储系统Jeewms使用指南

2021-07-02 13:08

最近找一款开源仓储系统,最好使用Java开发,发现Jeewms还不错,也有演示Demo。Gitee上大概有3.2K的Star,Github虽然也放了一个,但我看好像没有什么人关注。

Java

主要遇到的坑是JDK版本一定要是Java 8,我本地因为安装最新的Eclispe时安装了Java 11,结果编译后报各种错,一直没有跑起来,主要是Java 11去掉了某些库。最后设置JAVA_HOME为Java 8后就好了。

数据库

这个项目在数据库的设计上字段名称上有些使用英文命名,业务部分的字段是拼音命名,好在不是简写的,另外也有个数据库设计文件可以参考,字段上也有注释,对于习惯了使用英文命名的人来说可能会想着修改,但是还是有难度的,不建议重构。

也使了用视图,知道这个东西,但实际项目中并没有使用过,如果没有用过的需要注意下。

也使用了触发器的东西,也需要注意下,如果是直接拿项目里面的sql文件还原的话问题不大,但如果是重新导出sql的时候一定要注意,触发器这些设置也要一并导出,像我使用的MySQL Workbench默认是没有勾选的,而我也没有太注意是否使用了触发器,结果本地好着了,正式服务器却发现有问题,一查看是一个字段没有更新的缘故,习惯性的在代码里面查找哪里有修改,结果没有发现,查看二进制日志后,想到应该是触发器的问题,果然是通过触发器更新的,而服务器上的问题是因为导出的sql没有勾选触发器的缘故。

架构方面

这个使用Tomcat+Spring MVC,并不是现在流行的SpringBoot,所以对于只接触过SpringBoot的人需要注意下。操作数据方面使用的是Hibernat,反正没有用过,只使用过Mybatis,感觉还是需要学习下的。视图方面使用的是JSP,之前只使用Thymeleaf。

业务规则

这块并没有详细的文档说明,如果没有做个仓储系统的,需要修改一些东西还是会有点摸不着头绪,需要好好的厘清下。最好还是找一些仓储方面的资料对照着理解项目。

总结

整个项目时可用的,但要重构架构的话可能比较有难度,因为并不是最新的技术,不是很适合拿来学习,如果不了解之前的这类项目的开发技术的话,倒也是一种参考。

学习Zookeeper的使用

2021-06-22 15:03

ZooKeeper没有直接用过,所以想研究下,本来读《ZooKeeper:分布式过程协同技术详解》,感觉还是很模糊,虽然大概明白分布式会需要这样一个东西,现在使用的Spring微服务中Eureka跟ZooKeeper有相似的地方。纸上得来终归浅,所以觉得跑一些实际的例子。

安装

我的环境是Mac,使用Brew安装。

可视化界面

ZooKeeper自带的zkCli命令行工具,其实也能用。也有可视化的界面工具ZKUI,最后使用的ZKUI。

客户端

使用的Java跑的例子,有点类似数据的增删改查了,当然也有监听。

public class Main {
	// 连接地址及端口号
	private static final String SERVER_HOST = "127.0.0.1:2181";

	// 会话超时时间
	private static final int SESSION_TIME_OUT = 2000;

	public static void main(String[] args) throws Exception {
		// 参数一:服务端地址及端口号
		// 参数二:超时时间
		// 参数三:监听器
		ZooKeeper zooKeeper = new ZooKeeper(SERVER_HOST, SESSION_TIME_OUT, new Watcher() {
			public void process(WatchedEvent event) {
				// TODO Auto-generated method stub
				// 获取事件的状态
				Event.KeeperState state = event.getState();
				// 判断是否是连接事件
				if (Event.KeeperState.SyncConnected == state) {
					Event.EventType type = event.getType();
					if (Event.EventType.None == type) {
						System.out.println("zk客户端已连接...");
					}
				}
			}
		});
		zooKeeper.create("/go", "Hello World".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		System.out.println("新增ZNode成功");
		zooKeeper.close();
	}
}

更高级的可以使用Curator,出了基本的客户端功能外,还提供了锁、选举、屏障、缓存、持久化节点、队列这样的功能。

参考: ZooKeeper入门,看这篇就够了!

书籍

目前的书籍不多,在省图找到了这本《ZooKeeper:分布式过程协同技术详解》,此书不太适合一点经验都没有的人阅读, 相对来说偏实战了。此书还在读,目前来看结构清晰,推荐。吐槽下《ZooKeeper:Distributed Process Coordination》的中文版翻译为《ZooKeeper:分布式过程协同技术详解》,把“Process”翻译为“过程”确实没有“进程”或者“程序”好。ZooKeeper官方的说明是一种协调分布式服务的应用程序,这个其实很贴合意思。

总结

我还是习惯了从代码理解原理,这么跑下来,至少从代码的角度是理解了。初看有点简单,不就是一些节点数据么,但这样也很容易陷入技术细节,所以还是要看几个应用场景的实际例子,从整体上理解。

参考:

原创ZooKeeper入门实战教程,这个博主系列文章非常不错,浅显明了。

Zookeeper 应用实例,入门级的例子。

《详谈:左晖》读后感

2021-06-17 22:33

左晖这个人要不是最近因为去世,我估计也不太知道是谁。首次听到链家,那会觉得是一家新起来的互联网的网站,感觉好像很是风口,因为挖了不少技术的牛人过去。自己那会打算买房时也专门下载了链家的APP,不过感觉那上面的房子好像偏贵。而贝壳呢?好像那会广告打的比较凶。近一两年发现,发现附近多了好多叫德佑的房产中介,最近跟一位卖房的中介聊天时才发现德佑跟贝壳的关系。作为技术人我非常好奇他是如何实现传统行业加互联网的逆袭的?因为我最近两年一直在传统企业做相关的系统,但是成效很低,所以非常想一睹左晖的思路。

《详谈左晖》是本不到180页的32开小册子,我大概用了2个多小时读完了此书。主要是17年和20年对左晖的访谈内容。左晖虽然从事的是传统行业,实际上他是计算机专业毕业,只不过人家没有做技术,首先做过保险,后来因为政策的缘故,改做卖房中介,链家其实很早了,2001年就创建了,虽然早期也有网站,但实际主要做线下了,链家实际是一家有着IT基因的公司,这点很关键。另一家公司就是京东,一开始是摆柜台,后来借助互联网,终成巨头。左晖一直强调传统行业在基础方面的薄弱,主要体现在战略、组织、信息化、IT方面。个人深有体会,传统的中小企业重业务,流程上比较灵活,信息化还停留在表格的阶段。

总结

传统行业的互联化一定要紧密建立在业务环节,并且要能够利用数字以及互联网来优化或者抽象化一些细节流程,这样才能有所作为,当然也很容易变成信息化与流程的脱节问题,关键是在于落实。

初试WebAssembly

2021-06-02 20:02

听闻WebAssembly已经有些年了,不过一直没有跑个例子尝试下。主要是使用Rust来编译生成WebAssembly的目标文件,虽然可以使用C/C++,但想想我的Rust学习一直进展不大,不知道用在哪里,刚好Rust对WebAssembly支持也是比较详细。

Rust问题

安装wasm-pack时提示没有安装rustup,虽然我已经哟给Brew安装了rust,最后安装rustup后就好了。

执行cargo install cargo-generate时,加载Crates非常慢,最后使用国内的镜像后顺利完成,这是国内镜像的配置。

[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
# 指定镜像
replace-with = 'sjtu'

# 清华大学
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"

# 中国科学技术大学
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"

# 上海交通大学
[source.sjtu]
registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index"

# rustcc社区
[source.rustcc]
registry = "https://code.aliyun.com/rustcc/crates.io-index.git"

总结

我在iOS的Safari试了下,也可以。虽然之前也有其他语言编译为JS的做法,所以主要解决的是如何构建大型web应用的工程问题,现在ES6的普及,好像这类方案渐渐的也不怎么提了。其他语言编译成WebAssembly的做法,主要是为解决性能的问题,把一些跟性能有关系使用WebAssembly,另外WebAssembly可以解决原来JS的老是暴露的问题。理论上其他语言都可以编译WebAssembly,但是主流的还是C/C++、Go、Rust之类的编译为WebAssembly的方式了,不过

Web开发我不是全职的那种,有需要了就写写。感觉一般Web开发者也不大会用到,有性能要求的应用可能会用到,但估计写WebAssembly估计也是领域专业的人员。

参考资料

Rust 🦀 and WebAssembly 🕸 ,例子主要按这个来跑的。

WebAssembly Mozilla开发者网站关于WebAssembly的介绍,比较详细。