欢迎光临!请记住我的域名:http://wish123.cnblogs.com
代码改变世界

java技术选型

2018-05-19 18:00  wish123  阅读(5449)  评论(0编辑  收藏  举报

综述

  • JDK版本:JDK8/JDK7 + OracleJDK/OpenJDK
  • Java开发框架:Spring Boot/Spring + Hibernate/MyBatis
  • 前后端分离:单页应用/模板引擎
  • 前后端接口文档自动生成:Swagger
  • 业务端逻辑校验框架:Functional Validator/Fluent Validator/Hibernate Validator
  • CT框架:Rundeck
  • UT框架:TestNG/JUnit
  • 历史操作记录方案:Canal/AOP/硬编码

 

1. JDK版本

1.1 Why JDK8?

  • 开发效率的提升:用更少的代码完成更多的工作(Lambda代替匿名内部类、易于并行)
  • 可以使用函数式思维编程(高阶函数解放思想、消除副作用、简洁、各语言发展的趋势)
  • 未来趋势:一些开源项目及框架开始基于java8开发
  • JVM新特性:元空间代替永久代(避免JDK以及前期版本中常见的永久内存错误OOM:PermGen)

1.1.1 JDK8与JDK7代码对比

JDK7
JDK8

for (int i = 0; i < arr.length; i++) {

if (arr[i] % 2 != 0) {

arr[i]++;

}

System.out.println(arr[i]);

}

Stream.of(arr)

.map(x →(x % 2 == 0 ? x : x + 1))

.forEach(System.out::println);

Optional:优雅的处理null

JDK7
JDK8

public User getUser() {

return user;

}

public List<Order> getOrders() {

User user = getUser();

if (user != null) {

return user.getOrders();

} else {

return Collections.emptyList();

}

}

public Optional<User> getUser() {

return Optional.ofNullable(user);

}

public List<Order> getOrders() {

return getUser().map(u → u.getOrdes())

.orElse(Collections.emptyList());

}

建议:如果接口的返回值有可能是null,请用Optional封装

  • 优雅,下游不用写恶心的if-else判断
  • 安全:告知接口的使用方返回值可能为null,需要处理,以避免代码缺陷
  • 文档化:接口中可能为空的值文档化

1.1.2 易于并行

统计1-1000000内所有质数的数量

串行
并行

IntStream.range(1, 1000000)

.filter(PrimeUtil::isPrime)

.count();

IntStream.range(1, 1000000)

.parallel()

.filter(PrimeUtil::isPrime)

.count();

增强的Future:CompletableFuture

读写锁的改进:StampedLock(乐观的读策略增加系统的并行度)

原子类的增强:LongAdder(更快的原子类)、LongAccumulator

1.1.3 JVM新特性:元空间代替永久代

参考:

http://www.infoq.com/cn/articles/Java-PERMGEN-Removed?from=groupmessage&isappinstalled=0

http://www.6gdown.com/softedupage/59348.html

  • JDK7:“永久的”数据存放在一个叫做永久代的区域。永久代一段连续的内存空间,我们在JVM启动之前可以通过设置-XX:MaxPermSize的值来控制永久代的大小,32位机器默认的永久代的大小为64M,64位的机器则为85M。永久代的垃圾回收和老年代的垃圾回收是绑定的,一旦其中一个区域被占满,这两个区都要进行垃圾回收。但是有一个明显的问题,由于我们可以通过‑XX:MaxPermSize 设置永久代的大小,一旦类的元数据超过了设定的大小,程序就会耗尽内存,并出现内存溢出错误(OOM)。
  • JDK8:“永久的”数据被移到了一个与堆不相连的本地内存区域(元空间),这项改动是很有必要的,因为对永久代进行调优是很困难的。永久代中的元数据可能会随着每一次Full GC发生而进行移动。并且为永久代设置空间大小也是很难确定的,因为这其中有很多影响因素,比如类的总数,常量池的大小和方法数量等。将元数据从永久代剥离出来,不仅实现了对元空间的无缝管理,还可以简化Full GC以及对以后的并发隔离类元数据等方面进行优化。

移除永久代的影响:

  • 由于类的元数据分配在本地内存中,元空间的最大可分配空间就是系统可用内存空间。因此,我们就不会遇到永久代存在时的内存溢出错误,也不会出现泄漏的数据移到交换区这样的事情。最终用户可以为元空间设置一个可用空间最大值,如果不进行设置,JVM会自动根据类的元数据大小动态增加元空间的容量。
  • 注意:永久代的移除并不代表自定义的类加载器泄露问题就解决了。因此,你还必须监控你的内存消耗情况,因为一旦发生泄漏,会占用你的大量本地内存,并且还可能导致交换区交换更加糟糕。

元空间数据管理:

  • 元空间的内存管理由元空间虚拟机来完成。先前,对于类的元数据我们需要不同的垃圾回收器进行处理,现在只需要执行元空间虚拟机的C++代码即可完成。在元空间中,类和其元数据的生命周期和其对应的类加载器是相同的。话句话说,只要类加载器存活,其加载的类的元数据也是存活的,因而不会被回收掉。

元空间调优:

  • 默认情况下,-XX:MaxMetaspaceSize的值没有限制,因此元空间甚至可以延伸到交换区,但是这时候当我们进行本地内存分配时将会失败。
  • 为了避免频繁的GC,建议将–XX:MetaspaceSize设置为一个相对较高的值。对于一个64位的服务器端JVM来说,其默认的–XX:MetaspaceSize值为21MB。这就是初始的高水位线。一旦触及到这个水位线,Full GC将会被触发并卸载没有用的类(即这些类对应的类加载器不再存活),然后这个高水位线将会重置。新的高水位线的值取决于GC后释放了多少元空间。如果释放的空间不足,这个高水位线则上升。如果释放空间过多,则高水位线下降。如果初始化的高水位线设置过低,上述高水位线调整情况会发生很多次。
  • 经过多次GC之后,元空间虚拟机自动调节高水位线,以此来推迟下一次垃圾回收到来。
  • 有这样两个选项 ‑XX:MinMetaspaceFreeRatio和‑XX:MaxMetaspaceFreeRatio,他们类似于GC的FreeRatio选项,用来设置元空间空闲比例的最大值和最小值。我们可以通过命令行对这两个选项设置对应的值。

获取元空间信息的工具:

  • jmap -clstats PID:打印类加载器数据(-clstats是-permstat的替代方案)
  • jstat -gc LVMID:打印元空间的信息
  • jcmd PID GC.class_stats:连接到运行的JVM并输出详尽的类元数据的柱状图。

存在的问题:元空间虚拟机采用了组块分配的形式,同时区块的大小由类加载器类型决定。类信息并不是固定大小,因此有可能分配的空闲区块和类需要的区块大小不同,这种情况下可能导致碎片存在。元空间虚拟机目前并不支持压缩操作,所以碎片化是目前最大的问题。

1.1.4 关于垃圾收集

参考:http://developer.51cto.com/art/201508/489420.htm

1.2 OracleJDK和OpenJDK

稳妥起见,建议OracleJDK。

 

2. Java开发框架

2.1 Why Springboot?

参考《JavaEE开发的颠覆者:Spring Boot实战》

理念:“习惯优于配置”(项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动进行配置),让项目快速运行起来。使用Spring Boot很容易创建一个独立运行(运行jar,内嵌Servlet容器)、准生产级别的基于Spring框架的项目,使用spring Boot你可以不用或者只需要很少的Spring配置。

核心功能:

  • 独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行,运行一个Spring Boot项目只需要通过java -jar xx.jar来运行。
  • 内嵌Servlet容器:Spring Boot可选择内嵌Tomcat、Jetty或者Undertow,这样我们无须以war包形式部署项目。
  • 提供starter简化Maven配置:如使用了spring-boot-starter-web时,会自动加入相关依赖包。
  • 自动配置Spring:Spring Boot会根据在类路径中的jar包、类,为jar包里的类自动配置Bean。
  • 准生产的应用监控:提供基于http、ssh、telnet对运行时的项目进行监控。
  • 无代码生成和xml配置:条件注解而不是xml配置。

优点:

  • 快速构建项目
  • 对主流开发框架的无配置集成
  • 项目可独立运行,无须外部依赖Servlet容器
  • 提供运行时的应用监控
  • 极大地提高了开发、部署效率
  • 与云计算的天然集成

缺点:

  • 书籍文档较少且不够深入

2.2 Hibernate和MyBatis

参考http://blog.csdn.net/firejuly/article/details/8190229

MyBatis优势:

  • MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
  • MyBatis容易掌握,而Hibernate门槛较高。

Hibernate优势:

  •  Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
  • Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
  • Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
  • Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

 

3. 前后端分离:单页应用 OR 模板引擎 

 

4. 前后端接口文档自动生成:Swagger

参考:http://blog.csdn.net/wangnan9279/article/details/44541665

Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。

 

5. 业务端校验框架

FunctionalValidator介绍:http://jiebaojie.com/2017/01/28/FunctionalValidator/

主要优点:

  • 校验逻辑与业务逻辑解耦(HibernateValidator只能解决单参数的校验)
  • 目标提供更优雅、更易用的函数式业务逻辑验证框架(相比FluentValidator的优势)

缺点:

  • 不支持JDK7及以下版本
  • 需要对java8语法及函数式编程思想有一定了解

 

6. CT框架:Rundeck

参考:http://www.tuicool.com/articles/22me6zA

rundeck是一款开源的可以帮助你在数据中心或者云环境自动运行日常程序的软件,rundeck提供了一些特性来缓解费事繁琐的工作,并且很容易让你扩展自己的自动化成果。rundeck允许你在web界面或者命令行上指定在任何节点运行任务。rundeck也包含了其他特性来容易的扩展的你的自动化成果,例如:访问控制、工作流构建、调度、日志等等。

特性:

  • 提供web api
  • 分布式命令执行
  • 可插拔的系统插件
  • 多步骤工作流构建
  • 以守护进程执行job或者调度运行
  • 图形化web控制台来控制job执行
  • 基于规则的访问控制,支持LDAP/AD
  • 历史及构建日志查看
  • 可以集成到外部工具
  • 命令行控制工具

 

7. UT框架:TestNG和JUnit

参考:http://www.mkyong.com/unittest/junit-4-vs-testng-comparison/

中文翻译版:http://www.importnew.com/16270.html

TestNG 在参数化测试、依赖测试以及套件测试(组)方面功能更加强大。TestNG 意味着高级的测试和复杂的集成测试。它更加的灵活,特别是对大的套件测试。

 

8. 历史操作记录方案

9. MOCK框架

 

Mockito和JMockit。

 

两者的区别是,前者不能mock static method和final class、final method,后者可以,本项目mockito足以。