聊一聊 SpringBoot 中的一些被忽视的注解

之前在老的项目中看到了一个比较有趣的现象

有一个需求是需要对返回的数据进行加解密的操作,部分老代码是直接硬编码在项目中,但是后来有人改了一版,称之为 1.0 版本

1.0 版本是通过切面配合注解进行处理,大致的处理流程是对返回的对象通过反射遍历字段,如果发现字段上有指定的注解,则进行加密操作,如果发现该字段是一个对象的话,则进行递归处理,直至结束

后来有一个需求是对返回的手机号、身份证信息只需要对中间的信息进行加密,两边不处理…其他的例如家庭地址、家庭成员全部加密为密文

拿到这个需求的时候,想改也挺简单,只需要增加一个新的注解,然后替换该切面扫描到的返回值进行替换注解就可以了

阅读更多

Redis实现的分布式锁是完美的吗?

单实例

setnxRedis 官方提供的一个分布式原子性锁,它的实现利用了 Redis 在执行命令的时候是一个原子性操作,所以可以实现同一时间只有任务才能获取到锁。

当在同一个 redis 实例中进行加锁的操作的时候,如果加锁成功则会返回1,如果加锁失败的话,则是直接返回 0

1
2
127.0.0.1:6379> setnx 'redislock' 1
(integer) 1

如果此时另一个任务想进行加锁的话,则会返回0

阅读更多

重温生产者和消费者模型

生产者和消费者模型,主要解决的是数据的同步问题,生产者将数据放置一个存储区域,然后消费者过来取数据。这种模式类似于一个中间件,可以使得生产者不需要关心消费者什么时候来拿数据,同时在这种模式下,还可以控制两边的处理速率,避免数据的丢失。

下面以 Java 为例,来写一个生产者和消费者模型。

当队列满了的时候,生产者自己进行阻塞。而当消费者发现队列为空,则将自己阻塞。

所以要实现这个生产者消费者模型,首先必须有以下条件:

  1. 生产者或者消费者必须支持可阻塞
  2. 在多线程的情况下,必须保证并发安全(即插入不能产生数据错误),取数据不可以重复取
阅读更多

快速写一个程序将JVM的堆或者栈打满

堆和栈

数据结构

首先「堆」或者「栈」在本质上其实是一个数据结构,简介如下:
「栈」既可以用链表来实现,又可以用数组来实现,用链表来实现的话,它是一个含有头指针和尾指针的一种数据结构,根据含有指针的不同,分为单链表和双向链表。
「堆」是一种类似于「完全二叉树」的数据结构

JVM中的堆和栈

在 JVM 中由于编译后的 class 文件都是一行行的指令,因此天然适合用「栈」这种数据结构,

阅读更多

Thread.sleep(0)-vs-Thread.yield()

简介

Thread.sleep(long)yield() 都表示的是让出当前线程的 CPU 时间片,两者在执行的时候,都不会去释放自己已经持有的锁。

多线程

在现代的处理器中,以 4核心CPU 为例,这表示在同一个时刻,只会有 4 个线程在并行执行,而在每一个核心内部,多个线程其实是顺序执行的,它们的执行顺序依赖于线程的调度算法。

线程调度算法

阅读更多

ThreadLocalMap 简单分析

ThreadLocal

在使用多线程的时候,如果需要保存一份线程自己私有的一部分变量,避免其他线程污染这个变量的话,一般都会自己手动 new 一个 ThreadLocal,如下代码:

1
2
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("test");

当需要在某一刻使用这个变量的时候,只需要手动调用下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
threadLocal.get();
```

## ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的一个静态内部类,每一个线程在创建的时候都会有这个 ThreadLocalMap 变量,它的作用就是存储每一个通过 `threadLocal.set()` 方法存入的值,本质上也是一个HashMap。

先看下它的一个内部类:
### Entry
不同于 WeakHashMap 是继承自 HashMap 的Entry,ThreadLocalMap 的Entry 则是自己的一个内部类。
```java
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
阅读更多

mysql中count(*)和count(1)的区别

在进行旧的项目 review 的时候,我发现绝大多数的统计SQL都是基于 count(1) 来进行的,只有一少部分是基于 count(*),那么这两种写法到底有什么区别。

mysql中,常用的存储引擎有myisaminnodb,但是由于myisam只支持表级别锁,而且还不支持事物,所以在mysql的5.5版本之后就将默认的存储引擎调整为innodb

 
以下实验基于 Mysql8.0.1 来进行
 

首先这里准备了一个表.

阅读更多

Springboot自定义@EnableXX注解

在SpringBoot中,经常可以看到许多以 @Enable 开头的注解,例如:@EnableAutoConfiguration@EnableAsync……,那么我们是否可以自己定义一个注解呢?

其实自定义注解最终都是利用到了 ImportBeanDefinitionRegistrar 这个类,通过手动的方式,将一个类注册成为 Bean,然后在进行一系列的操作,下面就来看下 ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar

这个类的代码如下:

可以看到这个类的结构很简单,就是一个方法,那么下面来看下这两个参数是什么意思。

阅读更多

Springboot的maven间接依赖

在项目中经常使用 maven 来管理项目,但是有时候对于 maven 的细节还是了解的不是很清楚,因此今天复习下。

maven项目

首先开始建立一个最简单的 maven 项目,其配置如下图:

可以看到最上面一行是 xml 的文件描述符,然后再是 project,在这里引入 xsd 文件。

XSD(XML Schemas Definition)XML Schema,描述了 xml 文档的结构,用于判断其是否符合 xml 的格式要求

阅读更多

阿里云SDK使用代理的一个坑

由于项目中需要使用阿里云的短信平台,所以直接引用了最新的SDK,版本号为 4.5.1。但是由于机器在内网环境,如果需要访问外部网络的话,需要代理机器。于是去看下 阿里的SDK 官方文档,如何支持代理访问,于是找到以下内容:

坑就坑在这个文档里面的设置方法,设置了并没有什么用。于是自己研究了下这种设置为什么不生效。

System.setProperty

这个命令和在启动参数中加 -DXXX=XXX 是一样的效果,例如:

阅读更多