Wire实现Golang依赖注入一、什么是依赖注入简单来说,就是在项目开发中,我们经常遇到一直情况,实例A的创建会依赖于实例B的创建,并且在实例A的生命周期内,持有对实例B的访问权限。
二、为什么要使用依赖注入如果不适用依赖注入的话会有以下风险:
全局变量⼗分不安全,存在覆写的可能。
资源散落在各处,可能重复创建,浪费内存,后续维护能⼒极差。
提⾼循环依赖的⻛险。
全局变量的引⼊提⾼单元测试的成本
在使用依赖注入后,可以方便我们的代码进行维护。
三、Golang依赖注入目前来说我的解决方案是通过Google的Wire去实现Golang依赖注入
Wire对比与其他在运行阶段依靠反射实现依赖注入的方式来说,优势在于能在编译期实现依赖注入,如果依赖注⼊有问题,那么在代码⽣成时就会抛出异常,并不会拖到运⾏时暴露,更便于我们进行debug。
3.1 安装Wire1go install github.com/google/wire/cmd/wire@latest
3.2 代码实现123456789101112131415161718func initWebServer() *gin.Engi ...
后端开发
未读HashMap的底层实现JDK1.8 之前JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashcode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突
所谓扰动函数指的就是 HashMap 的 hash 方法
使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞
JDK 1.7 HashMap 的 hash 方法源码:
12345678static int hash(int h) { // This function ensures that hashCodes that differ only by // constant multiples at each bit posit ...
HashMap和常用集合类的区别HashMap 和 HashTable 的区别
线程是否安全: HashMap 是非线程安全的,HashTable 是线程安全的,因为 HashTable 内部的方法基本都经过synchronized 修饰。(如果要保证线程安全的话推荐使用 ConcurrentHashMap )
效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点,HashTable 基本被淘汰,尽量不要在代码中使用它
对 Null key 和 Null value 的支持: HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个,HashTable 不允许有 null 键和 null 值,否则会抛出NullPointerException
初始容量大小和每次扩充容量大小的不同:
创建时如果不指定容量初始值,HashTable 默认的初始大小为 11,之后每次扩充,容量变为原来的 2n + 1,HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍
创建时如果给定了 ...
后端开发
未读Java 多线程什么是并发和并行
并发:同一时刻多个指令在单个 CPU 上交替执行
并行:同一时刻多个指令在多个 CPU 上同时执行
线程实现方式Thread 实现通过将类继承 Thread 类,并重写 Run 方法
优点:实现简单,可以直接使用Thread 类中的方法
缺点:可扩展性差,不能继承其他的类
123456789101112131415161718class ExtendThread extends Thread { @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(getName() + " : " + "ExtendThread-Thread"); } super.run(); }}private static void runExtendThread() { ...
Scala 模式匹配模式匹配简单示例1234567891011121314val oper: Char = '+'val n1: Int = 20val n2: Int = 10var res: Int = 0oper match { case '+' => res = n1 + n2 case '-' => res = n1 - n2 case '*' => res = n1 * n2 case '/' => res = n1 / n2 case _ => println("oper error")}println("res:\t" + res)
说明:
1. match 和 case 是 scala 中模式匹配的关键字
1. 如果匹配成功,执行 => 后的代码块
1. 匹配顺序是从上到下的,匹配到就执行对应的代码
1. => 还没的代码块不需要写 break ,会自动退出 ...
偏函数(partial function)这里通过一个例子来了解一下什么是偏函数
需求:将一个 Any 类型的列表中的数字+1,非数字忽略
123456789val list: List[Any] = List(1, 2, 3, 4, "hello")list// 过滤 Int 类型之外的类型.filter(_.isInstanceOf[Int])// 将 Any 类型转为 Int 类型.map(_.asInstanceOf[Int])// 数字+1.map(_ + 1)
这里虽然解决了问题,但是太过于麻烦了
这里还可以通过模式匹配的方法去解决
1234list.map { case x: Int => x + 1 case _ =>}
虽然使用模式匹配比较简洁,但还是不够完美,这里我们就要通过偏函数去达到更加简洁方便的去解决这个问题
那么什么是偏函数呢?
在对符合某个条件时,而不是所有情况进行逻辑操作时,使用偏函数是个不错的选择
将包括在大括号内的一组 case 语句封装为函数,称之为偏函数,它只会对作用于指定类型的参数或者指定 ...
高阶函数(high-order function) 及 函数柯里化能够接收函数作为参数的函数,叫做高阶函数(high-order function)
可以使应用程序更加健壮
123456789def highFunc(f: Double => Double, num: Double): Unit = { f(num)}def sum(num: Double): Double = { num + num}highFunc(sum,6.0)
高阶函数可以接收多个函数作为参数
高阶函数可以返回一个函数
1234567def minusxy(x: Int) = { // 匿名函数 (y: Int) => x - y}// 输出结果是 8 - 5 = 3println(minusxy(8)(5))
说明:
minusxy 是高阶函数,返回了一个匿名函数
返回的匿名函数 (y: Int) => x - y
返回的匿名函数可以使用变量接收
闭包(closure)闭包就是一个函数和与其相关的引用环境组合的一个整体 ...
Scala泛型泛型的意思是 泛指某种具体的数据类型,在 Scala 中泛型用 [数据类型] 表示。
泛型方法通过getMiddleElement方法获取任意数据类型的数组中的中间元素
123def getMiddleElement[T](array: Array[T]): T = { array(array.length / 2)}
泛型类定义一个Pair泛型类,这个类中包含两个字段且字段类型不固定
1class Pair[T](var x: T, var y: T)
泛型特质Loggers是一个泛型特质,ConsoleLogger继承了Loggers,并重写了其 x 字段和 show 方法
1234567891011trait Logger[T] { val x: T def show(y: T)}object ConsoleLogger extends Logger[String] { override val x: String = "log" override def show(y: String) ...
Scala Actor 并发编程模型 Actor并发编程模型,是 Scala 提供的一直与 Java 完全不一样的并发编程模型,是一直基于事件模型的并发机制。Actor并发编程模型是一种不共享数据,依赖消息传递的并发编程模型,有效避免了资源争夺、死锁等现象。
Actor是一种基于事件(消息)的并发编程模型,不共享数据,有效避免了共享数据加锁问题。
Java并发编程对比 Actor 并发编程模型
Java并发编程
Actor 并发编程模型
共享数据锁模型(share data and lock)
share nothing
每个 object 都有一个monitor,用来监视对共享数据的访问
不共享数据,Actor直接通过Message通讯
加锁代码使用synchronized标识
死锁问题
每个Actor内部是顺序执行的
每个线程内部是顺序执行的
每个Actor内部是顺序执行的
Scala 在 2.11 及之后的版本中加入了Akka并发编程框架,Actor并发编程模型已经被废弃了。
创建 Actor可以通过类(Class)或者单例对象(O ...
通过 Akka 构建简单的 Spark 通信框架实现思路:
构建Master、Worker阶段
构建 Master ActorSystem、 Actor
构建 Worker ActorSystem、 Actor
Worker注册阶段
Worker进行向Master注册(将自己的ID、CPU 核数、内存大小(MB)发送给 Master)
Worke定时发送心跳阶段
Worke定期向Master发送心跳消息
Master定时心跳检测阶段
Master定期检测Worker心跳,将一些超时的Worker移除,并对Worker按照内存进行倒序排列
多个Worker测试阶段
启动多个Worker,查看是否能注册成功,并停止某个Worker查看是否能正常移除