自定义类加载器动态加载 JDBC 驱动

我们可以用自定义的 URLClassLoader 从外部动态加载类,并使用它。但数据库驱动的管理类 DriverManager 却不比较苛刻,不承认非当前应用系统加载器加载的驱动类。见 DriverManager 的 JavaDoc 

When the method getConnection is called, the DriverManager will attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application

对于有有应用自定义类加载器加载数据库驱动类的需求时,就要对原 Driver 简单包装一下。继续往后会说介绍为什么要这么做。

说明一下,DriverManager 能够根据 JDBC 连接字符串匹配到驱动类,所以一般来说都不需要显式调用 DriverManager.registerDriver() 方法。

先看 DriverManager 在应用外部驱动类时会出现什么情况 阅读全文 >>

函数定义 Kotlin V.S. Scala

关注 Kotlin 已有段时日了,真是因为 Google 把它扶正而跑来跟风。因为进行想在 Java 与 Scala 间找一个折中的编程语言,也就是 Kotlin。这是一篇好几月前列的我 想像中理想编程语言的几个特征,琢磨来去当今也就 Kotlin 比较符合我的口味。很早就想买 《Kotlin IN ACTION》这本书,因那是 Kotlin 1.1 刚出,而出版的书只涵盖到了 Kotlin, 所以未出手。看看再有一本好的那样的书估计也不是一时半会儿,所以今天还是把那本书弄到手了,至于 Kotlin 1.1 后的特性自个去补充。

尽管书中未提及 Kotlin 语言的设计灵感来自于何种语言,  但我的直觉就是与 Scala 太多相似之处,但没有 Scala 简单,并揉合一些 Swift 的特性,因此我在阅读 《Kotlin IN ACTION》时更多的会和 Scala 相比较。

第一个主题是关于 Kotlin 函数的定义与约定。Kotlin 的基本定义格式与 Scala 是类似的

//Kotlin
fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

注:Kotlin 也像 Scala 一样,if 不再是一个控制语句,而是一个表达式,所以它是有返回值的。与  Java 有不同的是,Kotlin 的赋值语句是没有返回值的,不能用作 val b = (a = 3), 而 Scala 的赋值语句总是返回 Unit 阅读全文 >>

Spring 定时任务(Schedule) 和线程

Spring 定时任务实例

Spring 中使用定时任务很简单,只需要  @EnableScheudling 注解启用即可,并不要求是一个 Spring Mvc 的项目。对于一个 Spring Boot 项目,使用定时任务的简单方式如下:

pom.xml 中

Application.java 阅读全文 >>

使用 avro-tools, jq 查看 Apache Avro 序列化文件

Apache Avro 是类似于 Google protobuf 那样的数据交换协议,但 Avro 可以用 JSON 格式来定义 Schema, 所以相比而言更容易上手。它也是 Hadoop, Kafka 所采用的交换格式。对于生成的 avro 序列化文件如果要编写代码来解读其中内容的话就太过于麻烦,Apache 给了我们一个便捷的工具来处理 Avro Schema 和数据。

Java 版的 Avro Tools 可点击链接 avro-tools-1.8.2.jar 下载,当前版本 1.8.2(发布于 2017/05/20),执行命令是

java -jar avro-tools-1.8.2.jar ..............

如果是 Mac 平台,还可以通过

brew install avro-tools

来安装,执行命令就只是 avro-tools 了。

在本文中还会用到一个 JSON 格式化高亮显示的工具 jq, 在 Mac 下通过以下命令安装

brew install jq

avro-tools 和 jq 已准备就绪,接下来演示下如何使用它们。

avro-tools 能做什么

阅读全文 >>

Spring 项目中把属性或 SQL 语句写在 .xml 文件中

Spring 项目中把大量的 SQL 分散在 Java 代码中,无 Here Doc 的情况下用加号来连接写着实在是不爽,于是之前思考这个 Spring 项目中把 SQL 语句写在 .sql 文件中 --  把它们写在 *.sql 文件中,但是这个 *.sql 需要特定的格式来标识属性 Key

--!select.user
select id, firstname, lastname, address
--!update.user
update ........

而且还需要一个额外的类 SqlPropertySourceFactory 来解析上面的 *.sql 文件, 识别出 select.user 是 Key, 紧接着后面的块是相应的属性值,用注解引用它时还有点额外的 factory 属性来配置,如

@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)

所以一直在思考是否能够再简单些,是否能用一个自定义的注解,如

@SqlPropertySource("classpath:sql/queries.sql")

捉摸了很久,似乎有点难度,不过再不断发掘的过程中找到了这个类 org.springframework.core.io.support.PropertiesLoaderUtils, 有下面的代码片断 阅读全文 >>

JMockit 中捕获 mock 对象方法的调用参数

三个月前写过一篇 Mockito 中捕获 mock 对象方法的调用参数,一般项目中 Mockito 不决求助于 JMockit, 同样的在 JMockit 也需对捕获被 Mock 的方法调用参数。当我们用 new Expectations(){{}} 打桩并在后面断言了返回值,那就无需捕获参数来断言,匹配到了方法调用即证明传入的参数也是对的,如下面的代码所示

public class UserServiceTest {

    @Mocked
    private UserDao userDao;

    @Test
    public void couldCallUserDaoToAddUser() {
        new Expectations(){{
           userDao.findById(123);
           result = "Yanbin";
        }};

        UserService userService = new UserService(userDao);
        String user = userService.findBy(123);

        assertThat(user).isEqualTo("Yanbin");  //这里断言成功也就证明了 userDao.findById(123) 方法被调用,参数必须是 123
    }
}

但如果是未打桩的方法,或打桩是用的模糊参数(withInstanceOf(String.class)), 或是无返回值的方法就要事后对是否调用了某个方法以及传入什么参数的情况进行断言。 阅读全文 >>

使用 Awaitility 测试异步代码

对于同步方法的测试很简单,调用完后可立马检查执行状态; 而异步方法,由于我们无法确切的知道何时结束,因此以往的办法是用 Thread.sleep(500) 来预估一个执行时间。然后通常我们估计的要长于实际的时间,这就很浪费,况且偶然的超过预估的等待时间也并不意味着代码有问题。还有 sleep 方法还抛出一个检测异常 InterruptedException, 一般会要对 Thread.sleep(500) 作下简单包装。

于是今天要介绍的 Awaitility 就应运而生了,专门针对异步方法的测试。它的官方文档在 https://github.com/awaitility/awaitility/wiki/Usage。本文主要关注在 Java 8 环境下用 Lambda 的代码书写方式。Awaitlity 实际运行是以某种轮询的方式来检查是否达到某个运行状态,可设定最多,最少等待时间,或永久等待,或自定义轮询策略,之后就开始进行需要的断言,所以它可以尽可能的节省测试异步方法所需的时长。而不像 Thread.sleep(500) 一路等到黑,并且没有回头路。

通常我会在项目中给 JUnit 配上三个最佳伴侣,它们是(按 mvn dependency:tree 中的显示方式):

  1. org.awaitility:awaitility:2.0.0:test
  2. org.assertj:assertj-core: version: 3.8.0:test
  3. org.mockito:mockito-core:2.7.22:test

当然如果项目中没有异步调用自然是不需要 Awaitility, 在我的项目中是基本不可能的。以上三种都追求 DSL,以流畅的方式进行愉快的测试。

现在来尝试下 Awaitility 的几种基本的用法,先假定有下面的代码 UserService 阅读全文 >>

使用 Mockito 修改私有属性

修改私有属性来 Mock 可能不是一种很好的测试方式, 因为属性名是动态的,但有时不得已而为了,例如下面的代码:

public class UserService {
    private ExternalApi external = ExternalApi.default();
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User findUserById(int id) {
        return userDao.findById(external.convertId(id));
}

测试时欲隔离对 ExternalApi 的外部依赖, 当然可以把它也作为构造函数的一个参数,这样创建 UserService 实例时就可以 Mock external 属性。不过 external 经常是不变的,所以作为方法参数的必要性也不大。这就希望能在构造出 UserService 之后对 external 私有属性进行 Mock 处理。

在 Mockito 1.x 和 2.x 下要使用不同的方式,分别使用到 Whitebox 和 FieldSetter 类,它们都来自于  mockito.internal.util.reflection 包,可见 Mockito 打心底不推荐直接使用它们,但谁叫它们是 public 的呢。还有一种方式是使用 PowerMock + Mockito, 这是后话。 阅读全文 >>

使用 JMockit 来 mock 构造函数

Java 测试的 Mock 框架以前是用 JMockit, 最近用了一段时间的 Mockito, 除了它流畅的书写方式,经常这也 Mock 不了,那也 Mock 不了,需要迁就于测试来调整实现代码,使得实现极不优雅。比如 Mockito 在 私有方法,final 方法,静态方法,final 类,构造方法面前统统的缴械了。powermock 虽然可作 Mockito 的伴侣来突破 Mockito 本身的一些局限,但是我一用它来 Mock 一个构造方法就出错

Caused by: java.lang.ClassNotFoundException: org.mockito.exceptions.Reporter

原因是 Mockito 变化太快,powermock 跟不上它的步伐 -- https://github.com/powermock/powermock/issues/684,于是我只能止步。

不得已再祭出 JMockit 这号称(也确实是)一无所不能的大杀器,在此见识一下它怎么 Mock 构造函数的

本篇实例所使用的 JMockit 版本是 1.30, 当前最新版 1.31, 由于尚未被 Maven 中央仓库收录,所以暂用 1.30。在 pom.xml 中如下方式引入 阅读全文 >>

JdbcTemplate 易被 Java 8 Lambda 带入的坑

Spring 的 JdbcTemplate 为我们操作数据库提供非常大的便利,不需要显式的管理资源和处理异常。在我们进入到了 Java 8 后,JdbcTemplate 方法中的回调函数可以用 Lambda 表达式进行简化,而本文要说的正是这种 Lambda 简化容易给我们带来的一个 Bug, 这是我在一个实际项目中写的单元测试发现的。

下面就是我们的一个样板代码,在我们的 UserRespository 中有一个方法 findAll() 用于获得所有用户:

阅读全文 >>