mghio

Java 搬运工 & 终身学习者


  • 首页

  • 标签

  • 分类

  • 归档

  • 关于

  • 搜索

服务发现组件之 — Eureka

发表于 2020-03-14 | 分类于 Java , 服务发现 , Eureka |
字数统计: 2.7k 字 | 阅读时长 ≈ 9 分钟

前言

现在流行的微服务体系结构正在改变我们构建应用程序的方式,从单一的单体服务转变为越来越小的可单独部署的服务(称为微服务),共同构成了我们的应用程序。当进行一个业务时不可避免就会存在多个服务之间调用,假如一个服务 A 要访问在另一台服务器部署的服务 B,那么前提是服务 A 要知道服务 B 所在机器的 IP 地址和服务对应的端口,最简单的方式就是让服务 A 自己去维护一份服务 B 的配置(包含 IP 地址和端口等信息),但是这种方式有几个明显的缺点:随着我们调用服务数量的增加,配置文件该如何维护;缺乏灵活性,如果服务 B 改变 IP 地址或者端口,服务 A 也要修改相应的文件配置;还有一个就是进行服务的动态扩容或缩小不方便。
一个比较好的解决方案就是 服务发现(Service Discovery)。它抽象出来了一个注册中心,当一个新的服务上线时,它会将自己的 IP 和端口注册到注册中心去,会对注册的服务进行定期的心跳检测,当发现服务状态异常时将其从注册中心剔除下线。服务 A 只要从注册中心中获取服务 B 的信息即可,即使当服务 B 的 IP 或者端口变更了,服务 A 也无需修改,从一定程度上解耦了服务。服务发现目前业界有很多开源的实现,比如 apache 的 zookeeper、 Netflix 的 eureka、hashicorp 的 consul、 CoreOS 的 etcd。

阅读全文 »

2020 年 JVM 生态报告解读

发表于 2020-03-04 | 分类于 Java , JVM |
字数统计: 1.7k 字 | 阅读时长 ≈ 6 分钟

前言

做过 Java 开发的同学都知道,JVM(Java 虚拟机) 是 Java 实现的基础,虽然在平时工作中真正运用到的时候可能并不多,但是一个程序员想要上升到高级层次,那就必须知道 Java 到底是怎么运行的,这就有必要去学习了解 JVM 的相关知识了。学习 JVM 可以能更深入的理解 Java 这门语言,可以清楚知道Java程序是如何执行的以及为未来排查线上问题打下坚实的基础。接下来我们看看 2020 年的 JVM 生态报告和最新趋势,值得我们每个 Java 开发者去关注了解。

JDK 厂商占比

Oracle JDK 和 Open JDK 加起来占比将近 60%,其中 Oracle JDK 占比略多一些,Oracle JDK 和 Open JDK 都是市场上的热门选择,我们看看二者之间的一些差异。Oracle JDK 更多的关注稳定性,更适合企业级用户,而 Open JDK 相对而言没有那么稳定,它会经常发布一些新特性。Oracle JDK 支持长期发布的更改,而 Open JDK 仅支持计划和完成下一个发行版,还有一个就是 Oracle JDK 是根据 二进制代码许可协议 获得许可,而 Open JDK 是根据 GPL v2 许可获得许可。使用 Oracle 平台时会产生一些许可影响。如 Oracle 宣布的那样,在没有商业许可的情况下,在 2019 年 1 月之后发布的 Oracle Java SE 8 的公开更新将无法用于商业,商业或生产用途。但是,Open JDK 是完全开源的,可以自由使用。

阅读全文 »

分布式系统之 — CAP 定理

发表于 2020-02-29 | 分类于 分布式系统 , CAP定理 |
字数统计: 2.1k 字 | 阅读时长 ≈ 7 分钟

前言

在互联网时代,我们的应用都是分布式系统,部署在 N 台机器上。说到分布式系统我们就不得不说分布式系统的祖先——集中式系统。它和分布式系统是两个完全相反的概念,集中式系统就是把所有的程序和功能都放到一台主机上,从而对外提供服务。集中式系统的优点就是容易理解、维护方便,它的的弊端也很明显,如果这个主机出故障了那么整个系统就崩溃了。著名投资家巴菲特有个关于投资的名言:

不要把鸡蛋放在一个篮子里

对于我们的系统而言也是如此,我们不可能保证主机永远不坏、也无法保证自己的程序永远不会出 bug,所以问题是无法避免的,我们只能把“鸡蛋”分散到不同的“篮子”里,降低系统出故障的风险,这就是我们为什么需要分布式系统的原因之一。使用分布式系统的另一个理由就是扩展性,毕竟单台主机都会有性能的极限,分布式系统可以通过增加主机数量来实现横向水平性能的扩展。接下来我们看看分布式系统中的一个基本定理——CAP定理。

阅读全文 »

IDEA 最新版(2019.3)激活教程

发表于 2020-01-12 | 分类于 Java , IDEA , 工具 |
字数统计: 829 字 | 阅读时长 ≈ 3 分钟

前言

相信做 Java 开发的朋友们绝大部分人应该都是用 IntelliJ IDEA 作为开发工具,没用过的朋友们建议将你的开发工具换成这个,关于它的优点可以去 Google 一下,我之前都是用 Eclipse 作为开发工具,自从用过一次 IDEA 之后就再也回不去了。。。今天早上更新(作死)了一下 IDEA 到最新版(2019.3.1),安装完毕之后进入就提示说之前的激活码失效了,经过一顿搜索之后终于成功激活了,在此记录一下激活过程。

start_welcome.png

阅读全文 »

Java 反射机制(二)

发表于 2020-01-04 | 分类于 Java , 反射 |
字数统计: 2.6k 字 | 阅读时长 ≈ 10 分钟

前言

在上篇 Java 反射机制(一) 介绍了一些 Java 反射相关的常用 API ,在知道了如何去使用反射之后,作为一个合格的工程师,下一步肯定是要去了解它的如何实现的,我们今天就来看看在 JDK 源码中是如何去实现反射的(PS:以下源码分析基于 JDK1.8)。

Field 类 set 方法的实现

Field 类的 set 方法是在运行时用来动态修改一个类的属性的值,进入到 Field 类的 set 方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}

首先根据 override 判断是否需要检查字段的访问权限,然后通过 getFieldAccessor 方法获得一个 FieldAccessor 字段访问者对象,最后调用的是 FieldAccessor 类的 set 方法进行下一步操作的,FieldAccessor 是一个接口,定义了对字段的一些操作,该接口有如下一些实现类:

阅读全文 »

Java 反射机制(一)

发表于 2019-12-29 | 分类于 Java , 反射 |
字数统计: 3.6k 字 | 阅读时长 ≈ 15 分钟

前言

在 Java 中有两种方式可以让我们在运行时识别对象和类的信息。一种是 RTTI(运行时类型识别:Run-Time Type Identification),它假定了我们在编译时已经知道了所有的类型;另一种是我们本文要说的反射机制,它允许我们在运行时获取和使用类的信息。无论是 RTTI 还是反射,其本质都是一样的,都是去动态的获取类的信息。它们唯一不同的是,RTTI 在编译时期知道要解析的类型,而反射是在运行时才知道要解析的类型。

反射概述

反射就是把 Java 类中的各个部分(属性、方法、构造方法等)映射成一个个对象。Class 类与 java.lang.reflect 类库一起对反射的概念提供了支持,类库中包含了 Field、Method 及 Constructor 类,每个类都实现了 Member 接口。这些类型的对象都是由 JVM 运行时创建的,用来表示未知类里对应的成员。这样我们就可以使用 Constructor 创建新的对象,用 get 和 set 方法读取和修改类中与 Field 对象关联的字段,用 invoke 方法调用类中与 Method 对象关联的方法等。
Java 反射机制是在运行状态中的,对于任意一个类我们可以通过反射获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。重要的是,要认识到反射机制并没有什么特别之处,当我们通过反射和一个未知类型的对象打交道时,JVM 只是简单的对这个对象做检查,看它属于哪个类,在用它做其它事情之前必须先加载那个类 Class 对象。所以那个类的字节码文件对象对于 JVM 来说必须是可获取的,要么在本地机器上,要么通过网络获取。

阅读全文 »

Linux 常用命令

发表于 2019-12-21 | 分类于 Linux笔记 |
字数统计: 4.5k 字 | 阅读时长 ≈ 17 分钟

1.1 前言

作为 Java 后端开发的我们,开发的项目绝大部分都是部署在 Linux 系统上的,因此熟练使用一些常用的 Linux 命令不管是对于日常开发、服务部署或者查找问题都非常有用。以下整理了一些常用的 Linux 常用命令。

1.2 文件管理

1.2.1 ls 命令

ls 命令是 Linux 最常用的命令之一,其功能是列出指定目录下的内容及其相关属性信息。默认状态下,ls 命令会列出当前目录的内容,它也可以带上一些参数来实现更多的功能。
语法格式:ls [选项] [文件]
常用参数

参数 描述
-a 显示所有文件及目录(包括以 . 开头的隐藏文件)
-l 使用长格式列出文件及目录
-r 将文件以相反次序显示(默认按照英文字母次序)
-t 根据最后的修改时间排序
-A 同 -a,但是不列出 .(当前目录)以及 ..(父级目录)
-S 根据文件大小排序
-R 递归列出所有子目录
阅读全文 »

Java 多线程基础(二)

发表于 2019-12-14 | 分类于 Java , 多线程 |
字数统计: 2.3k 字 | 阅读时长 ≈ 10 分钟

简介

在上篇 Java 多线程基础(一) 我们提到了一些线程的常用方法,这篇我们具体看看其中一些方法的使用以及方法的区别,让我们在工作中更好的使用。

wait 方法与 notify 方法

在 Object 类中定义了 wait 方法和 notify 方法,wait 方法的作用是让当前线程进入等待状态,将当前线程置入 预执行队列,会在 wait 方法所在代码处停止执行,直到被通知或者被中断,在调用 wait 方法之前,线程必须获取该对象的锁,因此只能在同步方法或者同步代码块中调用 wait 方法,并且该方法会释放当前线程锁持有的锁。notify 方法是唤醒在当前对象上等待的单个线程,如果有多个线程等待,那么线程调度器会挑出一个 wait 的线程,对其发出 notify ,并使它等待获取该对象的对象锁,这意味着,即使收到了通知,线程也不会立即获取到对象锁,必须等待 notify 方法的线程释放锁才可以。和 wait 方法一样,notify 方法也只能在同步方法或者同步代码块中调用。它还有个相似的方法 notifyAll,它的作用是唤醒在当前对象上等待的所有线程。

阅读全文 »

Java 多线程基础(一)

发表于 2019-12-07 | 分类于 Java , 多线程 |
字数统计: 3.3k 字 | 阅读时长 ≈ 12 分钟

简介

在接触多线程之前,在我们程序中在任意时刻都只能执行一个步骤,称之为单线程。在单线程开发的程序中所有的程序路径都是顺序执行的,前面的必须先执行,后面的才会执行。单线程的优点也很明显,相对于多线程来说更加稳定、扩展性更强、程序开发相对比较容易。但是由于每次都要等上一个任务执行完成后才能开始新的任务,导致其效率比多线程低,甚至有时候应用程序会出现假死的现象。使用多线程有利于充分发挥多处理器的功能。通过创建多线程进程,每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。多线程是 Java 学习的非常重要的方面,是每个 Java 程序员必须掌握的基本技能。本文是有关 Java 多线程的一些基础知识总结。

进程与线程的区别

进程

进程是操作系统资源分配的基本单位,它是操作系统的基础,是一个程序及其数据在处理机上顺序执行时所发生的活动。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。进程的实质就是程序在操作系统中的一次执行过程,它是动态产生的、动态销毁的,拥有自己的生命周期和各种不同的运行状态。同时,进程还具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进(PS:并发性和并行性是不同的概念,并行指的是同一时刻,两个及两个以上的指令在多个处理器上同时执行。而并发指的是同一时刻只有一条指令执行,但是多个进程可以被 CPU 快速交换执行,给我们感觉好像是多个执行在同时执行一样)。 

线程

线程是任务调度和执行的基本单位,也被称为轻量级进程,线程由线程 ID,当前指令指针(PC),寄存器集合和堆栈组成。线程不拥有系统资源,它只会拥有一点儿在运行时必不可少的资源,但是它可以与同属于同一进程的线程共享该进程所拥有的所有资源。一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

阅读全文 »

Java 线程池(二)

发表于 2019-11-30 | 分类于 Java , 线程池 |
字数统计: 4.3k 字 | 阅读时长 ≈ 16 分钟

简介

在上篇 Java 线程池(一) 我们介绍了线程池中一些的重要参数和具体含义,这篇我们看一看在 Java 中是如何去实现线程池的,要想用好线程池,只知其然是远远不够的,我们需要深入实现源码去了解线程池的具体实现细节,这样才能更好的使用到我们的工作中,当出现问题时能快速找到问题根源所在。

线程池如何处理提交的任务

我们向线程池提交任务有两种方式,分别是通过 submit 方法提交和通过 execute 方法提交,这两种方式的区别为 execute 只能提交 Runnable 类型的任务并且没有返回值,而 submit 既能提交 Runnable 类型的任务也能提交 Callable(JDK 1.5+)类型的任务并且会有一个类型 Future 的返回值,我们知道 Runnable 是没有返回值的,所以只有当提交 Callable 类型的任务时才会有返回值,而提交 Runnable 的返回值是 null。 execute 执行任务时,如果此时遇到异常会直接抛出,而 submit 不会直接抛出,只有在使用 Future 的 get 方法获取任务的返回结果时,才会抛出异常。
通过查看 ThreadPoolExecutor 的源码我们发现,其 submit 方法是继承自其抽象父类 AbstractExecutorService 而来的,有三个重载的方法,分别可以提交 Runnable 类型和 Callable 类型的任务。无论是哪个 submit 方法最终还是调用了 execute 方法来实现的。方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
阅读全文 »
1…456
mghio

mghio

58 日志
63 分类
57 标签
RSS
GitHub 思否 简书 掘金 E-Mail 博客园
友情链接
  • 气象万千
  • 淡白记忆博客
  • Junhua's blog
  • IT运维狗
  • Z
  • 13blog
  • 黄泽彬个人站
  • 荷戟独彷徨
  • Java学习之道
  • 宇宙湾
  • Morcat Blog
  • Jason
© 2019 — 2025 mghio
湘 ICP 备 2021001218 号-1 · 湘公网安备 43312302000074
本网站由提供 CDN 加速服务
访客数 人 总访问量 次