ClassNotFound 和 NoClassDefFoundError 的区别

在 Java 的开发中,这两个可能是让人比较头痛的异常了,因为出现这个异常,又得一大堆 jar 包冲突需要解决。

ClassNotFound

按照 oracle 官方的描述:Class ClassNotFoundException

Thrown when an application tries to load in a class through its string name using:
The forName method in class Class.
The findSystemClass method in class ClassLoader .
The loadClass method in class ClassLoader.

也就是当 JVM 尝试着去加载某个类的时候,会发现 classPath 下面却没有这个类,那么就会直接报错,在日常开发中出现的常见的常见原因是,两处引用了不同版本的第三方包(maven)。

阅读更多

RestTemplate 处理转义的相关细节

在业务开发中,常见的 Http 请求开源框架有如下几个:

  1. JDK 自带的 Http 请求库
  2. Apache 提供的 HttpCLient
  3. OkHttp
  4. 由 JDK 封装而来的 RestTempalte

其中因为我们是用的 Spring 框架,所以自然而言的优先选择 RestTemlate,优点非常的多,很多配置都可以做到低耦合,并且可以将请求和相应做单独的处理。

但是在使用的过程中,遇到了转义的坑了,在此记录下

场景复现

阅读更多

优雅的dubbo服务端校验

在业务的开发过程中,肯定会有一些数据字段的校验,例如手机号格式,用户名格式等等。

如果这个放到每一个具体的接口去判断的话,首先是和业务代码耦合,每一个接口的实现方都需要在代码中判断一系列的校验,而且后续如果需求产生变更,那么每一个在业务中进行判断的方法都需要改变,非常的耗时且不优雅

解决方案

目前无论是 spring全家桶 还是 dubbo,通用的做法就是通过 Hibernate Validator 来进行入参的校验,如果是配合 spring 使用的话,那么可以直接引入如下的 pom 文件:

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
阅读更多

算法系列「回溯」-排列、切割、子集

回溯定义

按照维基百科上给到的定义:回溯是一种最优选择法,如果发现某一些选择不符合目标,那么就会进行退回操作

在了解回溯算法之前,首先就不得不提到一个概念「递归」,递归 和 回溯 在基本的逻辑上其实是差不多的,只不过回溯都含有撤销操作,而递归则是一条路走到底,两者都属于暴力搜索法。

最经典的题目就属于「八皇后」

递归

阅读更多

使用lambda来优化责任链模式

责任链模式是设计模式的一种,可以为调用的对象进行一个链式处理,这种模式在 Java 的一些第三方库中经常见到。

而在业务开发中,这种需求也是很常见的,如果用好这个设计模式,对于代码的扩展性和可维护性都是非常有帮助的,例如常见的下单流程,就可以用责任链模式处理。

而在第三方库中,像 tomcat 的过滤器就是使用责任链模式进行处理

Tomcat 中的使用

在 tomcat 中,过滤器的实现就完全是责任链模式的使用了

阅读更多

CyclicBarrier详解

在上一篇的文章中有提到过 CountDownLatch ,其实 CyclicBarrier 也有异曲同工之妙,不过 CyclicBarrier 是等到所有的线程都到达一个点以后,然后再一起执行

有点像小时候一起去春游,必须等到所有的同学都到了学校,才能一起去坐车,不然就会一直等待。

构造函数

CyclicBarrier 的构造函数有两个,分别如下:

1
2
3
public CyclicBarrier(int parties) {
this(parties, null);
}
阅读更多

CountDownLatch详解

CountDownLatch

CountDownLatch 只有一个构造函数:CountDownLatch(int count)

其中 count 表示该信号量的数量,其中具体的实现类是 Sync,而 Sycn 又是继承自 AQS,实现了几个 AQS 的方法

在生产环境中可以用于分治思想,讲一些复杂的处理分成一些子任务,等所有处理任务处理完毕以后,主线程才会执行

还可以用于一些任务的流程检查,例如只有所有的检查都完毕以后,主线程才可以获取数据然后执行

阅读更多

Java中多线程使用经验

在子线程中获取父线程的ThreadLocal

如果想子线程想使用父线程的 ThreadLocal,那么父线程中的 inheritableThreadLocals 有值,这样子线程中的 init 方法就会自动的将父线程的 inheritableThreadLocals 设置为 ThreadLocal

但是因为子线程是在 init 方法中进行赋值的,所以如果子线程是由线程池创建的,那么该方法就又可能会失效,当线程池刚初始化完毕的时候,此时线程池中的还没有线程,当调用 execute 方法,此时就会 new 一个线程,那么这时候子线程是可以读取到父线程中 inheritableThreadLocals 的值

但是线程池中的线程是可以被复用的,所以后续如果线程不再创建的时候,那么子线程便不能再次获取父线程中的 inheritableThreadLocals,也就无法再将 ThreadLocal 进行父子线程的传递

如何感知到子线程的异常

阅读更多

慢查询排查以及优化

排查方式

SHOW PROCESSLIST

SHOW PROCESSLIST 只能查看到当前用户正在运行的线程,如果你是ROOT用户,那么是可以看到所有用户正在运行的线程
如果想看到其他用户的线程,则必须为此用户赋予 PROCESS 权限。

危害:

  1. 造成机器的 CPU 以及 IO 过高,影响到数据库实例。
  2. 阻塞 DDL 查询语句,会造成其他正常业务出现耗时过高。
  3. 会导致 mysql 出现 MDL 锁,影响到该机器上正常 SQL 的执行。
阅读更多

Java中的SPI机制以及应用场景

SPI 全称是 Service Provider Interface,是 JDK1.5 新增的一个功能,允许不同的服务提供者去实现某个规定的接口,而且将具体的实现完全提供给使用方,允许使用方按需加载服务提供方的一些功能。

前言

提到 SPI,就不得不提下 API,以 dubbo 为例,服务提供方对外提供一系列 API,而使用方是不用关心服务提供方是如何实现具体的业务逻辑,只需要通过 RPC 调用远程服务即可。

API

这样的好处就是 client 端不用关心服务端的具体逻辑,方便服务的水平扩展以及解耦。

阅读更多