简明 VIM 练级攻略
https://www.cnblogs.com/chengjiawei/p/9339951.html
获取Spring上下文(ApplicationContext)的三种方法
https://blog.csdn.net/fubo1990/article/details/79648766
十二种获取Spring的上下文环境ApplicationContext的方法
https://my.oschina.net/u/2391658/blog/729414
字段必填项校验
有时候需要 动态的,有条件的 去校验参数
比如预约发邮件,有需求修改一个邮件,
在邮件还没有发出去,可以修改,校验邮件内容的有效性,
如果邮件已经发出去了,则不能修改了.
这里就需要先判断下邮件是否发出去了.
这时就可以使用org.springframework.validation.SmartValidator.
SmartValidator
https://www.liangzl.com/get-article-detail-28869.html
java8中map的用法
在Java 8中stream().map(),您可以将对象转换为其他对象。查看以下示例:
https://www.cnblogs.com/sbj-dawn/archive/2018/05/23/9075765.html
List collect1 = num.stream().map(n -> n * 2).collect(Collectors.toList());
List collect = alpha.stream().map(String::toUpperCase).collect(Collectors.toList());
String failMessage = StreamUtil.streamOf(bindingResult.getFieldErrors()).map(FieldError::getDefaultMessage).collect(Collectors.joining(","));
反序列化时将null值转换为空的字符串
JSONObject.toJSONString(reverseVO, SerializerFeature.WriteNullStringAsEmpty)
bean通过注解实现字段校验
https://blog.csdn.net/xuanwugang/article/details/81106747
@Valid注解的使用—SpringMvc中的校验框架@valid和@validation的概念及相关使用
https://blog.csdn.net/u012240455/article/details/81841882
使用AOP对Spring @Valid的校验结果做统一处理
Java中的关键字 transient
https://www.cnblogs.com/chenpi/p/6185773.html
json转化的时候如何忽略某些属性字段值
https://www.cnblogs.com/ya-qiang/p/9364435.html
分布式锁的实现方式及原理
http://ifeve.com/浅谈autocloseable接口/
https://www.cnblogs.com/SophieLSR/p/9001789.html
mybatis关联查询
redis分布式锁-SETNX实现
https://www.cnblogs.com/SimplifyIT/p/6691584.html
ETCD相关介绍–整体概念及原理方面
ETCD 简介 + 使用
https://blog.csdn.net/bbwangj/article/details/82584988
Hystrix原理与实战
https://blog.csdn.net/loushuiyifan/article/details/82702522
Java遍历Map对象的四种方式
https://www.cnblogs.com/fqfanqi/p/6187085.html
Spring Boot (十九):使用 Spring Boot Actuator 监控应用
http://www.ityouknow.com/springboot/2018/02/06/spring-boot-actuator.html
VisualVM使用方法
https://blog.csdn.net/lijie1010/article/details/78805837
2.1启动visualvm 命令行运行jvisualvm
springcloud学习 纯洁的微笑
http://www.ityouknow.com/spring-cloud.html
jvm系列(五):tomcat性能调优和性能监控(visualvm)
https://www.cnblogs.com/ityouknow/p/5378874.html
使用SecureRandom类替代Random类
raise用于函数中打印输出,类似于oracle的dbms_output.putline(); raise的语法为:raise notice ‘this is raise test %’,param;
postgreSQL学习记录之raise用法
https://blog.csdn.net/publishwy/article/details/9241387
存储过程:
https://www.cnblogs.com/stephen-liu74/archive/2012/06/06/2312759.html
stream的groupingBy函数
listMap = StreamUtil.streamOf(list).collect(Collectors.groupingBy(DirSegmentRuleInfoVO::getCheckDlCode));
filter函数
DirMainCaseInfoVO creditVO = dirMainCaseList.stream().filter(d -> LoadTypeEnum.CREDIT.getKey().equals(d.getLoadFlag())).findFirst().orElse(new DirMainCaseInfoVO());
map reduce函数
BigDecimal freeAmount = value.stream().map(DivDetailVO::getFreeAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
Redis分布式锁的实现原理看这篇就够了~
https://blog.csdn.net/gupao123456/article/details/84327254
https://blog.csdn.net/gupao123456/article/details/84327254
单个Redis实例下的锁正确使用姿势
https://blog.csdn.net/She_lock/article/details/88894096
Java面试----2018最全Redis面试题整理
https://blog.csdn.net/wchengsheng/article/details/79925654
Redisson分布式锁
https://www.cnblogs.com/ASPNET2008/p/6385249.html
利用Redisson实现分布式锁及其底层原理解析(感觉还可以)
https://blog.csdn.net/turbo_zone/article/details/83422215
通过使用 Redis 集群命令行工具 redis-trib , 编写节点配置文件的工作可以非常容易地完成: redis-trib 位于 Redis 源码的 src 文件夹中, 它是一个 Ruby 程序, 这个程序通过向实例发送特殊命令来完成创建新集群, 检查集群, 或者对集群进行重新分片(reshared)等工作。
锁的原理
在Redisson中,使用key来作为是否上锁的标志,当通过getLock(String key)方法获得相应的锁之后,这个key即作为一个锁存储到Redis集群中,在接下来如果有其他的线程尝试获取名为key的锁时,便会向集群中进行查询,如果能够查到这个锁并发现相应的value的值不为0,则表示已经有其他线程申请了这个锁同时还没有释放,则当前线程进入阻塞,否则由当前线程获取这个锁并将value值加一,如果是可重入锁的话,则当前线程每获得一个自身线程的锁,就将value的值加一,而每释放一个锁则将value值减一,直到减至0,完全释放这个锁。因为底层是基于分布式的Redis集群,所以Redisson实现了分布式的锁机制。
加锁
在Redisson中,加锁需要以下三个参数:
KEYS[1] :需要加锁的key,这里需要是字符串类型。
ARGV[1] :锁的超时时间,防止死锁
ARGV[2] :锁的唯一标识,id(UUID.randomUUID()) + “:” + threadId
Future tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LONG,
// 检查是否key已经被占用,如果没有则设置超时时间和唯一标识,初始化value=1
"if (redis.call(‘exists’, KEYS[1]) == 0) then " +
"redis.call(‘hset’, KEYS[1], ARGV[2], 1); " +
"redis.call(‘pexpire’, KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
// 如果锁重入,需要判断锁的key field 都一直情况下 value 加一
"if (redis.call(‘hexists’, KEYS[1], ARGV[2]) == 1) then " +
"redis.call(‘hincrby’, KEYS[1], ARGV[2], 1); " +
//锁重入重新设置超时时间
"redis.call(‘pexpire’, KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
// 返回剩余的过期时间
“return redis.call(‘pttl’, KEYS[1]);”,
Collections.singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
解锁
在Redisson中解锁需要以下五个参数:
KEYS[1] :需要加锁的key,这里需要是字符串类型。
KEYS[2] :redis消息的ChannelName,一个分布式锁对应唯一的一个channelName:“redisson_lock__channel__{” + getName() + “}”
ARGV[1] :reids消息体,这里只需要一个字节的标记就可以,主要标记redis的key已经解锁,再结合redis的Subscribe,能唤醒其他订阅解锁消息的客户端线程申请锁。
ARGV[2] :锁的超时时间,防止死锁
ARGV[3] :锁的唯一标识,也就是刚才介绍的 id(UUID.randomUUID()) + “:” + threadId
public void unlock() {
Boolean opStatus = commandExecutor.evalWrite(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
// 如果key已经不存在,说明已经被解锁,直接发布(publihs)redis消息
"if (redis.call(‘exists’, KEYS[1]) == 0) then " +
"redis.call(‘publish’, KEYS[2], ARGV[1]); " +
"return 1; " +
“end;” +
// key和field不匹配,说明当前客户端线程没有持有锁,不能主动解锁。
"if (redis.call(‘hexists’, KEYS[1], ARGV[3]) == 0) then " +
“return nil;” +
"end; " +
"local counter = redis.call(‘hincrby’, KEYS[1], ARGV[3], -1); " +
// 如果counter>0说明锁在重入,不能删除key
"if (counter > 0) then " +
"redis.call(‘pexpire’, KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
// 删除key并且publish 解锁消息
"redis.call(‘del’, KEYS[1]); " +
"redis.call(‘publish’, KEYS[2], ARGV[1]); " +
"return 1; "+
"end; " +
“return nil;”,
Arrays.asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(Thread.currentThread().getId()));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
// 解锁成功之后取消更新锁expire的时间任务
if (opStatus) {
cancelExpirationRenewal();
}
}
注意点
Redisson 默认的 CommandExecutor 实现是通过 eval 命令来执行 Lua 脚本,所以要求 Redis 的版本必须为 2.6 或以上,否则可能要自己来实现
Redis分布式锁的正确实现方式
https://www.cnblogs.com/linjiqin/p/8003838.html
https://www.cnblogs.com/nfcm/p/7550772.html
https://www.cnblogs.com/hyq0002013/p/5545825.html
Class-Path: /proxy_test/src/main/java
https://blog.csdn.net/fengfengchen95/article/details/79915346
Springloaded使用方法
https://blog.csdn.net/tang86100/article/details/78772079
java -javaagent:D:\proxy_test\target\classes\out\artifacts\hello\hello.jar=hello
Manifest-Version: 1.0
Can-Redefine-Classes: true
Main-Class: agent.pre_MyProgram
Premain-Class: agent.pre_MyProgram
https://www.cnblogs.com/showxiaxian/p/4826568.html
IntelliJ IDEA打jar时,MANIFEST.MF内容出错
https://www.cnblogs.com/aspirant/p/8796974.html