JAVA 拾遗--JPA 二三事

记得前几个月,spring4all 社区刚搞过一次技术话题讨论:如何对 JPA 或者 MyBatis 进行技术选型?传送门:http://www.spring4all.com/article/391 由于平时工作接触较多的是 JPA,所以对其更熟悉一些,这一篇文章记录下个人在使用 JPA 时的一些小技巧。补充说明:JPA 是一个规范,本文所提到的 JPA,特指 spring-data-jpa。

tips:阅读本文之前,建议了解值对象和实体这两个概念的区别。

使用 @Embedded 关联一对一的值对象

现实世界有很多一对一的关联关系,如人和身份证,订单和购买者…而在 JPA 中表达一对一的关联,通常有三种方式。下面就以订单(Order)和购买者(CustomerVo)为例来介绍这三种方式,这里 CustomerVo 的 Vo 指的是 Value Object。


JAVA 拾遗 --Instrument 机制

最近在研究 skywalking,发现其作为一个 APM 框架,比起作为 trace 框架的 zipkin 多了一个监控维度:对 JVM 的监控。而 skywalking 集成进系统的方式也和传统的框架不太一样,由于其需要对 JVM 进行无侵入式的监控,所以借助了 JAVA5 提供的 Instrument 机制。关于“Instrument”这个单词,没找到准确的翻译,个人理解为“增强,装配”。


研究优雅停机时的一点思考

开头先废话几句,有段时间没有更新博客了,除了公司项目比较忙之外,还有个原因就是开始思考如何更好地写作。远的来说,我从大一便开始在 CSDN 上写博客,回头看那时的文笔还很稚嫩,一心想着反正只有自己看,所以更多的是随性发挥,随意吐槽,内容也很简陋:刷完一道算法题记录下解题思路,用 JAVA 写完一个 demo 之后,记录下配置步骤。近的来看,工作之后开始维护自己的博客站点: www.cnkirito.moe 也会同步更新自己公众号。相比圈子里其他前辈来说,读者会少很多,但毕竟有人看,每次动笔之前便会开始思考一些事。除了给自己的学习经历做一个归档,还多了一些顾虑:会不会把知识点写错?会不会误人子弟?自己的理解会不会比较片面,不够深刻?等等等等。但自己的心路历程真的发生了一些改变。在我还是个小白的时候,学习技术:第一个想法是百度,搜别人的博客,一步步跟着别人后面配置,把 demo run 起来。而现在,遇到问题的第一思路变成了:源码 debug,官方文档。我便开始思考官方文档和博客的区别,官方文档的优势除了更加全面之外,还有就是:“它只教你怎么做”,对于一个有经验有阅历的程序员来说,这反而是好事,这可以让你有自己的思考。而博客则不一样,如果这个博主特别爱 BB,便会产生很多废话(就像本文的第一段),它会有很多作者自己思考的产物,一方面它比官方文档更容易出错,更容易片面,一方面它比官方文档更容易启发人,特别是读到触动到我的好文时,会抑制不住内心的喜悦想要加到作者的好友,这便是共情。我之后的文章也会朝着这些点去努力:不避重就轻,多思考不想当然,求精。

最近瞥了一眼项目的重启脚本,发现运维一直在使用 kill -9 <pid> 的方式重启 springboot embedded tomcat,其实大家几乎一致认为:kill -9 <pid> 的方式比较暴力,但究竟会带来什么问题却很少有人能分析出个头绪。这篇文章主要记录下自己的思考过程。

kill -9 和 kill -15 有什么区别?

在以前,我们发布 WEB 应用通常的步骤是将代码打成 war 包,然后丢到一个配置好了应用容器(如 Tomcat,Weblogic)的 Linux 机器上,这时候我们想要启动 / 关闭应用,方式很简单,运行其中的启动 / 关闭脚本即可。而 springboot 提供了另一种方式,将整个应用连同内置的 tomcat 服务器一起打包,这无疑给发布应用带来了很大的便捷性,与之而来也产生了一个问题:如何关闭 springboot 应用呢?一个显而易见的做法便是,根据应用名找到进程 id,杀死进程 id 即可达到关闭应用的效果。

上述的场景描述引出了我的疑问:怎么优雅地杀死一个 springboot 应用进程呢?这里仅仅以最常用的 Linux 操作系统为例,在 Linux 中 kill 指令负责杀死进程,其后可以紧跟一个数字,代表 ** 信号编号 **(Signal),执行 kill -l 指令,可以一览所有的信号编号。


给初中级 JAVA 准备的面试题

笔者作为一个今年刚毕业的初级 JAVA,根据群里水友的讨论,也结合自己刚毕业时的一些面经,加上近期一点点在公司面试别人的经验,总结了如下的常见面试问题,适用于初级和中级 JAVA。

JAVA

  1. HashMap 相关

HashMap 一直是经典的面试题,所有面试官都喜欢问他,因为它可以牵扯出非常多的知识点,而面试者到底能了解到何种程度,则一定程度反映其综合能力。

细节聊扩容因子 LoadFactor=0.75,初始大小 InitailCapacity=16


打开 orika 的正确方式

缘起

架构分层

开发分布式的项目时,DO 持久化对象和 DTO 传输对象的转换是不可避免的。集中式项目中,DO-DAO-SERVICE-WEB 的分层再寻常不过,但分布式架构(或微服务架构)需要拆分模块时,不得不思考一个问题:WEB 层能不能出现 DAO 或者 DO 对象?我给出的答案是否定的。

新的项目分层结构

这张图曾出现在我过去的文章中,其强调了一个分层的要素:服务层 (应用层) 和表现层应当解耦,后者不应当触碰到任何持久化对象,其所有的数据来源,均应当由前者提供。


JAVA 拾遗 -- 关于 SPI 机制

JDK 提供的 SPI(Service Provider Interface)机制,可能很多人不太熟悉,因为这个机制是针对厂商或者插件的,也可以在一些框架的扩展中看到。其核心类 java.util.ServiceLoader 可以在 jdk1.8 的文档中看到详细的介绍。虽然不太常见,但并不代表它不常用,恰恰相反,你无时无刻不在用它。玄乎了,莫急,思考一下你的项目中是否有用到第三方日志包,是否有用到数据库驱动?其实这些都和 SPI 有关。再来思考一下,现代的框架是如何加载日志依赖,加载数据库驱动的,你可能会对 class.forName(“com.mysql.jdbc.Driver”)这段代码不陌生,这是每个 java 初学者必定遇到过的,但如今的数据库驱动仍然是这样加载的吗?你还能找到这段代码吗?这一切的疑问,将在本篇文章结束后得到解答。

首先介绍 SPI 机制是个什么东西


java 小技巧 (一)-- 远程 debug

该系列介绍一些 java 开发中常用的一些小技巧,多小呢,从不会到会只需要一篇文章这么小。这一篇介绍如何使用 jdk 自带的扩展包配合 Intellij IDEA 实现远程 debug。

项目中经常会有出现这样的问题,会令程序员抓狂:关键代码段没有打印日志,本地环境正常生产环境却又问题… 这时候,远程 debug 可能会启动作用。

1 准备用于 debug 的代码

准备一个 RestController 用于接收请求,最后可以通过本地断点验证是否成功开启了远程 debug


XML 与 javabean 的转换

XML 可以说是一种被时代淘汰的数据传输格式,毕竟相比较 JSON,其语法,表现形式,以及第三方类库的支持,都要略逊一筹,但最近在对接一些老接口时,主要还是以 XML 为主,而翻阅相关的文档以及博客,没看到很好的文章介绍如何使用 xml 进行数据传输,所以简单写下此文,做一下记录。内心多多少少还是会抵制对接如此老旧的接口,不过生活还是要继续。

Code First

先上一段代码,展示一下如何封装,讲解放到后面

一个典型的对接方提供的 XML 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ORDER>
<ORDER_NO>10086</ORDER_NO>
<TOTAL_PRICE>3.14</TOTAL_PRICE>
<CREATE_TIME>2017-08-26 03:39:30</CREATE_TIME>
<ORDER_ITEMS>
<ORDER_ITEM>
<GOODS_NAME> 德芙 </GOODS_NAME>
<NUM>3</NUM>
</ORDER_ITEM>
<ORDER_ITEM>
<GOODS_NAME> 旺仔 </GOODS_NAME>
<NUM>10</NUM>
</ORDER_ITEM>
</ORDER_ITEMS>
</ORDER>

而我们要对应的实体类,则应当如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@XmlRootElement(name = "ORDER")// <1>
@XmlAccessorType(XmlAccessType.FIELD)// <1>
public class Order {

@XmlElement(name = "ORDER_NO")// <1>
private String orderNo;

@XmlElement(name = "TOTAL_PRICE")
private BigDecimal totalPrice;

@XmlElement(name = "CREATE_TIME")
@XmlJavaTypeAdapter(DateAdapter.class) // <2>
private Date createTime;

@XmlElementWrapper(name = "ORDER_ITEMS") // <3>
@XmlElement(name = "ORDER_ITEM")
private List<OrderItem> orderItems;

}
1
2
3
4
5
6
7
8
9
10
@XmlAccessorType(XmlAccessType.FIELD)
public class OrderItem {

@XmlElement(name = "GOODS_NAME")
private String goodsName;

@XmlElement(name = "NUM")
private Integer num;

}

我举的这个示例基本包含一般情况下所有可能出现的需求

<1> 常用注解 XmlRootElement,XmlAccessorType,XmlElement

<2> 日期转换的适配器注解

<3> 如何在 XML 中设置集合

在介绍这三点之前,先给出转换的工具类


java 并发实践 --ConcurrentHashMap 与 CAS

前言

最近在做接口限流时涉及到了一个有意思问题,牵扯出了关于 concurrentHashMap 的一些用法,以及 CAS 的一些概念。限流算法很多,我主要就以最简单的计数器法来做引。先抽象化一下需求:统计每个接口访问的次数。一个接口对应一个 url,也就是一个字符串,每调用一次对其进行加一处理。可能出现的问题主要有三个:

  1. 多线程访问,需要选择合适的并发容器
  2. 分布式下多个实例统计接口流量需要共享内存
  3. 流量统计应该尽可能不损耗服务器性能

但这次的博客并不是想描述怎么去实现接口限流,而是主要想描述一下遇到的问题,所以,第二点暂时不考虑,即不使用 redis。

说到并发的字符串统计,立即让人联想到的数据结构便是 ConcurrentHashpMap<String,Long> urlCounter;


volatile 疑问记录

对 java 中 volatile 关键字的描述,主要是 可见性有序性 两方面。

一个很广泛的应用就是使得多个线程对共享资源的改动变得互相可见,如下:


Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×