Java中的魔法: SPI

Java中的魔法: SPI

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制,常用于创建可扩展、可替换组件的应用程序,是java中模块化插件化的关键。

SPI 框架包含3个基本组件:

  1. 服务接口 Service Interface
  2. 服务接口的实现类,Service Provider
  3. 服务加载器 Service Loader

Service Interface是一组定义标准的接口和类。Service Provider是服务接口的特定实现,需要实现接口,并子类化服务本身中定义的类。java.util包下的ServiceLoader类就是SPI机制的核心类,主要功能是通过相关的类加载器扫描并加载provider的jar包,并且通过反射实例化服务的实现类。服务Provider程序可以以扩展的形式安装在Java平台的实现中,也就是说,可以将provider的jar文件放置在任何常用扩展目录中,也可以通过将其jar包添加到应用程序的类路径或通过其他一些特定于平台的方式来使使用方来调用。

ServiceLoader机制允许用户在其应用程序代码保持不变的前提下扩展程序功能或者添加新功能。例如SLF4J本身只是API,日常编程中我们只需要使用LogFactory获得log实例,而不用关心底层是的日志实现框架是Logback还是Log4J;java.sql.Driver是在java中定义的标准SQL服务API,如果需要从oracal数据库切换到mysql数据库,我们的数据访问层代码不需要任何修改,只需要替换掉jdbc 驱动包即可。

JDK中包含了非常多的SPI服务功能(如servlet、邮件服务、音频服务、SQL驱动,大部分位于javax),以供不同的服务厂商或者插件商基于标准定义实现自己的方案。除了能够服务于厂商或插件商,JavaSPI 也为我们实现框架扩展提供了一个不错思路。当一个功能可能会有两种以上的实现方案时,可以在应用程序中预留出 SPI 接口,剩下的适配工作便留给了开发者,这样可以在不侵入代码的前提下,通过增删依赖来扩展框架

解密SPI

目标:实现消息推送功能,要求后期能够切换不同推送厂商的推送服务(例如极光推送、小米推送、百度推送等等)


金融系统中正确的金额计算及存储方式

金融系统中正确的金额计算及存储方式

经典的精度丢失问题

Java中的类型float、double用来做计算会有精度丢失问题,下面来看下面的示例。

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
test1();
test2();
}

private static void test1() {
double totalAmount = 0.09;
double feeAmount = 0.02;
double tradeAmount = totalAmount - feeAmount;
System.out.println(tradeAmount);
}

上面的程序输出结果是多少?

0.07?非也!

正确的结果是:

1
0.06999999999999999

为什么是这样?


JVM8的启动参数

1. JVM版本

本文所描述的启动参数在如下JVM版本测试通过,

java --version
1
2
3
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)

启动参数的推荐值主要针对的场景为:4核CPU + 4G内存的机器配置,部署单应用,应用的堆内存使用量在1-2GB。

2. 服务器配置

参数名 说明 默认值 推荐值 备注
server Java Hotsport Server VM 64位机器默认为server选项 启用 -

java编程技巧累积(持续更新)

java 编程技巧累积

  1. 对象深复制
  2. ShutdownHook
  3. LRUMAP
  4. 单例模式
  5. Mysql insert/update IGNORE的利用
  6. 更多…

自动化部署 - 如何利用rpm-maven-plugin打包前后端项目

Maven打包成RPM

RPM全称是 Red Hat Package Manager(Red Hat包管理器)。几乎所有的 Linux 发行版本都使用这种形式的软件包管理安装、更新和卸载软件。

在devops链条上,常见的部署方式是通过持续集成工具如jenkins/CI 构建和发布jar包到服务端制定目录。不过随着越来越多的应用趋向于paas 平台,本地化自动部署的需求越来越多,在软件包的安装过程中各种自动控制命令的集成也越来越复杂,jenkins等部署方式已经无法满足需求,这时候将软件包和集成脚本一起打包成rpm包的形式,也是一种另外的思路。对于最终用户来说,使用 RPM所提供的功能来维护系统是比较容易和轻松的。安装、卸载和升级RPM软件包只需一条命令就能搞定。
后续还可以构建yum本地源,通过ambari等其他集成工具,进行对软件包的安装、管理、监控、卸载、升级全生命周期的管控

利用rpm-maven-plugin插件实现rpm构建,以便于RPM软件仓库管理。
包含四个部分:

  • 基本单项目 打包成rpm
  • 多module 项目打包成rpm
  • 纯前端项目 打包成rpm
  • rpm script 应用-通过自动创建软连接实现rpm包自动升级

备注:

rpm-maven-plugin 需要在linux 机器上才能正常运行,运行机器需要

1
yum install rpm-build

Java Thread Life Cycle and Thread States

Java Thread Life Cycle and Thread States

一个java 线程 在它的生命周期来,可以处于下图的任何一个状态,可以是 New,Runnable,Blocked,Waiting,Timed Waiting 或 Terminated。同业也称为生命周期内的事件。

Java Thread Life Cycle Status

Java-Thraed-Life-Cycle-States


java 并发工具类CountDownLatch & CyclicBarrier

java 并发工具类CountDownLatch & CyclicBarrier

CountDownLatch

CountDownLatch 概念

CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×