这些年 java 非主流技术的那些事

Posted by NotGeek on December 22, 2018

主流的 JAVA 技术

  • Spring 全家桶
  • Struts
  • Apache ActiveMQ
  • Mybatis
  • Spark
  • Hibernate
  • JPA
  • Shiro
  • ……

Web 表示层

  • struts
  • spring web MVC
  • Spring Web Flux
  • JSF
  • JAX-RS ( REST )

持久层

  • iBatis
  • Mybatis
  • Hibernate
  • JPA
  • Spring JDBC

消息

  • Apache ActiveMq
  • RabbitMq
  • RocketMq
  • Kafka

RPC

  • Dubbo
  • Spring Cloud

议题

  • 语言工具类拓展
  • 集合工具类拓展
  • JAVA SPI 拓展
java 非空判断
  • Nulling : JSR 303 Not null 、JSR 308 @NonNull
  • 集合非空
    • Collection
    • Map
  • 数组非空

站在哲学的一定的高度上来思考这个问题。

为什么人都吃得了贫穷的苦,却吃不了学习的苦。

学习是一个主动吃苦的过程,而贫穷是一个被动的吃苦的过程。

你学习的时候,要查询很多文档。

开发的时候的意识

  • 版本意识
    • JAVA 7
    • JAVA 8
  • 依赖意识
    • JAVA 6
      • Spring
      • Apache Commons-Lang

我们对主流框架非常的推崇。会对他们的编程模式不自觉地推崇

编程模式

  • Spring 事务

    • @Transational

    • 1
      
      <Bean id=""  class=""/>
      
      1
      2
      3
      
      new Thread(()->{
              
      });
      

你要站在一个很高地高度,高屋建瓴,不受制于某一个框架。

  • 顶层设计能力
  • 下层细节实现能力。

上层建筑决定系统的合理性,下层决定你的落地是不是实在。

很多架构师给你一个蓝图,但是行不行,他心里都没有谱。

​ How To Do ?

不知道怎么去做。

  • Apache
    • BCEL
      • 字节码的提升
    • BeanUtils
      • 反射,java Beans 的东西。
    • Cli
      • 命令行解析 -D -d
    • Codec
    • Collections
      • 集合
    • Compress
      • 压缩 zip tar
    • Digester
      • XML 的解析,只能用于解析 tomcat 里版用的多
    • Lang
      • 拓展
1
2
3
String name
int age
// 一个map 通过反射映射到这个类上边去。

Spring 只是一部分

1
2
3
4
5
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>3.7</version>
</dependency>

StringUtils:

  • apache
    • isBlank
  • Spring
    • hasText

都有重复发明轮子。

如果你的依赖只有 Spring ,干脆就不要,不要重复的去实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class NullDemo {
    public static void main(String[] args) {
        Object object = null;
        System.out.println(Objects.isNull(object));
    }

    /***
     *Before 7
     */
    private static boolean isnNull(Object object) {
        return object == null;
    }
}
org.springframework.util.StringUtils#parseLocale
1
2
3
4
5
6
7
8
9
10
11
@Nullable
public static Locale parseLocale(String localeValue) {
    String[] tokens = tokenizeLocaleSource(localeValue);
    if (tokens.length == 1) {
        validateLocalePart(localeValue);
        Locale resolved = Locale.forLanguageTag(localeValue);
        return resolved.getLanguage().length() > 0 ? resolved : null;
    } else {
        return parseLocaleTokens(localeValue, tokens);
    }
}

标准的 JAVA 的 API

​ 你用一些顶层框架以后,屏蔽了很多细节,一个好的程序员要站在巨人的肩膀上,首先你要知道巨人的肩膀在哪里。爬到肩膀上去才能去做。

RabbitMq 新特性的文章看的人多。非主流技术的文章看的人少,

永远站在一个使用者的角度,而不是站在一个发明者的角度。所以永远不会提高。

多用才不会忘记!

很多工具类里边,你要去注意它的版本。 其实 Spring 做的不是很好。

API 推荐书籍 《Practical.API.Design.Confessions.of.a.Java.Framework.Architect》

JAVA Beans 的作者

什么是决定你是一个好的 API ?

  • 二进制兼容
  • 源代码兼容

它的书少看。Martin Fowler 把很多概念给转换了。

《Effective Java》

集合操作尽量返回非null;

书中讲 Array 不如 List

但是没有考虑性能问题。

下边这段代码创建了几个对象?
1
String value = "a" + "b";
  • @Since JAVA 7 StringBuilder 是一个对象
  • before Java 7 String 是三个对象。

写代码非常的难。

你要考虑各种问题,站在设计的角度上

兼听则明,偏听则暗。

看文章,有些文章又对又不对的。

  • ArrayList
    • java 6 的时候, 10
    • JAVA 7 的时候,是 null 的。
    • JAVA 8 : 0 添加一个元素的时候,才是 10

Integer 有一个 cache,自动拆箱,装箱的。

是不是有缓存。

  • JDK 1,7
    • static 里边
  • JDK 1.6
    • InterCache 是一个内置类了。

-128~127 这个内存是可以调整的。

HashMap 算法改变了,

  • < JDK 1.8
    • 链表 + 数组 Hash Table
  • 1.8 红黑树

不要被面试题!!!

先有技术,再有题目。

面试题可以参考一下,但是一定要有自己的方法。

java.util.Collections

如何生成一个一个元素的 Set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CollectionDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                add();
            }).start();
        }
    }

    private static void add(){
        // 线程安全吗?
        Set<String> values = Collections.singleton("1");

        // 线程安全吗?
        Set<String> newValues = new ConcurrentSkipListSet<>();
        values.add("1");
        newValues.add("1");
    }
}

这是一个并发的重进入的问题。

在方法里边怎么掉都是线程安全的。

你每个线程看到对象的状态是不一样的。

集合返回的时候,尽量返回不变的对象。

java.util.Collections#unmodifiableCollection

全部的都是只读。写的什么之类的都报错。

java.util.HashMap#values

返回的是集合的一个视图。只能看,不能改。浅 copy 的问题,也会有问题。

Arrays#mergeSort

  • 1.6 堆排序

java.util.List#sort

  • 1.7 会有一个阈值了。
  • 1.8 有点类似 TimSort

每个 JAVA 版本都有区别。

1
2
3
public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

TreeMap 的 key 是可以比较的。

不是可比较的,就会编译失败。

TreeMap 的 key 不约束,是因为 可以把 Comparator 丢进去。

TreeMap -> Comparator

  • Key1, key2
    • comparator -> key1 instanceof Object
    • Comparator -> key 咳哟 instanceof Comparable 相互比较

String

Integer

看你设计,工匠的心情。

开发仅仅是 4 则混合运算。

<k extends Comparable , V> == k class = Comparable.class or subClass

JAVA SPI

java Spi 有很多种

  • ServiceLoder 机制

dubbo 的 SPI 类似

SPI = Service Provider Interface

SPI API

  • Client SPI 提供实现

dubbo 的 SPI 是不是有 问题。

java.util.spi.ResourceBundleControlProvider

会解决 properties 的中文乱码的问题。

JAVA 6 里边提供了一个解决方案

jdk.internal.misc.JavaUtilResourceBundleAccess#getBundle

java.util.ResourceBundle.Control

会去取资源文件用的是 InputStream 字节流,就没有编码

META-INF/services

  • java.uitls.spi.ResourceBundlControlProvider 配置。

如果我有多个不同的实现,分发在不同的 jar 包得时候,怎么去设计。

abc=ABCLoadBalance

def=DEFLoadBalance

性能没有太大得影响,启动的时候就加载了。

java 只能通过顺序,区分,

Dubbo 的方式可以通过 key 去取

你没有比较,就不知道其中的

当多个 ClassLoader 的时候,你是不确定哪个是先加载,哪个是后加载的。

好的解决方案是

使用注解 @SPI("abc") 在框架的层面取校验

改变了我们的内部实现 SPI 类似于 AOP 的实现。

1
2
ResourceBundle DefaultControl 中文乱码
ResourceBundleControlProvider 替换掉 DefaultControl 

我代码去读取的时候

  • 旧方式:
    • ResourceBundle.getBundle() -> DefaultControl-> 中文乱码
  • 新方式:
    • ResourceBundle.getBundle() -> control -> 中文正常

SPI

java

java.util.ServiceLoader

Spring

org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
public class ServiceLoaderFactoryBean extends AbstractServiceLoaderBasedFactoryBean implements BeanClassLoaderAware {
    public ServiceLoaderFactoryBean() {
    }

    protected Object getObjectToExpose(ServiceLoader<?> serviceLoader) {
        return serviceLoader;
    }

    public Class<?> getObjectType() {
        return ServiceLoader.class;
    }
}
Spirng 把我的 Service 当做了他的一个 Bean。

《Practical API Design》

一个是 java 的扩展机制,

Java 6 的 java.utils.ServiceLoader

书中的 serviceLoader 的 依赖注入是 JAVA 的依赖注入

​ 国内的没有很牛逼的开源软件,但是讲起来某些技术头头是道。用的时候,用的淋漓尽致,创造的时候,创造不出来。