[关闭]
@zhuchao941 2018-07-09T10:11:20.000000Z 字数 10673 阅读 781

订单中心代码规范

命名规约

  1. 【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。

    1. 反例:_name / __name / $name / name_ / name$ / name__
  2. 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。

    1. 说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式 也要避免采用。
    2. 正例:alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文。
    3. 反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3
  3. 【强制】类名使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等(统一DTO,暂未区分其他)。

    1. 正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
    2. 反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
  4. 【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从 驼峰形式。

    1. 正例: localValue / getHttpMessage() / inputUserId
  5. 【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。

    1. 正例:MAX_STOCK_COUNT 
反例:MAX_COUNT
  6. 【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类 命名以它要测试的类的名称开始,以 Test 结尾。

  7. 【强制】类型与中括号紧挨相连来表示数组。

    1. 正例:定义整形数组 int[] arrayDemo;
    2. 反例:在 main 参数中,使用 String args[]来定义。
  8. 【强制】POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。

    1. 反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),RPC 阿里巴巴 Java 开发手册 2/38 框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛 出异常。
  9. 【强制】包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。包名统一使用 单数形式,但是类名如果有复数含义,类名可以使用复数形式。

    1. 正例:应用工具类包名为 com.alibaba.ai.util、类名为 MessageUtils(此规则参考 spring 的框架结构)
  10. 【强制】杜绝完全不规范的缩写,避免望文不知义。

    1. 反例:AbstractClass“缩写”命名成 AbsClasscondition“缩写”命名成 condi,此类随 意缩写严重降低了代码的可阅读性。
  11. 【推荐】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词 组合来表达其意。 


    1. 正例:在 JDK 中,表达原子更新的类名为:AtomicReferenceFieldUpdater
    2. 反例:变量 int a 的随意命名方式。
  12. 【推荐】如果模块、接口、类、方法使用了设计模式,在命名时需体现出具体模式。

    1. 说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。
    2. 正例:
    3. public class OrderFactory;
    4. public class LoginProxy;
    5. public class ResourceObserver;
  13. 【推荐】接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁 性,并加上有效的 Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。 


    1. 正例:接口方法签名 void commit(); 接口基础常量 String COMPANY = "alibaba";
    2. 反例:接口方法定义 public abstract void f();说明:JDK8 中接口允许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默 认实现。
  14. 【强制】枚举类名带上 En 后缀,枚举成员名称需要全大写,单词间用下划线隔开。 


    1. 说明:枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有。正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKNOWN_REASON
  15. 【参考】各层命名规约:

    1. Manager 层方法命名规约
    2. 获取单个对象的方法用 get 做前缀。
    3. 获取多个对象的方法用 list 做前缀,复数形式结尾如:listObjects
    4. 获取统计值的方法用 count 做前缀。
    5. 插入的方法用 save/insert 做前缀。
    6. 删除的方法用 remove/delete 做前缀。
    7. 修改的方法用 update 做前缀。
    8. 领域模型命名规约
    9. 数据对象:MyBatis自动生成,对应表名即可。命名上不做改动
    10. 数据传输对象:xxxDTOxxx 为业务领域相关的名称。

    常量定义

  16. 【强制】不允许任何魔法值(即未经预先定义的常量)直接出现在代码中。

    1. 反例:
    2. String key = "Id#taobao_" + tradeId;
    3. cache.put(key, value);
  17. 【强制】在 long 或者 Long 赋值时,数值后使用大写的 L,不能是小写的 l,小写容易跟数字 1 混淆,造成误解。

    1. 说明:Long a = 2l; 写的是数字的 21,还是 Long 型的 2?
  18. 【推荐】不要使用一个常量类维护所有常量,要按常量功能进行归类,分开维护。

    1. 说明:大而全的常量类,杂乱无章,使用查找功能才能定位到修改的常量,不利于理解和维护。
    2. 正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts

OOP 规约

  1. 【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成 本,直接用类名来访问即可。 

  2. 【强制】所有的覆写方法,必须加@Override 注解。

    1. 说明:getObject()与 get0bject()的问题。一个是字母的 O,一个是数字的 0,加@Override 可以准确判断是否覆盖成功。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错。
  3. 【强制】相同参数类型,相同业务含义,才可以使用 Java 的可变参数,避免使用 Object。

    1. 说明:可变参数必须放置在参数列表的最后。(提倡同学们尽量不用可变参数编程)
    2. 正例:public List listUsers(String type, Long... ids) {...}
  4. 【强制】外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生 影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么。

  5. 【强制】不能使用过时的类或方法。

    1. 说明:java.net.URLDecoder 中的方法 decode(String encodeStr) 这个方法已经过时,应该使用双参数 decode(String source, String encode)。接口提供方既然明确是过时接口, 那么有义务同时提供新的接口;作为调用方来说,有义务去考证过时方法的新实现是什么。
  6. 【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。

    1. 正例:"test".equals(object);
    2. 反例:object.equals("test");
    3. 说明:推荐使用 java.util.Objects#equals(JDK7 引入的工具类)

  7. 【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。

    1. 说明:对于 Integer var = ? 在-128 127 范围内(描述不精确,这个值可以通过JVM启动参数来改变)的赋值,Integer 对象是在 IntegerCache.cache产生,会复用已有对象,这个区间内的Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
  8. 【强制】定义 DO/DTO/VO 等 POJO 类时,不要设定任何属性默认值。

    1. 反例:POJO 类的 gmtCreate 默认值为 new Date(),但是这个属性在数据提取时并没有置入具体值,在更新其它字段时又附带更新了此字段,导致创建时间被修改成当前时间。
  9. 【强制】序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;如果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。

    1. 说明:注意 serialVersionUID 不一致会抛出序列化运行时异常。
  10. 【强制】构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。


  11. 【强制】禁止在 POJO 类中,同时存在对应属性 xxx 的 isXxx()和 getXxx()方法。

    1. 说明:框架在调用属性 xxx的提取方法时,并不能确定哪个方法一定是被优先调用到。
  12. 【推荐】setter 方法中,参数名称与类成员变量名称一致,this.成员名 = 参数名。在 getter/setter方法中,不要增加业务逻辑,增加排查问题的难度。

    1. 反例:
    2. public Integer getData() {
    3. if (condition) {
    4. return this.data + 100;
    5. } else {
    6. return this.data - 100;
    7. }
    8. }
  13. 【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。

    1. 说明:下例中,反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象, 然后进行 append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。
    2. 反例:
    3. String str = "start";
    4. for (int i = 0; i < 100; i++)
    5. {
    6. str = str + "hello";
    7. }
  14. 【推荐】类成员与方法访问控制从严:
    如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。
    工具类不允许有 public 或 default 构造方法。
    类非 static 成员变量并且与子类共享,必须是 protected。
    类非 static 成员变量并且仅在本类使用,必须是 private。
    类 static 成员变量如果仅在本类使用,必须是 private。
    若是 static 成员变量,考虑是否为 final。
    类成员方法只供类内部调用,必须是 private。
    类成员方法只对继承类公开,那么限制为 protected。

    1. 说明:任何类、方法、参数、变量,严控访问范围。过于宽泛的访问范围,不利于模块解耦。
    2. 思考:如果是一个 private 的方法,想删除就删除,可是一个 public service 成员方法或 成员变量,删除一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视线内,变量作 用域太大,无限制的到处跑,那么你会担心的。

集合处理

  1. 【强制】关于 hashCode 和 equals 的处理,遵循如下规则:

    1. 只要重写 equals,就必须重写 hashCode。
    2. 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的 对象必须重写这两个方法。
    3. 如果自定义对象作为 Map 的键,那么必须重写 hashCode 和 equals。
    1. 说明:String 重写了 hashCode equals 方法,所以我们可以非常愉快地使用 String 对象作为 key 来使用。
    2. 其他自定义的对象的话,建议使用 Lombok 来重写 hashCodeequals 方法
  2. 【强制】ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException 异常,即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。

    1. 说明:subList 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 而是 ArrayList 的一个视图,对于 SubList 子列表的所有操作最终会反映到原列表上。
  3. 【强制】使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方 法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

    1. 说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配器模式,只是转换接口,后台的数据仍是数组。
    2. String[] str = new String[] { "you", "wu" };
    3. List list = Arrays.asList(str);
    4. 第一种情况:list.add("yangguanbao"); 运行时异常。
    5. 第二种情况:str[0] = "gujin"; 那么 list.get(0)也会随之修改。
  4. 【强制】不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。

    1. 正例:
    2. List list = new ArrayList<>();
    3. list.add("1");
    4. list.add("2");
    5. Iterator iterator = list.iterator();
    6. while (iterator.hasNext()) {
    7. String item = iterator.next();
    8. if (删除元素的条件) {
    9. iterator.remove();
    10. }
    11. }
    12. 反例:
    13. for (String item : list) {
    14. if ("1".equals(item)) {
    15. list.remove(item);
    16. }
    17. }
    18. 说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把“1”换成“2”,会是同样的 结果吗?
  5. 【推荐】集合泛型定义时,在 JDK7 及以上,使用 diamond 语法或全省略。

    1. 说明:菱形泛型,即 diamond,直接使用<>来指代前边已经指定的类型。
    2. 正例: // <> diamond 方式 HashMap userCache = new HashMap<>(16);
    3. // 全省略方式 ArrayList users = new ArrayList(10);
  6. 【推荐】集合初始化时,指定集合初始值大小。 说明:HashMap 使用 HashMap(int initialCapacity) 初始化。 
正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意负载因子(即 loader factor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。 


    1. 反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容 7 次被迫扩大,resize 需要重建 hash 表,严重影响性能。
  7. 【参考】利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的 contains 方法进行遍历、对比、去重操作。

  8. 【强制】两个大List求非交集部分,不允许直接使用removeAll(会有两重循环)

并发处理

  1. 【强制】创建线程池都使用统一的工具类来创建,避免自己手动创建,且需要明确核心参数的设置(比如核心线程数,任务队列)

  2. 【强制】SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为 static,必须加锁,或者使用 DateUtils 工具类。

    1. 正例:注意线程安全,使用 DateUtils。亦推荐如下处理:
    2. private static final ThreadLocal df = new ThreadLocal() {
    3. @Override protected DateFormat initialValue() {
    4. return new SimpleDateFormat("yyyy-MM-dd");
    5. }
    6. };
    7. 说明:如果是 JDK8 的应用,可以使用 Instant 代替 DateLocalDateTime 代替 Calendar DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe
  3. 【强制】高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

    1. 说明:尽可能使加锁的代码块工作量尽可能的小,避免在锁代码块中调用 RPC 方法。
  4. 【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造 成死锁。

    1. 说明:线程一需要对表 ABC 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序 也必须是 ABC,否则可能出现死锁。
  5. 【强制】并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加 锁,要么在数据库层使用乐观锁,使用 合适字段 作为更新依据。(比如更新余额时使用余额作为乐观锁字段)

    1. 说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁默认都是手动重试,程序不做自动重试
  6. 【推荐】使用 CountDownLatch 进行异步转同步操作,每个线程退出前必须调用 countDown 方法,线程执行代码注意 catch 异常,确保 countDown 方法被执行到,避免主线程无法执行 至 await 方法,直到超时才返回结果。

    1. 说明:注意,子线程抛出异常堆栈,不能在主线程 try-catch 到。
  7. 【推荐】避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一 seed 导致的性能下降。

    1. 说明:Random 实例包括 java.util.Random 的实例或者 Math.random()的方式。正例:在 JDK7 之后,可以直接使用 API ThreadLocalRandom,而在 JDK7 之前,需要编码保 证每个线程持有一个实例。
  8. 【推荐】在并发场景下,通过双重检查锁(double-checked locking)实现延迟初始化的优 化问题隐患(可参考 The "Double-Checked Locking is Broken" Declaration),推荐解 决方案中较为简单一种(适用于 JDK5 及以上版本),将目标属性声明为 volatile 型。

    1. 反例:
    2. class LazyInitDemo {
    3. private Helper helper = null;
    4. public Helper getHelper() {
    5. if (helper == null)
    6. synchronized(this) {
    7. if (helper == null) {
    8. helper = new Helper();
    9. }
    10. return helper;
    11. } // other methods and fields...
    12. }
  9. 【参考】volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题, 但是如果多写,同样无法解决线程安全问题。如果是 count++操作,使用如下类实现: AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推 荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)。


  10. 【参考】 HashMap 在容量不够进行 resize 时由于高并发可能出现死链,导致 CPU 飙升,在 开发过程中可以使用其它数据结构或加锁来规避此风险。

控制语句

  1. 【强制】在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程 序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且 放在最后,即使空代码。
  2. 【强制】在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避免采用 单行的编码方式:

    1. if (condition) statements;
  3. 【强制】在高并发场景中,避免使用”等于”判断作为中断或退出的条件。

    1. 说明:如果并发控制没有处理好,容易产生等值判断被“击穿”的情况,使用大于或小于的区间判断条件来代替。
    2. 反例:判断剩余奖品数量等于 0 时,终止发放奖品,但因为并发处理错误导致奖品数量瞬间变成了负数,这样的话,活动无法终止。

日志规范

  1. 【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 SLF4J 中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

    1. import org.slf4j.Logger;
    2. import org.slf4j.LoggerFactory;
    3. private static final Logger LOGGER = LoggerFactory.getLogger(Abc.class);
  2. 【强制】对 trace/debug/info 级别的日志输出,必须使用条件输出形式或者使用占位符的方式。

    1. 反例:
    2. LOGGER.debug("Processing trade with id: " + id + " and symbol: " + symbol);
    3. 如果日志级别是 warn,上述日志不会打印,但是会执行字符串拼接操作,如果 symbol 是对象, 会执行 toString()方法,浪费了系统资源,执行了上述操作,最终日志却没有打印。
    4. 正例:
    5. LOGGER.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
  3. 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。不要把堆栈信息吃掉。

    1. 反例:
    2. catch(Exception e){
    3. LOGGER.error("occurs error");
    4. }
    5. 正例:
    6. catch(Exception e){
    7. LOGGER.error("occurs error", e);
    8. }
  4. 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘 撑爆,并记得及时删除这些观察日志。

    1. 说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。
    2. 记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
  5. 【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况,避免用户投诉时,无所适 从。如非必要,请不要在此场景打出 error 级别,避免频繁报警。

    1. 说明:注意日志输出的级别,error 级别只记录系统逻辑出错、异常或者重要的错误信息。error级别日志的记录准则是,是否需要技术干预,比如业务异常/参数不合法 这种都打warn
  6. 【强制】业务监控埋点文档

异常处理

  1. 【强制】Java 类库中定义的可以通过预检查方式规避的 RuntimeException 异常不应该通过 catch 的方式来处理,比如:NullPointerException,IndexOutOfBoundsException 等等。

    1. 说明:无法通过预检查的异常除外,比如,在解析字符串形式的数字时,不得不通过 catch NumberFormatException 来实现。
    2. 正例:if (obj != null) {...}
    3. 反例:
    4. try {
    5. obj.method();
    6. }
    7. catch (NullPointerException e) {…}
  2. 【强制】异常不要用来做流程控制,条件控制。

    1. 说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式 要低很多。
  3. 【强制】catch 时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。 对于非稳定代码的 catch 尽可能进行区分异常类型,再做对应的异常处理。

    1. 说明:对大段代码进行 try-catch,使程序无法根据不同的异常做出正确的应激反应,也不利 于定位问题,这是一种不负责任的表现。 正例:用户注册的场景中,如果用户输入非法字符,或用户名称已存在,或用户输入密码过于 简单,在程序上作出分门别类的判断,并提示给用户。
  4. 【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。

  5. 【强制】finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。

    1. 说明:如果 JDK7 及以上,可以使用 try-with-resources 方式。
  6. 【强制】不要在 finally 块中使用 return。

    1. 说明:finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。
  7. 【推荐】方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分 说明什么情况下会返回 null 值。

    1. 说明:本手册明确防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用 阿里巴巴 Java 开发手册 20/38 者来说,也并非高枕无忧,必须考虑到远程调用失败、序列化失败、运行时异常等场景返回 null 的情况。
  8. 【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:

    1. 返回类型为基本数据类型,return包装数据类型的对象时,自动拆箱有可能产生 NPE

      1. public int f() { return Integer 对象}, 如果为 null,自动解箱抛 NPE
    2. 数据库的查询结果可能为 null。

    3. 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。
    4. 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。
    5. 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。
    6. 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。 正例:使用 JDK8 的 Optional 类来防止 NPE 问题。

    Dubbo接口设计规范

  9. 单一原则
    1. 一个接口只做明确的一件事
    2. 便于排查问题(因为没有N多的逻辑分支)
    3. 对调用方友好
  10. 参数定义明确
    1. 调用方需要明确每个字段的含义,没有【这个字段某个调用方不用管】这么一种说法
    2. 在遵循【单一原则】的前提下,应该也不会有冗余的字段
  11. 参数校验
    1. 必传参数做好校验并明确提示,提前让消费者明确
    2. 某些参数不传可能触发异常流程,导致业务结果异常
    3. 不要以NPE来兜底
    4. 便于双方排查问题
  12. 入参和返回参数设计
    1. 遵循命名规范,语义简洁明确无歧义
    2. 参数不用枚举类型
    3. 形参为保证可扩展性尽量都使用自定义DTO类来传参
  13. 异常处理

    1. 直接抛异常,区分业务异常(自定义的,继承自DubboException)和非业务异常(类似NPE)

    数据库(Mysql)相关规范

    Redis相关规范

    ES相关规范

    配置中心(Disconf)使用规范

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注