Java字节码结构
我们都知道java实现跨平台靠的是虚拟机技术,将源文件编译成与操作系统无关的,只有虚拟机能识别并执行的字节码文件,由各个操作系统上的jvm来负责执行,屏蔽了底层具体的操作系统。这里我们就来认识一下这个只有jvm才认识的字节码文件的真实样子。 为了节省空间,类文件中没有任何分隔符,各个数据项都是一个挨着一个紧凑排列的,所以其中无论是顺序还是数量等都是严格规定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变。下面我们先看一下类文件的整体结构: Class文件结构 其中常量、接口、字段、方法和属性在其中按各自的结构紧密排列,个数由其前面的数量字段决定。同时类文件中最小单位为1个字节,超过一个字节的数据以大端方式存储。 下面依次介绍其中的每个部分: 魔数 魔数是用来确定文件的类型是否是class文件,因为只靠文件扩展名来确定文件类型并不可靠。 这个魔数占文件的开始4个字节,为CA FE BA BE。(注意:这里的字面代表的是十六进制数,而不是ASCII码) 版本号 接下来的4个字节为class文件版本号,其中前两个字节表示的是次版本号,后两个字节表示的是主版本号(从4...
Spring 事件及异步方法使用
Spring 不仅为我们提供了IOC , AOP功能外,还在这个基础上提供了许多的功能,我们用的最多的可能就是 Spring MVC了吧,但是让我们来看下spring-context包,其中包含了缓存、调度、校验功能等等 这里主要想介绍一下Spring提供的观察者模式实现(事件发布监听)及异步方法执行,这些功能也都是基于AOP实现的 Spring 事件 观察者模式大家都了解,它可以解耦各个功能,但是自己实现的话比较麻烦,Spring为我们提供了一种事件发布机制,可以按需要发布事件,之后由监听此事件的类或方法来执行各自对应的功能,代码互相不影响,以后修改订单后续的逻辑时不会影响到订单创建,有点类似于使用MQ的感觉~ 比如在配置中心apollo项目中,在portal创建了app后会发送app创建事件,监听此事件的逻辑处将此消息同步到各个环境的adminsevice中,大家有兴趣可以看下相关代码 现在我们来看看具体如何使用:假设一个下单场景,订单创建成功后可能有一些后续逻辑要处理,但是和创建订单本身没有关系,此时就可以在创建订单完成后,发送一个消息,又相应部分的代码进行监听处理,避...
Spring AOP 使用及浅析
看过了前面的Spring Beans相关的 IOC 功能, 接下来我们来看看 AOP 是如何实现的 我们都知道 AOP 是通过动态代理来实现的, 但是代理这一步是如何实现的呢? 其实就是之前提到过的, 在Spring Bean的创建过程中, 实现BeanPostProcessor的接口可以对创建好的Bean进行修改替换等操作 123456789protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) { invokeAwareMethods(beanName, bean); Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); // 依次执行beanFactory中所有实现BeanPostProcessor的后置方法...
流计算-Flink笔记
一种被设计来处理无穷数据集的数据处理系统引擎 对实时产生的数据进行实时统计分析 电商大促时,统计当前下单量、金额 实时统计 App 中的埋点数据等 流计算相比批处理需要切分为窗口才能进行分组聚合处理 同时需要解决如下两个问题 正确性/完整性 exactly-once 处理无序、延迟数据的能力 Flink对流计算提供的支持 同时支持高吞吐、低延迟、高性能(spark支持高吞吐和高性能,strom支持低延迟高性能) 支持事件时间概念 支持有状态的计算 支持高度灵活的窗口 基于轻量级分布式快照实现容错 基于JVM实现独立的内存管理 save point(保存点) 流计算的流程 窗口 在处理无限流数据时, 如果需要对数据进行分组聚合操作,实时获取结果时, 则需要将数据分段到不同的窗口中,分别进行计算输出 窗口可分为 滚动窗口(时间驱动、数量驱动) 有固定间隔相等的连续窗口,每个窗口不会重复, 如每5分钟统计一次或每5个数据计算一次 滑动窗口(时间驱动、数量驱动) 有固定间隔相等的连续窗口,每个窗口之间可能有重叠,如每5分钟,统计前20分钟数据 ...
Dubbo扩展点加载使用简述
扩展点加载机制主要是为了实现接口和实现的解耦,接口的具体实现并不在代码中指定,而是通过通过外部配置实现,Dubbo的扩展点加载是对JDK的SPI扩展点加强而来,大家如果不了解JDK的SPI也没有关系,这里我们主要来看一下Dubbo的实现 在Dubbo的实现中,主要有三个注解,@SPI、@Adaptive和@Activate,下面我们来结合例子分别看一下它们的使用 首先我们来定义一个接口和几个对应的实现 123456// @SPI注解表示这是一个扩展点,可以有不同的实现// 指定实现时,其中的名字需要与配置文件中的key相同@SPI("simple")public interface DemoService { String echo(URL url, String s);} 123456public class SimpleServiceImpl implements DemoService { @Override public String echo(URL url, String s) { ...
自定义扩展线程池
线程池的基本使用 Executors框架提供的创建线程池的方法 123456// 固定线程数量的线程池Executors.newFixedThreadPool(5);// 对于添加的任务,如果有线程可用则使用其执行,否则就创建新线程Executors.newCachedThreadPool();// 创建只有一个线程的线程池Executors.newSingleThreadExecutor(); 它们内部实现都是使用了ThreadPoolExecutor,平时使用时我们最好是直接使用ThreadPoolExecutor,根据实际情况提供如下7个参数对线程池进行定义使用 配置参数 1234567int corePoolSize, // 核心线程数int maximumPoolSize, // 最大线程数long keepAliveTime, // 超出核心数线程的最大空闲存活时间TimeUnit unit, // 空闲存活时间的...
状态模式笔记
在介绍状态模式之前,我们先看个简单的例子 比如我们正常的网上购物的订单,对于订单它有许多个不同的状态,在不同状态下会有不同的行为能力,如状态有待支付、已支付待发货、待收货、订单完成等等,在整个订单流转过程中,由不同的事件行为导致它状态的变更,可以看下它简单的状态图 这些状态虽然不同,但是都是属于订单的状态,对应的行为也是订单的行为,在编码的过程中,一种写法是将这些行为(方法)都写到订单这个类或者类似OrderService这种类中,如 1234567891011121314151617public class OrderService { private OrderDao orderDao; public void pay(Long orderId) { Order order = orderDao.findById(orderId); // 下面逻辑也可以改成使用switch if (order.getStatus() == OrderStatus.WAIT_PAY) { ...
Drools入门使用
Drools是一款基于Java语言的开源规则引擎,通过drools特定的语法,将复杂多变的业务规则统一管理。 环境配置 一、使用maven创建项目 添加相关依赖,pom.xml如下 123456789101112131415161718192021222324<?xml version="1.0" encoding="UTF-8"?><project ...> <packaging>kjar</packaging> <dependencies> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>7.27.0.Final</version> </depend...
Redis内存优化小技巧
在Redis中,相同的数据,如果我们使用不同的数据结构来存储,它们使用的内存大小差异可能是非常大的,要想更多的节省空间,我们不仅仅需要了解Redis的几种常用数据类型,还需要了解他们内部在不同情况下使用的具体数据结构 之前曾整理过一篇Redis每种数据类型及对应的内部结构,如果对此不太了解的同学可以先大致看一下 压缩数据结构 Redis为hash、set、zset都提供了对应的节约空间的数据结构存储方式,合理使用它们可以大大节约内存空间 下面以hash结构举例,其他的结构也是类似的 hash内部有两种结构 hashtable -哈希表 这是我们比较熟悉的一种结构,内部使用数组与链表结合,正常使用数组,如果遇到冲突则使用链表 查找迅速但是比较占用空间 ziplist - 压缩列表 使用条件: 键和值的长度都不能超过64字节(可通过 hash-max-ziplist-value配置) 键值对数量小于512个(可通过 hash-max-ziplist-entries配置) ziplist的使用条件虽然苛刻了一些,但是如果满足条件后,则可以节省很多的空间 它内部使用的是一段连续内存...
Redis服务端-客户端通信协议
了解Redis通信内容 Redis我们都比较熟悉,可以用来做缓存、分布式锁等,但是,其中的客户端与服务端是如何进行通信的呢? 我们可以分别模拟一个服务端或者客户端,打印查看来自实际连接的请求来获取它们的通信方式 首先,让我们先使用先模拟一个服务端,使用Jedis进行连接查看 1234567891011121314// 一个简单的demopublic class MockRedisServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(6379); Socket socket = serverSocket.accept(); try (InputStream inputStream = socket.getInputStream(); final OutputStream outputStream = socket.getO...
