java代码分层规范

代码分层

不使用 biz层, 减少不必要复杂性

api/service/dao即可

对同一个模块, 应该包含两类service, 一个是业务表service, 一个是模块service, 模块service复杂度极高后。 说明该模块可以拆模块, 拆服务了

不允许service访问非本模块的Dao

如果要访问其他模块的数据, 必须通过service访问.

原则上, 每个表的dao只能由该表的service访问. 由此也可以避免掉关联查询

比如动态模块.
DynamicService 不能直接访问动态评论, 动态分的数据, 必须通过对应的service访问

todo

增加demo

对cache的理解

cache最好是entity级别

cache应该是读的

原则上redis的数据不可信, 应该以Mysql为准

当不得不以redis为准时. 应该根据业务流程, 辅以技术手段, 划分在哪个阶段以redis为准, 在哪个阶段以mysql为准.

可以不同的段针对同样的数据保存在不同的地方。 这样就能确认每个阶段的数据状态。 这样当局部以不可靠数据源为准时, 可以使用相对较小的成本去保证数据的可靠性, 因为此时明确知道在那些阶段数据是以Mysql为准, 是可靠的. 只需要处理不可靠的那个小段即, 因为此时明确知道在那些阶段数据是以Mysql为准, 是可靠的. 只需要处理不可靠的那个小段即可.

case

todo

jackson序列化

jackson的序列化有坑, 可能会导致死循环, 栈溢出

1
2
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)

所以慎重使用jackson序列化, 当存在A,B循环引用的时候就会存在该序列化问题

同样的还有注解lombok 的 @Data注解, 同样有该风险

栈溢出的case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

package me.huakai.domain.api;

import com.alibaba.fastjson.JSONObject;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

/**
* 测试循环引用的 toString 和 toJson 方法
* @author xiang.rao created on 3/7/18 9:15 PM
* @version $Id$
*/
@Slf4j
public class CircleReferenceSerializableTest {


@Test
public void testJson() {
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
String encodeA = JSONObject.toJSON(a).toString();
log.info("encodeA:{}", encodeA);
}

@Test
public void testToString() {
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
log.info("a:{}", a);
}
}

@Getter
@Setter
class A {
private B b;

@Override
public String toString() {
return "A{" +
"b=" + b +
'}';
}
}


@Getter
@Setter
@ToString
class B {
private A a;

@Override
public String toString() {
return "B{" +
"a=" + a +
'}';
}
}

jackson 结合redis序列化, 反序列化时候有坑

如果value存储的不是bean对象, 是基本的整数类型, int, long, biginteger. jackson会根据数字长度去决定反序列化的结果是什么类型. 这时候可能和程序希望的类型不一致

如果value 是bean对象, 就没有该问题

参考

http://the-whiteboard.github.io/java/debugging/warstory/2017/03/12/dangers-of-objects-from-json.html

https://stackoverflow.com/questions/34238153/spring-data-redis-java-lang-classcastexception

comparable 比较的坑

Exception in thread “main” java.lang.IllegalArgumentException: Comparison method violates its general contract!at java.util.TimSort.mergeLo(TimSort.java:777)at java.util.TimSort.mergeAt(TimSort.java:514)at java.util.TimSort.mergeCollapse(TimSort.java:439)at java.util.TimSort.sort(TimSort.java:245)at java.util.Arrays.sort(Arrays.java:1512)at java.util.ArrayList.sort(ArrayList.java:1462)at java.util.Collections.sort(Collections.java:175)at com.applabel.utils.SortList.getSortList(SortList.java:38)at com.applabel.utils.SortList.main(SortList.java:22)

3、分析原因:
在JDK7以后,实现Comparable接口后,要满足一下三个特性:

1) 自反性:x,y 的比较结果和 y,x 的比较结果相反。

2) 传递性:x>y,y>z,则 x>z。

3) 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。

参考

实现Comparable接口报错:Comparison method violates its general contract!