Java 9 出来了很久,买的书《Java 9 Revealed - For Earyly Adoption and Migration》,说怎么迁移到 Java 9,可是突然间 Java 9 就无法通过正常渠道从 Oracle 官网下载了,这书还让不让人看。当然要看,因为尽管 Java 10 出来了,但实际的变化全压在 Java 9 这个版本上的,就当是通过 Java 10 来学习 Java 9 吧。
本文随便说说 Java 8 之后的版本变迁,不涉及 Java 9 或是 Java 10 的具体新特性,并不能回答标题中的问题。作为一个不甘落后的 IT 从业人员,总是希望能紧跟技术(某一狭小特定领域的技术)的步伐。譬如说当从 Java 1.4 升级到 Java 1.5 之后,对范型也是跃跃欲试,无奈当时公司追求的是稳定压倒一切,不在服务器上升级 JDK,所以只能创造条件也要上。于是弄了个 Retrotranslator让你用JDK1.5的特性写出的代码能在JVM1.4中运行 来适配。
后来的公司,也就是现在更为激进一些,来了 JDK 6,跟; JDK 7,跟; JDK 8, 继续跟; JDK 9 发布后,不跟了。不是不想跟,而是 Java 9 实在是变化有点大,模块化带来的不仅仅语言方面的改变,而是影响到如何组织,发布应用,这也就是为什么 jigsaw 雪藏多年的缘故。其实也可以对模块化不欲理会,但是单纯的把 Java 8 换成 Java 9 造成原来的项目不能正常构建的概率也比以往要高。
Java 8 是 2014 年 3 月发布,四后半后的 Java 9 在 2017 年 9 月发布,然而 2018 年 3 月 Java 10 就出来了。谁说 Oracle 在收购 Java 后就对它不作为了呢?Oracle 在 Java 9 之后开始了 6 个月的发布周期(见 Oracle Java SE Support Roadmap),这让人如何受得了,Oracle 自己也是。更何况我们都没来得急品尝 Java 9 的滋味,Oracle 自己就把 Java 9 的生命周期给结束了,进到 Java 9 的下载而面 Java SE 9 Downloads, 自动会导向到 Java SE 10 的下载页面,想要下载 Java SE 9 的话,只能到历史存档中去找 Java SE 9 Archive Downloads。 Read More
SQL Server 自 2008 版起引入了uniqueidentifier字段,它存储的是一个 UUID, 或者叫 GUID,内部存储为 16 个字节。SQL Server 可用两个函数来生成uniqueidentifier, 分别是NEWID()和NEWSEQUENTIALID(), 后者只能用作字段的默认值。Java 也有一个 UUID 工具类java.uti.UUID,UUID.randomUUID().toString()生成一个随机的 UUID 字符串,在java.util.UUID也是用两个long字段表示内部状态。
SQL Server 的uniqueidentifier类型字段表明了内部如何存储,在我们操作它时,它的外在表现形式都是一个固定格式 `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` 的字符串,不区分大小写的。
本文所使用的 SQL Server 是 2017 版,通过 Docker 来启动的docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=yourStrong(!)Password' -p 1433:1433 -d microsoft/mssql-server-linux:2017-latest
然后我们创建一个带有uniqueidentifier类型字段的表 Read More
以实际 Java 项目中的单元测试 Mock 框架基本是 Mockito 2 了,因为它有一个十分流畅的 API。Mockito 2也为 JUnit 5 配上了 MockitoExtension, 所以 JUnit 5 下使用 Mockito 2 的关节也打通了。但在我们享受 Mockito 2 便利的同时,与 JMockit 相比局限性就很明显,因为 Mockito 2 是通过创建匿名子类来进行 Mock 的,所以任何子类对父类无法突破的方面它都存在。譬如,final 类, final 方法, 私有方法, 静态方法, 构造函数都是无法通过子类型进行重写的。所以除非特别需要,在 Mockito 2 无法胜任时都求助于 JMockit,JMockit 借助于 javaagent 取得了 JVM 的高控制权才得已为所欲为。
当 Mockito 来到了 2.1.0 版本,它也觉得不能对以上所有的限制置若罔闻, 首先带给我们的突破是它也可以 Mock final 类和 final 方法,虽然仍处于孵化器中,但毕竟是应用在单元测试中,能用就很不错了,只要以后不被拿走就行。这是官方对它的介绍 Mock the unmockable: opt-in mocking of final classes/methods
下面我亲自操作一遍,并给出更全方位的测试样例 Read More
JUnit 5 刚出来那时,也就是第一个版本 5.0.0 时,还不能很好的支持 Mockito 的测试,因为 Mockito 没能跟得那么紧密。那时候 JUnit 5 只能试验性的提供了一个极不正式的 com.example.mockito.MockitoExtension, 看那包名就知道不是来真的,所以决定再等。JUnit 5 不再原生支持 JUnit 4 的 Rule,一切都将是 Extension,那也是要求 Mockito 能够与之俱进。现在等来了,JUnit 5 进化到了 5.2.0, Mockito 也早已有了一个单独的模块mockito-junit-jupiter来迎接它。
在 Mockito 2.1.0 的 What's new in Mockito 2 中记述了 JUnit 5 为 Mockito 2 开发了一个 MockitoExtension。追溯到 Mockito 2 的 Release Notes, 我们发现 Mockito 2 官方最早引入 MockitoExtension 的版本是 2.16.3(2018-03023)。我对 Mockito 对 JUnit 5 支持的最新更新是从这个 Pull Request MockitoExtension for JUnit5 得知的。
一句话讲就是现在的 Mockito 2 有原生态的 MockitoExtension 来支援 JUnit 5, 可以非常放心可靠的让 JUnit 5 和 Mockito 2 一起稳定工作。因此前面那个包名带example字样的 MockitoExtension 链接也就无效了。 Read More刚开始阅读 《Akka IN ACTION》这本书,刚开始是对
Revolution这个词翻译成中文是革命感到诧异,因为革命通俗来讲就是杀人的意思。至于Revolution英文解释不深究了,只是感叹何以颠覆性的变化就一定要杀人吗?也由此引出了编程中经常面对的
Concurrent(名词为:Concurrency) 和Parallel(名词为:Parallelism) 这两个词,基本上是认为它们是同一个意思。其实不然,下面慢慢道来。如果从英文字典对它们的解释也没有多大区别,差不多都是说同是发生,但字面上
Parallel多了一个平行的意思。所以在中文上,在计算机领域我们约定的翻译是- Concurrent(Concurrency) -- 并发
- Parallel(Parallelism) -- 并行
比如在多线程环境中它们的区别具体体现在:
并发:多个任务在同一个 CPU 核上按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。针对 CPU 内核来说,任务仍然是按细粒度的串行执行。也难怪在 Java 5 中新加的并发 API 的包名是
java.uti.concurrent。 Read More
初识 Mockito 这个测试框架后,我们要使用 Mock 的属性创建一个被测试类实例时,大概会下面这么纯手工来打造。
假定类
UserService有一个属性UserDao userDao, 需要构造UserService实例时 Mock 内部状态UserDao userDao = Mockito.mock(UserDao.class);
UserService testMe = new UserService(userDao);如此,userDao 的行为就可以自由模拟了,这种纯手工方式都不需要给测试类添加
@RunWith(MockitoJunitRuner.class)
//或
MockitoAnnotations.initMocks(this);因为上面两句是给 Mockito 的注解使用的。
如果所有的 Mock 对象全部通过手工来创建,那就不容易体现出 Mockito 的优越性出来。因此对于被测试对象的创建,Mock 属性的注入应该让
@Mock和@InjectMocks这两个注解大显身手了。标注在实例变量上的
@Mock相当于是Mockito.mock(Class)创建了一个 Mock 对象,而@InjectMock标的实例会寻找到相应 Mock 属性想法构造出被测试类的实例。看下面的例子: Read More- 标准 SQL 都提供了下面这种方式一条 INSERT INTO 语句插入多条记录
VALUES 之后用括号列出每一条记录。但是在 Java 中想把上面的语句转换成 PreparedStatement 来插入多条记录时就有些问题。要么写成INSERT INTO Customers(Id, Name, Age) VALUES (1, 'Name1', 21.5), (2, 'Name2', 32.3)
INSERT INTO Customers(Id, Name, Age) VALUES(?, ?, ?), (?, ?, ?), (?, ?, ?) ....
我们不知道 VALUES 后应该列多少个问号,而且 JDBC 对参数的个数是有限制的,最多 2000 个参数。如果根据字段个数来算一次添加多少条记录,那么这条 SQL 语句也是动态的,不能很好的作为 PreparedStatement 进行预编译。以一个表三个字段为例,2000 个参数下一次性最多能插入记录数 666 条,也可能由于输入是 666 条记录的任意数量,所以生成的语句非静态的。
这种方式与每次手动拼凑一个完全静态的 INSERT INTO 语句应该不会有太多的差别。
如果只是写成INSERT INTO Customers(Id, Name, Age) VALUES(?, ?, ?)
然后试图进行下面的操作 Read More
前脚研究完 Mockito 中被 Mocked 的对象属性及方法的默认值, 虽然目今更多的是拥抱着 Mockito, 但总有时对 JMockit 也会挤眉弄眼,谁叫 JMockit 无所不能呢!被 Mockito 的 Mock 对象方法的默认返回值洗脑之后,进而觉察出 JMockit 应该有同样的实现方式。
经过类似的测试,这里不详细列出测试过程,只是在基于前篇的测试中加入 JMockit 的依赖,最新版是 1.36。测试类 MyClassTest 中使用1@Mocked 2private MyClass myClass;
来构造 MyClass 的 mock 对象 myClass, 其余代码是一样的。相关代码请前往上篇 Mockito 中被 Mocked 的对象属性及方法的默认值 中找。 使用 JMockit 后跑出来的效果如下: Read More
在 Java 测试中使用 Mockito 有段时日了,以前只是想当然的认为 Mock 的对象属性值和方法返回值都是依据同样的规则。基本类型是 0, 0.0, 或 false, 对象类型都是 null, Mock 对象的默认返回值也应该是一样的。直到最近有一天,有一个返回
Optional<String>类型的方法,由于忘记对该方法打桩,意外的发现它返回的不是 null, 而Optional.empty(), 因此才意识到此处定有蹊跷。着实有必要用代码验证一下 Mockito 是怎么决定属性及方法的各种返回类型的默认值的。此次测试所用的 Mockito 版本是 mockito-core-2.12.0.
于是创建了下面一个类 MyClass 用于生成 Mock 对象,选取了一些典型的数据类型, 包括 int, Double, String, long[], Optional<String>, Collection<String>, Map<String, String>, 同时测试 Mock 对象默认的属性值与方法默认返回值。 Read More
- 昨天刚刚侍弄完 Spring 下基于自定义注解拦截方法调用, 现在试下纯 AspectJ 的方式来打造,因为不是每一个项目都是 Spring。这次要推到 5 年前试验过用 javac 命令行编译的方式织入方面, 见 AspectJ 基于自定义的方法注解来拦截方法, 这次着重在用 aspectj-maven-plugin 插件的方法来织入 AspectJ 方面。
基本上代码还是昨天的,需求还是一样的:
被 @LogStartTime 注解的方法在进入该方法时记录当前时间在 ThreadLocal 中,并能根据 @LogStartTime 的属性值决定处理逻辑
因为 Java5+ 之后 AspectJ 可以写成 Java 类加注解的方式,*.aj 文件一般都没太大必要了,所以可以和 Spring AOP 共用一个 @Aspect 注解的方面代码MethodStartAspect。
我们将采用编译器织入,因此项目依赖只需要一个org.aspectj:aspectjrt:1.8.0, 它也不会引入别的组件。同样我们从 Main 方法和测试用例两方面来验证实现的效果,下面是整个测试项目的布局,以及依赖,除掉单元测试的其时就只需要一个 jar 包。 Read More