一文搞懂 Spring Bean 的生命周期
一. 前言在学习Spring框架的IOC、AOP两大功能之前,首先需要了解这两个技术的基础——Bean。在Spring框架中,Bean无处不在,IOC容器管理的对象就是各种各样的Bean。理解Bean的生命周期有助于我们更好的理解和使用Spring框架的IOC功能,也有助于我们理解框架如何初始化、使用和管理Bean。接下来我们通过代码实现观察 BeanFactory 与 ApplicationContext 中bean的生命周期。
二. BeanFactory中Bean的生命周期Bean 的生命周期概括起来就是 4 个阶段:
实例化(Instantiation)
属性赋值(Populate)
初始化(Initialization)
销毁(Destruction)
在四个阶段中,Spring框架会向外暴露多个扩展点,此时业务代码可以根据情况,从不同的扩展点切入影响Bean的默认创建行为。
其中橙色和绿色的是容器级别生命周期接口,也就是所有的Bean初始化时都会发生作用。主要包含两个接口InstantiationAwareBeanPostProcessor、BeanPostProc ...
布隆过滤器在缓存系统中的实践
一. 背景在业务开发中,如果遇到并发量很高的情况下,通常会使用缓存对系统查询性能进行优化,在缓存命中率很高的情况下,缓存的使用能够大幅提升系统查询性能。但是在缓存命中率非常低场景下,如果采用传统缓存读取模式,大部分的请求会穿透至数据库,造成数据库的巨大压力。
例如:最近上线一个“贵族”功能,由于贵族价格比较贵,拥有比较强的特权,该功能也主要面向平台头部大R用户,所以如果采用传统的缓存模式,查询一个用户的贵族信息就会大概率出现缓存无法命中去读库的情况。
有些同学可能会将“空结果”缓存至数据库,这样下次去查询该用户的结果时就会命中缓存。但是由于平台巨大的用户量,如果将所有用户的空结果进行缓存成本是非常高的。
此种场景就非常适合使用布隆过滤器去解决缓存命中率低的问题。
二. 什么是布隆过滤器本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的, ...
开发中你不得不知的一个Git小技巧
一. 背景在工作中大家应会碰到需要频繁在两个分支中切换工作的情况,我们通常做法是利用git stash命令暂存当前工作区中的变更,然后git checkout到目标分支中工作,工作完成后回到刚刚分支使用git stash pop命令还原历史工作区变动。
整体流程大致如下:
12345678910111213141516171819202122232425262728293031323334# 当前工作分支,存在变更$ worktree-test (dev1) git statusOn branch testChanges not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: bbb.txtno changes added to ...
tcc-transaction源码详解
本文主要介绍TCC的原理,以及从代码的角度上分析如何实现的;不涉及具体使用示例。本文通过分析tcc-transaction源码带大家了解TCC分布式事务的实现原理。
需要注意的是,本文所有代码都基于master-1.7.x分支,不同版本的源码会存在一定的差异。完整代码注释请参考:bigcoder84/tcc-transaction
一. 概述1.1 项目模块本文对 tcc-transaction 源码分析。主要涉及如下四个模块:
tcc-transaction-core:tcc-transaction 底层实现。
tcc-transaction-api:tcc-transaction 使用 API。
tcc-transaction-spring:tcc-transaction 对 Spring 的支持。
tcc-transaction-dubbo:tcc-transaction 对 Dubbo 的支持。
本文基于tcc-transaction 1.7.x版本源码进行分析。
1.2 tcc-transaction中的概念在详细分析框架源码之前,我们先熟悉 tcc-trans ...
详解进程Fork
一. fork函数详解一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
我们来看一个例子:
12345678910111213141516171819#include <unistd.h>#include <stdio.h>int main() { pid_t fpid; //fpid表示fork函数返回的值 int count = 0; fpid = fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am ...
深入理解Docker容器技术
本文参考转载至:《深入剖析Kubernetes - 张磊》
容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界”。对于 Docker 等大多数 Linux 容器来说,Cgroups 技术是用来制造约束的主要手段,而Namespace 技术则是用来修改进程视图的主要方法。你可能会觉得 Cgroups 和 Namespace 这两个概念很抽象,别担心,接下来我们一起动手实践一下,你就很容易理解这两项技术了。
一. Namespace假设你已经有了一个 Linux 操作系统上的 Docker 项目在运行,比如我的环境是 Ubuntu 16.04和 Docker CE 18.05。
接下来,让我们首先创建一个容器来试试。
12$ docker run -it busybox /bin/sh/ #
这个命令是 Docker 项目最重要的一个操作,即大名鼎鼎的 docker run。而 -it 参数告诉了 Docker 项目在启动容器后,需要给我们分配一个文本输入 / 输出环境,也就是 TTY,跟容器的标准输入相关联,这样我们就可以和这个 Docker ...
synchronized锁升级过程
JDK 1.6后锁的状态总共有四种,级别由低到高依次为:无锁、偏向锁、轻量级锁、重量级锁,这四种锁状态分别代表什么,为什么会有锁升级?
其实在 JDK 1.6之前,synchronized 还是一个重量级锁,底层使用操作系统的 Mutex Lock(互斥锁)实现,而操作系统实现线程之间的切换需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么重量级锁效率低的原因。
但是在JDK 1.6后,JVM为了提高锁的获取与释放效率对(synchronized )进行了优化,引入了 偏向锁 和 轻量级锁 ,从此以后锁的状态就有了四种(无锁、偏向锁、轻量级锁、重量级锁),并且四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,也就是说只能进行锁升级(从低级别到高级别),不能锁降级(高级别到低级别),这种设计目的是为了提高获得锁和释放锁的效率。
一. 对象的内存布局要弄清楚加锁过程到底发生了什么需要看一下对象创建之后再内存中的布局是个什么样的?
一个对象在new出来之后在内存中主要分为4个部分:
markword:默认存储对象的HashCode,分代年龄和锁标 ...
记一次线上内存泄露排查
一. 排查过程前不久测试环境一直无缘无故的挂掉,这可苦了我们一线开发人员,每次测试都得把挂掉服务全部起起来。面对几十个微服务模块,我想大家看到这样的场景内心也是一万个草泥马飞过….
硬着头皮把代码写完了,但是大规模的服务宕机显然不正常,看了一波还是热乎的日志,发现是服务器OOM了,顺道看了一下JVM配置,居然没有任何配置,看到这里嘴角丝丝上扬,觉得自己破案了。
随即给核心服务都加上了JVM参数:
1JAVA_OPTS: "-server -Xmx256m" #因为是测试环境对扩容抖动并不敏感,所以没有设置Xms,这样可以节省一点测试环境资源
改完配置,我觉的自己头不疼了,自己又行了。
第二天上班发现,测试环境还是挂了
带着满脸的问号,看了一波日志,结果还是OOM,但是挂的服务明显变少了。这一波我开始怀疑是不是测试环境应用内存给的确实太少了(线上是1GB),我把堆内存改成了512M:
1JAVA_OPTS: "-server -Xmx512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/h ...
探寻Dubbo集群容错机制
一. timeout 与 retriesDubbo的服务可以通过timeout配置超时时间,防止远程调用失败,该属性的默认值为1000(ms),用户可以在多个地方配置服务的超时时间:
图中涉及的配置方式从上至下优先级越来越低,总体来说配置覆盖遵循以下规律:consumer配置优先于provider配置,细粒度配置优先于整体配置。
我们在消费者中sleep一段时间人为制造超时效果:
123456789101112131415161718@DubboService(timeout = 3000)@Slf4jpublic class UserServiceImpl implements IUserService{ @Override public UserDTO queryById(Integer userId) { if (userId == null) { throw new RuntimeException("参数不能为空"); } log.info(&q ...
使用OpenVPN搭建虚拟专用网
一. 初衷先说说自己搭建VPN的初衷,作为一个社畜在上海栖息之地是一间合租的卧室,房间虽小也抑制不住自己爱折腾的毛病,前不久自己在网上淘了一个M72主机,这个主机挺适合在家里当一个服务器,主要是因为它是I3处理功耗相对较低还是X86架构,相比用树莓派当服务器,不仅算力更强软件兼容性以及硬件可扩展性也更好。
因为日常开发学习过程中不免需要安装一些中间件应用,阿里云上可怜的2G内存显然是不允许我这样的操作(主要是财力不足)。没办法我只能将大部分应用部署在家庭内网服务器上。我给M72设置了一个固定的局域网IP,平常在家连接服务器会非常方便,但是一旦遇到外出的情况,家庭内网的服务器就完全访问不到了。
问题总归是要解决的,在Google上遨游了一番决定搭建一个内网穿透服务器,将家庭服务器的端口映射到公网服务器的某一个端口上。只要我访问公网服务器的这个端口,公网服务器就会把数据包转发到内网服务器上来。
网上的内网穿透方案非常多(frp,ngrok),最终选择了带WEB界面的 NPS,内网穿透的基本效果如下(至于内网穿透如何解决NAT网络模式下无法直接请求内网服务器的问题我们抽时间再谈):
配置 ...