浅析Java强大的动态Instrumention能力

前言

在前面的博客中,我写过一句话,叫做

Java世界里的一切东西都是在拼Java命令行参数

如果你使用IDEA,并且在运行 Java 代码时观察过 IDEA 帮我们拼出来的命令行参数,举个例子

D:\jdk8\jdk1.8.0_232\bin\java.exe "\"-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 201.4865.12\lib\idea_rt.jar=61840:C:\Program Files\JetBrains\IntelliJ IDEA 201.4865.12\bin\"" -Dfile.encoding=UTF-8 -classpath ( 省略一系列依赖Jar包 ) C:\Users\25959\Desktop\test\target\classes com.ayang818.test.Test

这是我运行一个很简单的程序,IDEA 帮我们拼出来的命令行参数,其中 -Dfile.encoding 和 -classpath 我们都很熟悉,一个是指定编码方式,另一个是指定 classpath 路径。但是有一个我们可能很陌生的参数,叫做 -javaagent , agent 翻译成中文是代理的意思。于是我开始了一天的探究过程。

常用的一些算法板子(持续更新)

持续更新的一些算法板子

更详细的题目或题解可以查看我的刷题仓库

序列化动态规划解题技巧

序列化动态规划解题技巧总结

序列化动态规划属于动态规划中的基础题,这类题目通常是一组序列。

这类题目一般有一种比较通用的状态转移方程
$$
dp[i][aa]=Option_1^{i-1}(dp[i-1][bb])+cast_i
$$
其实这种题目在代码上也有一些小技巧

  1. 如果使用递推时间代码,让动态规划有效状态的下表从 1 开始,把下表 0 让给一步决策都没有做的初始状态。通常这样做,可以让边界处理简单不少。
  2. 其次是主动转移和被动转移,主动转移是从一个状态去找这个这个状态可以转移到什么状态;被动转移是去找这个状态是由什么状态转移来的。

寒假开始啦! 开始进行Kugga的基础设施建设了!

寒假博客应该不怎么会更新了。我的Kugga计划也提上日程了。寒假里的一些知识记录部分会以文档的形式更新在Kugga-wiki上面,感兴趣也可以关注下。

我 的 2 0 1 9

2019年对我而言算是非常重要的一年吧,这里也正好理理这一年我都干了些什么。

maven模块化最小实践

为什么要进行maven模块化

在说模块化之前,不妨说说非模块化的项目是怎么样的,非模块化的项目往往是一个单体应用,他的目录结构如下

为什么说是单体的呢,事实上

  1. 上面看到的所有的包比如controller,mapper,utils,
    , 这些一个个应用里的功能都是业务的一部分,到时候打jar包的时候其实就是把这些所有的功能打到同一个jar包中。然后运行就可以了。
  2. 整个项目只有一个pom文件,功能与项目强耦合,代码复用能力差。

那么对于一个多模块项目来说呢,他的目录结构如下

使用0xff来保证二进制补码的一致性

写这篇文章的起因

本来今天在写浅析分布式唯一ID生成算法——snowflake的实现这篇博客的时候,写的好好的,但是写到一种生成方式

UUID.randomUUID().toString();

发现自己并不是很知道这个怎么实现的,然后点开了源码打算读一下。结果就发现了一段代码。

/*
* Private constructor which uses a byte array to construct the new UUID.
*/
private UUID(byte[] data) {
long msb = 0;
long lsb = 0;
assert data.length == 16 : "data must be 16 bytes in length";
for (int i=0; i<8; i++)
msb = (msb << 8) | (data[i] & 0xff);
for (int i=8; i<16; i++)
lsb = (lsb << 8) | (data[i] & 0xff);
this.mostSigBits = msb;
this.leastSigBits = lsb;
}

其中有一小段(下方代码段)我不是很理解有什么作用,因为data[i]的类型实际上是byte类型的,byte的十进制范围是-128-127,而0xff的十进制是15 * 16 + 16 = 256,转化为八位二进制就是11111111,我想着data[i] & 0xff的话是使用0xff做截取操作,但是byte转化为二进制的长度肯定在8位以内,所以这个截取操作第一眼看起来并没有什么用哈?

data[i] & 0xff

浅析分布式唯一ID生成算法——snowflake的实现

开头先放一个snowflake的实现——仓库地址

分布式唯一Id是什么

分布式唯一Id其实是一个分布式系统里面的一个不可或缺的元素,他一般具有如下几个特性

  • 同一业务的全局唯一性(globally unique)
  • 包含时间信息(timestamp)
  • 递增有序性(incremented and ordered)

分布式唯一Id有什么用

这样一个分布式唯一Id,在一个分布式系统中的作用都有些什么呢。

举个例子,比如说业务量大了要做分库分表了,拿MyCat这个中间件举例,你对接了MyCat这个中间件后,你是接触不到MyCat后面被取余策略或其他策略分离的表的。MyCat呈现给你的仍然是一张表,但是却是分离的表的合并。 那这个时候你后面的数据库的主键要是还是和单机的策略一样,仍然是普通的auto_increment 1的话,你的分割后的每张表都会有重复的Id。
比如说有一组订单表order_1, order_2

使用CGlib实现动态代理模式

前言

关于代理模式和使用JDK dynamic proxy实现的动态代理模式,已经在使用JDK dynamic proxy实现动态代理模式写过了,也说了Spring5之前使用的代理就是JDK默认的动态代理。然后我自己最近也在写一个框架——Agito。在自己实现AOP特性的时候,感觉使用JDK自带的动态代理并不容易实现我的需求,所以在技术选型的时候,我选择了CGlib这个字节码增强利器来实现动态代理。

使用JDK dynamic proxy实现动态代理模式

代理模式

代理模式理解起来很简单,比如说我有一个接口叫做Hello

public interface Hello {
void say();
}

他的实现类是HelloImpl

public class HelloImpl implements Hello {
@Override
public void say() {
System.out.println("hello world");
}
}

但是我又想在say()调用前做些什么,这里其实很关键,因为你找到了一个切点,这就是AOP——面向方面编程的特征,这个待会再说。想加新的功能,但是我们都学过开闭原则,所以我们打算再创建一个代理类来实现这一功能(组合)

public class HelloProxy implements Hello {
private Hello hello;

public HelloProxy() {
hello = new HelloImpl();
}

@Override
public void say() {
System.out.println("start");
hello.say();
System.out.println("end");
}
}

然后运行试下

public static void main(String[] args) {
Hello hello = new HelloProxy();
hello.say();
}

结果就是

start
hello world
end

这样看着既简单,又实现了需要的功能,似乎已经满足我们的需求了。这种方式叫做静态代理。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×