|
|
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width"><meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.2.0"><link rel="preconnect" href="https://fonts.googleapis.com" crossorigin><link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin><link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png"><link rel="mask-icon" href="/images/logo.svg" color="#222"><meta name="google-site-verification" content="2X6S9P7CAjXjVvw8YyQR8pCu-B0oEu7O9quLgxXuWyA"><meta name="baidu-site-verification" content="dV8JGNzi0c"><script>setTimeout(function(){var d=document.createElement("script");d.setAttribute("data-ad-client","ca-pub-7480618470784058"),d.async=!0,d.src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",document.body.appendChild(d)},5e3),window.addEventListener?window.addEventListener("load",downloadJsAtOnload,!1):window.attachEvent?window.attachEvent("onload",downloadJsAtOnload):window.onload=downloadJsAtOnload</script><link rel="stylesheet" href="/css/main.css"><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha256-DfWjNxDkM94fVBWx1H5BMMp0Zq7luBlV8QRcSES7s+0=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.css" integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin="anonymous"><script class="next-config" data-name="main" type="application/json">{"hostname":"nicksxs.me","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.12.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":false,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":true,"preload":true}}</script><script src="/js/config.js"></script><meta name="description" content="learn from zero,技术博客,Nicksxs,史学森"><meta property="og:type" content="website"><meta property="og:title" content="Nicksxs's Blog"><meta property="og:url" content="https://nicksxs.me/page/11/index.html"><meta property="og:site_name" content="Nicksxs's Blog"><meta property="og:description" content="learn from zero,技术博客,Nicksxs,史学森"><meta property="og:locale" content="zh_CN"><meta property="article:author" content="Nicksxs"><meta property="article:tag" content="Nicksxs,史学森,米方方,米方方的男朋友,森哥"><meta name="twitter:card" content="summary"><link rel="canonical" href="https://nicksxs.me/page/11/"><script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"page/11/index.html","title":""}</script><script class="next-config" data-name="calendar" type="application/json">""</script><title>Nicksxs's Blog - What hurts more, the pain of hard work or the pain of regret?</title><script async src="https://www.googletagmanager.com/gtag/js?id=UA-61358619-1"></script><script class="next-config" data-name="google_analytics" type="application/json">{"tracking_id":"UA-61358619-1","only_pageview":false}</script><script src="/js/third-party/analytics/google-analytics.js"></script><script src="/js/third-party/analytics/baidu-analytics.js"></script><script async src="https://hm.baidu.com/hm.js?20f33b3c0c0eff9b1522999c0015646d"></script><noscript><link rel="stylesheet" href="/css/noscript.css"></noscript><link rel="alternate" href="/atom.xml" title="Nicksxs's Blog" type="application/atom+xml"></head><body itemscope itemtype="http://schema.org/WebPage"><div class="headband"></div><main class="main"><header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-container"><div class="site-nav-toggle"><div class="toggle" aria-label="切换导航栏" role="button"><span class="toggle-line"></span> <span class="toggle-line"></span> <span class="toggle-line"></span></div></div><div class="site-meta"><a href="/" class="brand" rel="start"><i class="logo-line"></i><h1 class="site-title">Nicksxs's Blog</h1><i class="logo-line"></i></a><p class="site-subtitle" itemprop="description">What hurts more, the pain of hard work or the pain of regret?</p></div><div class="site-nav-right"><div class="toggle popup-trigger"><i class="fa fa-search fa-fw fa-lg"></i></div></div></div><nav class="site-nav"><ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li><li class="menu-item menu-item-top"><a href="/top/" rel="section"><i class="fa fa-th fa-fw"></i>热度</a></li><li class="menu-item menu-item-sitemap"><a href="/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>站点地图</a></li><li class="menu-item menu-item-commonweal"><a href="/404/" rel="section"><i class="fa fa-heartbeat fa-fw"></i>公益 404</a></li><li class="menu-item menu-item-search"><a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索</a></li></ul></nav><div class="search-pop-overlay"><div class="popup search-popup"><div class="search-header"><span class="search-icon"><i class="fa fa-search"></i></span><div class="search-input-container"><input autocomplete="off" autocapitalize="off" maxlength="80" placeholder="搜索..." spellcheck="false" type="search" class="search-input"></div><span class="popup-btn-close" role="button"><i class="fa fa-times-circle"></i></span></div><div class="search-result-container no-result"><div class="search-result-icon"><i class="fa fa-spinner fa-pulse fa-5x"></i></div></div></div></div></div><div class="toggle sidebar-toggle" role="button"><span class="toggle-line"></span> <span class="toggle-line"></span> <span class="toggle-line"></span></div><aside class="sidebar"><div class="sidebar-inner sidebar-overview-active"><ul class="sidebar-nav"><li class="sidebar-nav-toc">文章目录</li><li class="sidebar-nav-overview">站点概览</li></ul><div class="sidebar-panel-container"><div class="post-toc-wrap sidebar-panel"></div><div class="site-overview-wrap sidebar-panel"><div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person"><img class="site-author-image" itemprop="image" alt="Nicksxs" src="/uploads/avatar.jpg"><p class="site-author-name" itemprop="name">Nicksxs</p><div class="site-description" itemprop="description">learn from zero,技术博客,Nicksxs,史学森</div></div><div class="site-state-wrap site-overview-item animated"><nav class="site-state"><div class="site-state-item site-state-posts"><a href="/archives/"><span class="site-state-item-count">173</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"><a href="/categories/"><span class="site-state-item-count">148</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"><a href="/tags/"><span class="site-state-item-count">283</span> <span class="site-state-item-name">标签</span></a></div></nav></div><div class="links-of-author site-overview-item animated"><span class="links-of-author-item"><a href="https://github.com/nicksxs" title="GitHub → https://github.com/nicksxs" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a> </span><span class="links-of-author-item"><a href="mailto:nicksxs1202@gmail.com" title="E-Mail → mailto:nicksxs1202@gmail.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a></span></div><div class="cc-license site-overview-item animated" itemprop="license"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="https://cdnjs.cloudflare.com/ajax/libs/creativecommons-vocabulary/2020.11.3/assets/license_badges/small/by_nc_sa.svg" alt="Creative Commons"></a></div><script charset="utf-8" src="/js/tagcloud.js"></script><script charset="utf-8" src="/js/tagcanvas.js"></script><div class="widget-wrap"><div id="myCanvasContainer" class="widget tagcloud"><canvas width="250" height="250" id="resCanvas"><ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/2019/" rel="tag">2019</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/2020/" rel="tag">2020</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/2021/" rel="tag">2021</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/2PC/" rel="tag">2PC</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/360-%E5%85%A8%E5%AE%B6%E6%A1%B6/" rel="tag">360 全家桶</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/3PC/" rel="tag">3PC</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/3Sum-Closest/" rel="tag">3Sum Closest</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/AOP/" rel="tag">AOP</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Adaptive/" rel="tag">Adaptive</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Apollo/" rel="tag">Apollo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/AutoConfiguration/" rel="tag">AutoConfiguration</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Binary-Tree/" rel="tag">Binary Tree</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Broker/" rel="tag">Broker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/C/" rel="tag">C</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/C/" rel="tag">C++</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/CachedThreadPool/" rel="tag">CachedThreadPool</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Comparator/" rel="tag">Comparator</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/DFS/" rel="tag">DFS</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/DP/" rel="tag">DP</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/DefaultMQPushConsumer/" rel="tag">DefaultMQPushConsumer</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Design-Patterns/" rel="tag">Design Patterns</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Disruptor/" rel="tag">Disruptor</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Distributed-Lock/" rel="tag">Distributed Lock</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/" rel="tag">Docker</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Dockerfile/" rel="tag">Dockerfile</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Druid/" rel="tag">Druid</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Dubbo/" rel="tag">Dubbo</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/EagerThreadPool/" rel="tag">EagerThreadPool</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Evict/" rel="tag">Evict</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Filter/" rel="tag">Filter</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/First-Bad-Version/" rel="tag">First Bad Version</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/FixedThreadPool/" rel="tag">FixedThreadPool</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/G1/" rel="tag">G1</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/GC/" rel="tag">GC</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Garbage-First-Collector/" rel="tag">Garbage-First Collector</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Gogs/" rel="tag">Gogs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Homebrew/" rel="tag">Homebrew</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Inorder-Traversal/" rel="tag">Inorder Traversal</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Interceptor/" rel="tag">Interceptor</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Intersection-of-Two-Arrays/" rel="tag">Intersection of Two Arrays</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/JMap/" rel="tag">JMap</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/JPS/" rel="tag">JPS</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/JStack/" rel="tag">JStack</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/JVM/" rel="tag">JVM</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Java/" rel="tag">Java</a><span class="tag-list-count">31</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Leetcode-42/" rel="tag">Leetcode 42</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/LimitedThreadPool/" rel="tag">LimitedThreadPool</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linked-List/" rel="tag">Linked List</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Lowest-Common-Ancestor-of-a-Binary-Tree/" rel="tag">Lowest Common Ancestor of a Binary Tree</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/MQ/" rel="tag">MQ</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Mac/" rel="tag">Mac</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Maven/" rel="tag">Maven</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Median-of-Two-Sorted-Arrays/" rel="tag">Median of Two Sorted Arrays</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Mybatis/" rel="tag">Mybatis</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Mysql/" rel="tag">Mysql</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/NameServer/" rel="tag">NameServer</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/PHP/" rel="tag">PHP</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Preorder-Traversal/" rel="tag">Preorder Traversal</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Print-FooBar-Alternately/" rel="tag">Print FooBar Alternately</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/RPC/" rel="tag">RPC</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Redis/" rel="tag">Redis</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Remove-Duplicates-from-Sorted-List/" rel="tag">Remove Duplicates from Sorted List</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/RocketMQ/" rel="tag">RocketMQ</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Rotate-Image/" rel="tag">Rotate Image</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Rust/" rel="tag">Rust</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/SPI/" rel="tag">SPI</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Servlet/" rel="tag">Servlet</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Sharding-Jdbc/" rel="tag">Sharding-Jdbc</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Shift-2D-Grid/" rel="tag">Shift 2D Grid</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Singleton/" rel="tag">Singleton</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring/" rel="tag">Spring</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring-Event/" rel="tag">Spring Event</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/SpringBoot/" rel="tag">SpringBoot</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Sql%E6%B3%A8%E5%85%A5/" rel="tag">Sql注入</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Stream/" rel="tag">Stream</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Synchronized/" rel="tag">Synchronized</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Thread-dump/" rel="tag">Thread dump</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ThreadLocal/" rel="tag">ThreadLocal</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ThreadPool/" rel="tag">ThreadPool</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Tomcat/" rel="tag">Tomcat</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Trapping-Rain-Water/" rel="tag">Trapping Rain Water</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/WeakReference/" rel="tag">WeakReference</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Web/" rel="tag">Web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Webhook/" rel="tag">Webhook</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/WordPress/" rel="tag">WordPress</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aqs/" rel="tag">aqs</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/await/" rel="tag">await</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/bloom-filter/" rel="tag">bloom filter</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/c/" rel="tag">c++</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cglib/" rel="tag">cglib</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cgroup/" rel="tag">cgroup</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cluster/" rel="tag">cluster</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/condition/" rel="tag">condition</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/" rel="tag">docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dp/" rel="tag">dp</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/echo/" rel="tag">echo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/environment/" rel="tag">environment</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gap-lock/" rel="tag">gap lock</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gc/" rel="tag">gc</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/" rel="tag">git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/grep/" rel="tag">grep</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/" rel="tag">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/icu4c/" rel="tag">icu4c</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/im/" rel="tag">im</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/is-not-null/" rel="tag">is not null</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/is-null/" rel="tag">is null</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/j-u-c/" rel="tag">j.u.c</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/" rel="tag">java</a><span class="tag-list-count">30</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jvm/" rel="tag">jvm</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/leetcode/" rel="tag">leetcode</a><span class="tag-list-count">37</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/leetcode-155/" rel="tag">leetcode 155</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linked-list/" rel="tag">linked list</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/" rel="tag">linux</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/lock/" rel="tag">lock</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mfc/" rel="tag">mfc</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/min-stack/" rel="tag">min stack</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/" rel="tag">mq</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mvcc/" rel="tag">mvcc</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mysql/" rel="tag">mysql</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/namespace/" rel="tag">namespace</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/next-key-lock/" rel="tag">next-key lock</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/" rel="tag">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nullsfirst/" rel="tag">nullsfirst</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/openresty/" rel="tag">openresty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/php/" rel="tag">php</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/procedure/" rel="tag">procedure</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/python/" rel="tag">python</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/read-view/" rel="tag">read view</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/" rel="tag">redis</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/scp/" rel="tag">scp</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/signal/" rel="tag">signal</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sort/" rel="tag">sort</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spark/" rel="tag">spark</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ssh/" rel="tag">ssh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/stack/" rel="tag">stack</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/stream/" rel="tag">stream</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/string/" rel="tag">string</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/swoole/" rel="tag">swoole</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/top/" rel="tag">top</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/uname/" rel="tag">uname</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/unlock/" rel="tag">unlock</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/utf8/" rel="tag">utf8</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/utf8mb4/" rel="tag">utf8mb4</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/utf8mb4-0900-ai-ci/" rel="tag">utf8mb4_0900_ai_ci</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/utf8mb4-general-ci/" rel="tag">utf8mb4_general_ci</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/utf8mb4-unicode-ci/" rel="tag">utf8mb4_unicode_ci</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/value/" rel="tag">value</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/websocket/" rel="tag">websocket</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/" rel="tag">zookeeper</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zsh/" rel="tag">zsh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%89%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/" rel="tag">三阶段提交</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8/" rel="tag">不可变引用</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%9C%E4%BA%AC%E5%A5%A5%E8%BF%90%E4%BC%9A/" rel="tag">东京奥运会</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4/" rel="tag">两阶段提交</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%AD%E5%B1%B1%E8%B7%AF/" rel="tag">中山路</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%AD%E5%BA%8F/" rel="tag">中序</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/" rel="tag">中间件</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B8%BE%E9%87%8D/" rel="tag">举重</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%B9%92%E4%B9%93%E7%90%83/" rel="tag">乒乓球</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%BA%8B%E5%8A%A1/" rel="tag">事务</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/" rel="tag">二叉树</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%BA%92%E6%96%A5%E9%94%81/" rel="tag">互斥锁</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%BB%A3%E7%A0%81%E9%A2%98%E8%A7%A3/" rel="tag">代码题解</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E4%BF%AE%E7%94%B5%E8%84%91%E7%9A%84/" rel="tag">修电脑的</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%81%8F%E5%90%91%E9%94%81/" rel="tag">偏向锁</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%81%A5%E5%BA%B7%E7%A0%81/" rel="tag">健康码</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%85%AC%E4%BA%A4/" rel="tag">公交</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%85%AC%E4%BA%A4%E8%BD%A6/" rel="tag">公交车</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%86%85%E5%AD%98%E5%88%86%E5%B8%83/" rel="tag">内存分布</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F/" rel="tag">内存泄漏</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%87%86%E5%A4%87/" rel="tag">准备</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%87%8F%E8%82%A5/" rel="tag">减肥</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1/" rel="tag">分布式事务</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81/" rel="tag">分布式锁</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%88%87%E7%89%87/" rel="tag">切片</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%88%9D%E5%A7%8B%E5%8C%96/" rel="tag">初始化</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7/" rel="tag">削峰填谷</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%89%8D%E5%BA%8F/" rel="tag">前序</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8A%A0%E5%A1%9E/" rel="tag">加塞</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8A%A0%E8%BD%BD/" rel="tag">加载</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8D%95%E4%BE%8B/" rel="tag">单例</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8D%9A%E5%AE%A2%EF%BC%8C%E6%96%87%E7%AB%A0/" rel="tag">博客,文章</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8E%A6%E9%97%A8/" rel="tag">厦门</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE/" rel="tag">双亲委派</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8F%91%E8%A1%8C%E7%89%88/" rel="tag">发行版</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8F%A3%E7%BD%A9/" rel="tag">口罩</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%8F%AF%E5%8F%98%E5%BC%95%E7%94%A8/" rel="tag">可变引用</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%90%90%E6%A7%BD/" rel="tag">吐槽</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%9B%A4%E7%89%A9%E8%B5%84/" rel="tag">囤物资</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/" rel="tag">垃圾回收</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD/" rel="tag">基础设施</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%A4%A7%E6%89%AB%E9%99%A4/" rel="tag">大扫除</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%AD%97%E7%AC%A6%E9%9B%86/" rel="tag">字符集</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%AE%89%E5%85%A8/" rel="tag">安全</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%AE%B9%E9%94%99%E6%9C%BA%E5%88%B6/" rel="tag">容错机制</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%AF%84%E7%94%9F%E8%99%AB/" rel="tag">寄生虫</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B0%84%E5%87%BB/" rel="tag">射击</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B0%8F%E6%8A%80%E5%B7%A7/" rel="tag">小技巧</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B1%80%E5%8F%A3%E8%A1%97/" rel="tag">局口街</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8/" rel="tag">布隆过滤器</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B9%B2%E6%B4%BB/" rel="tag">干活</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B9%B4%E4%B8%AD%E6%80%BB%E7%BB%93/" rel="tag">年中总结</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/" rel="tag">年终总结</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B9%B6%E5%8F%91/" rel="tag">并发</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B9%B8%E7%A6%8F%E4%BA%86%E5%90%97/" rel="tag">幸福了吗</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%B9%BB%E8%AF%BB/" rel="tag">幻读</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%BA%94%E7%94%A8/" rel="tag">应用</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%BC%80%E8%BD%A6/" rel="tag">开车</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%BC%B1%E5%BC%95%E7%94%A8/" rel="tag">弱引用</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E5%BD%B1%E8%AF%84/" rel="tag">影评</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%89%80%E6%9C%89%E6%9D%83/" rel="tag">所有权</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%89%93%E5%8D%A1/" rel="tag">打卡</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%89%B6%E6%A2%AF/" rel="tag">扶梯</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%8A%80%E6%9C%AF/" rel="tag">技术</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%8B%96%E6%9B%B4/" rel="tag">拖更</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%8D%A2%E8%BD%A6%E7%89%8C/" rel="tag">换车牌</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%8E%92%E5%BA%8F/" rel="tag">排序</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%8E%A5%E9%9B%A8%E6%B0%B4/" rel="tag">接雨水</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%95%B0%E6%8D%AE%E6%BA%90%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2/" rel="tag">数据源动态切换</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/" rel="tag">数据结构</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%96%B0%E8%AF%AD%E8%A8%80/" rel="tag">新语言</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%97%85%E6%B8%B8/" rel="tag">旅游</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%97%A5%E5%BF%97/" rel="tag">日志</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%9B%BE%E5%8E%9D%E5%9E%B5/" rel="tag">曾厝垵</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%9C%80%E5%B0%8F%E6%A0%88/" rel="tag">最小栈</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%9D%80%E4%BA%BA%E8%AF%9B%E5%BF%83/" rel="tag">杀人诛心</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%9D%AD%E5%B7%9E/" rel="tag">杭州</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%A0%87%E8%AE%B0%E6%95%B4%E7%90%86/" rel="tag">标记整理</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%A4%8D%E7%89%A9%E5%9B%AD/" rel="tag">植物园</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%B2%99%E8%8C%B6%E9%9D%A2/" rel="tag">沙茶面</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%B3%A8%E8%A7%A3/" rel="tag">注解</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%B5%B7%E8%9B%8E%E7%85%8E/" rel="tag">海蛎煎</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/" rel="tag">消息队列</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5/" rel="tag">淘汰策略</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%BA%90%E7%A0%81/" rel="tag">源码</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/" rel="tag">源码解析</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%94%9F%E6%B4%BB/" rel="tag">生活</a><span class="tag-list-count">39</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%94%B5%E7%93%B6%E8%BD%A6/" rel="tag">电瓶车</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%96%AB%E6%83%85/" rel="tag">疫情</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%9C%8B%E4%B9%A6/" rel="tag">看书</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%9C%8B%E5%89%A7/" rel="tag">看剧</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%9F%A9%E9%98%B5/" rel="tag">矩阵</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%AB%AF%E5%8F%A3%E8%BD%AC%E5%8F%91/" rel="tag">端口转发</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%B1%BB%E5%8A%A0%E8%BD%BD/" rel="tag">类加载</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%B3%9F%E5%BF%83%E4%BA%8B/" rel="tag">糟心事</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%B4%A2%E5%BC%95/" rel="tag">索引</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BA%BF%E7%A8%8B%E6%B1%A0/" rel="tag">线程池</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BC%93%E5%AD%98/" rel="tag">缓存</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BC%93%E5%AD%98%E5%87%BB%E7%A9%BF/" rel="tag">缓存击穿</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BC%93%E5%AD%98%E7%A9%BF%E9%80%8F/" rel="tag">缓存穿透</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BC%93%E5%AD%98%E9%9B%AA%E5%B4%A9/" rel="tag">缓存雪崩</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BC%96%E7%A0%81/" rel="tag">编码</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E7%BE%8E%E5%9B%BD/" rel="tag">美国</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%80%81%E7%94%B5%E8%84%91/" rel="tag">老电脑</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/" rel="tag">自动装配</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%87%AA%E6%97%8B/" rel="tag">自旋</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%87%AA%E9%80%82%E5%BA%94%E6%8B%93%E5%B1%95/" rel="tag">自适应拓展</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%A3%85%E7%94%B5%E8%84%91/" rel="tag">装电脑</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%A7%84%E5%88%99/" rel="tag">规则</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%A7%A3%E6%9E%90/" rel="tag">解析</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" rel="tag">设计模式</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%AF%BB%E4%B9%A6/" rel="tag">读书</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/" rel="tag">读后感</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/" rel="tag">负载均衡</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%B6%B3%E7%90%83/" rel="tag">足球</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%B7%91%E6%AD%A5/" rel="tag">跑步</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%B7%AF%E6%94%BF%E8%A7%84%E5%88%92/" rel="tag">路政规划</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%B7%B3%E6%B0%B4/" rel="tag">跳水</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%B8%A9%E8%B8%8F/" rel="tag">踩踏</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BD%AC%E4%B9%89/" rel="tag">转义</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%94%81/" rel="tag">轻量级锁</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BF%87%E6%9C%9F%E7%AD%96%E7%95%A5/" rel="tag">过期策略</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BF%90%E5%8A%A8/" rel="tag">运动</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BF%9C%E7%A8%8B%E5%8A%9E%E5%85%AC/" rel="tag">远程办公</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%80%92%E5%BD%92/" rel="tag">递归</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%87%8D%E9%87%8F%E7%BA%A7%E9%94%81/" rel="tag">重量级锁</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%93%BE%E6%8E%A5/" rel="tag">链接</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%A2%98%E8%A7%A3/" rel="tag">题解</a><span class="tag-list-count">21</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%A9%AC%E6%88%8F%E5%9B%A2/" rel="tag">马戏团</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%AA%8C%E8%AF%81/" rel="tag">验证</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%AA%91%E8%BD%A6/" rel="tag">骑车</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%AB%98%E9%80%9F/" rel="tag">高速</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E9%BC%93%E6%B5%AA%E5%B1%BF/" rel="tag">鼓浪屿</a><span class="tag-list-count">1</span></li></ul></canvas></div></div><div class="links-of-blogroll site-overview-item animated"><div class="links-of-blogroll-title"><i class="fa fa-globe fa-fw"></i> Links</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"><a href="https://covermusic.cn/" title="https://covermusic.cn" rel="noopener" target="_blank">69伙伴</a></li></ul></div></div></div></div></aside><div class="sidebar-dimmer"></div></header><div class="back-to-top" role="button" aria-label="返回顶部"><i class="fa fa-arrow-up"></i> <span>0%</span></div><a href="https://github.com/nicksxs" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin:130px 106px" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><noscript><div class="noscript-warning">Theme NexT works best with JavaScript enabled</div></noscript><div class="main-inner index posts-expand"><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content"><link itemprop="mainEntityOfPage" href="https://nicksxs.me/2021/10/03/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%B8%89/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/uploads/avatar.jpg"><meta itemprop="name" content="Nicksxs"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Nicksxs's Blog"><meta itemprop="description" content="learn from zero,技术博客,Nicksxs,史学森"></span><span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork"><meta itemprop="name" content="undefined | Nicksxs's Blog"><meta itemprop="description" content=""></span><header class="post-header"><h2 class="post-title" itemprop="name headline"><a href="/2021/10/03/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%B8%89/" class="post-title-link" itemprop="url">聊一下 RocketMQ 的消息存储三</a></h2><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间:2021-10-03 20:17:37" itemprop="dateCreated datePublished" datetime="2021-10-03T20:17:37+08:00">2021-10-03</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间:2022-06-11 22:45:11" itemprop="dateModified" datetime="2022-06-11T22:45:11+08:00">2022-06-11</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/" itemprop="url" rel="index"><span itemprop="name">MQ</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/RocketMQ/" itemprop="url" rel="index"><span itemprop="name">RocketMQ</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/RocketMQ/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/" itemprop="url" rel="index"><span itemprop="name">消息队列</span></a> </span></span><span id="/2021/10/03/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%B8%89/" class="post-meta-item leancloud_visitors" data-flag-title="聊一下 RocketMQ 的消息存储三" title="阅读次数"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数:</span> <span class="leancloud-visitors-count"></span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-comment"></i> </span><span class="post-meta-item-text">Disqus:</span> <a title="disqus" href="/2021/10/03/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%B8%89/#disqus_thread" itemprop="discussionUrl"><span class="post-comments-count disqus-comment-count" data-disqus-identifier="2021/10/03/聊一下-RocketMQ-的消息存储三/" itemprop="commentCount"></span></a></span></div></div></header><div class="post-body" itemprop="articleBody"><p>ConsumeQueue 其实是定位到一个 topic 下的消息在 CommitLog 下的偏移量,它也是固定大小的</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// ConsumeQueue file size,default is 30W</span>
|
|
|
<span class="token keyword">private</span> <span class="token keyword">int</span> mapedFileSizeConsumeQueue <span class="token operator">=</span> <span class="token number">300000</span> <span class="token operator">*</span> <span class="token class-name">ConsumeQueue</span><span class="token punctuation">.</span>CQ_STORE_UNIT_SIZE<span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> CQ_STORE_UNIT_SIZE <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>所以文件大小是5.7M 左右</p><p><img data-src="https://img.nicksxs.com/uPic/5udpag.png" alt="5udpag"></p><p>ConsumeQueue 的构建是通过<code>org.apache.rocketmq.store.DefaultMessageStore.ReputMessageService</code>运行后的 doReput 方法,而启动是的 reputFromOffset 则是通过<code>org.apache.rocketmq.store.DefaultMessageStore#start</code>中下面代码设置并启动</p><pre class="line-numbers language-java" data-language="java"><code class="language-java">log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"[SetReputOffset] maxPhysicalPosInLogicQueue={} clMinOffset={} clMaxOffset={} clConfirmedOffset={}"</span><span class="token punctuation">,</span>
|
|
|
maxPhysicalPosInLogicQueue<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getMinOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getMaxOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getConfirmOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputMessageService<span class="token punctuation">.</span><span class="token function">setReputFromOffset</span><span class="token punctuation">(</span>maxPhysicalPosInLogicQueue<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputMessageService<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>看一下 doReput 的逻辑</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">doReput</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator"><</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getMinOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"The reputFromOffset={} is smaller than minPyOffset={}, this usually indicate that the dispatch behind too much and the commitlog has expired."</span><span class="token punctuation">,</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset<span class="token punctuation">,</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getMinOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">=</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getMinOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">boolean</span> doNext <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isCommitLogAvailable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> doNext<span class="token punctuation">;</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isDuplicationEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
|
<span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">>=</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getConfirmOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">break</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token comment">// 根据偏移量获取消息</span>
|
|
|
<span class="token class-name">SelectMappedBufferResult</span> result <span class="token operator">=</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span>reputFromOffset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>result <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">=</span> result<span class="token punctuation">.</span><span class="token function">getStartOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> readSize <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> readSize <span class="token operator"><</span> result<span class="token punctuation">.</span><span class="token function">getSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> doNext<span class="token punctuation">;</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 消息校验和转换</span>
|
|
|
<span class="token class-name">DispatchRequest</span> dispatchRequest <span class="token operator">=</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">checkMessageAndReturnSize</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">getByteBuffer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">int</span> size <span class="token operator">=</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getBufferSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token operator">?</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getMsgSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getBufferSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">isSuccess</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 进行分发处理,包括 ConsumeQueue 和 IndexFile</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">doDispatch</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">BrokerRole</span><span class="token punctuation">.</span>SLAVE <span class="token operator">!=</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBrokerRole</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
|
<span class="token operator">&&</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>brokerConfig<span class="token punctuation">.</span><span class="token function">isLongPollingEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>messageArrivingListener<span class="token punctuation">.</span><span class="token function">arriving</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
|
dispatchRequest<span class="token punctuation">.</span><span class="token function">getQueueId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getConsumeQueueOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span>
|
|
|
dispatchRequest<span class="token punctuation">.</span><span class="token function">getTagsCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getStoreTimestamp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
|
dispatchRequest<span class="token punctuation">.</span><span class="token function">getBitMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getPropertiesMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">+=</span> size<span class="token punctuation">;</span>
|
|
|
readSize <span class="token operator">+=</span> size<span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBrokerRole</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token class-name">BrokerRole</span><span class="token punctuation">.</span>SLAVE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>storeStatsService
|
|
|
<span class="token punctuation">.</span><span class="token function">getSinglePutMessageTopicTimesTotal</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">incrementAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>storeStatsService
|
|
|
<span class="token punctuation">.</span><span class="token function">getSinglePutMessageTopicSizeTotal</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
|
|
<span class="token punctuation">.</span><span class="token function">addAndGet</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">getMsgSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">=</span> <span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>commitLog<span class="token punctuation">.</span><span class="token function">rollNextFile</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
readSize <span class="token operator">=</span> result<span class="token punctuation">.</span><span class="token function">getSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">isSuccess</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>size <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"[BUG]read total count not equals msg total size. reputFromOffset={}"</span><span class="token punctuation">,</span> reputFromOffset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">+=</span> size<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
doNext <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// If user open the dledger pattern or the broker is master node,</span>
|
|
|
<span class="token comment">// it will not ignore the exception and fix the reputFromOffset variable</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isEnableDLegerCommitLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span>brokerConfig<span class="token punctuation">.</span><span class="token function">getBrokerId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token class-name">MixAll</span><span class="token punctuation">.</span>MASTER_ID<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"[BUG]dispatch message to consume queue error, COMMITLOG OFFSET: {}"</span><span class="token punctuation">,</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>reputFromOffset <span class="token operator">+=</span> result<span class="token punctuation">.</span><span class="token function">getSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> readSize<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
|
|
|
result<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
doNext <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>分发的逻辑看到这</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"> <span class="token keyword">class</span> <span class="token class-name">CommitLogDispatcherBuildConsumeQueue</span> <span class="token keyword">implements</span> <span class="token class-name">CommitLogDispatcher</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Override</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token class-name">DispatchRequest</span> request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">final</span> <span class="token keyword">int</span> tranType <span class="token operator">=</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span><span class="token function">getTransactionValue</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getSysFlag</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">switch</span> <span class="token punctuation">(</span>tranType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">case</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span>TRANSACTION_NOT_TYPE<span class="token operator">:</span>
|
|
|
<span class="token keyword">case</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span>TRANSACTION_COMMIT_TYPE<span class="token operator">:</span>
|
|
|
<span class="token class-name">DefaultMessageStore</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">putMessagePositionInfo</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">break</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">case</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span>TRANSACTION_PREPARED_TYPE<span class="token operator">:</span>
|
|
|
<span class="token keyword">case</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span>TRANSACTION_ROLLBACK_TYPE<span class="token operator">:</span>
|
|
|
<span class="token keyword">break</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">putMessagePositionInfo</span><span class="token punctuation">(</span><span class="token class-name">DispatchRequest</span> dispatchRequest<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">ConsumeQueue</span> cq <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">findConsumeQueue</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dispatchRequest<span class="token punctuation">.</span><span class="token function">getQueueId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
cq<span class="token punctuation">.</span><span class="token function">putMessagePositionInfoWrapper</span><span class="token punctuation">(</span>dispatchRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>真正存储的是在这</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">putMessagePositionInfo</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">long</span> offset<span class="token punctuation">,</span> <span class="token keyword">final</span> <span class="token keyword">int</span> size<span class="token punctuation">,</span> <span class="token keyword">final</span> <span class="token keyword">long</span> tagsCode<span class="token punctuation">,</span>
|
|
|
<span class="token keyword">final</span> <span class="token keyword">long</span> cqOffset<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>offset <span class="token operator">+</span> size <span class="token operator"><=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>maxPhysicOffset<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"Maybe try to build consume queue repeatedly maxPhysicOffset={} phyOffset={}"</span><span class="token punctuation">,</span> maxPhysicOffset<span class="token punctuation">,</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>byteBufferIndex<span class="token punctuation">.</span><span class="token function">flip</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>byteBufferIndex<span class="token punctuation">.</span><span class="token function">limit</span><span class="token punctuation">(</span>CQ_STORE_UNIT_SIZE<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>byteBufferIndex<span class="token punctuation">.</span><span class="token function">putLong</span><span class="token punctuation">(</span>offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>byteBufferIndex<span class="token punctuation">.</span><span class="token function">putInt</span><span class="token punctuation">(</span>size<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>byteBufferIndex<span class="token punctuation">.</span><span class="token function">putLong</span><span class="token punctuation">(</span>tagsCode<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这里也可以看到 ConsumeQueue 的存储格式,</p><p><img data-src="https://img.nicksxs.com/uPic/AA6Tve.jpg" alt="AA6Tve"></p><p>偏移量,消息大小,跟 tag 的 hashCode</p></div><footer class="post-footer"><div class="post-eof"></div></footer></article></div><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content"><link itemprop="mainEntityOfPage" href="https://nicksxs.me/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/uploads/avatar.jpg"><meta itemprop="name" content="Nicksxs"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Nicksxs's Blog"><meta itemprop="description" content="learn from zero,技术博客,Nicksxs,史学森"></span><span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork"><meta itemprop="name" content="undefined | Nicksxs's Blog"><meta itemprop="description" content=""></span><header class="post-header"><h2 class="post-title" itemprop="name headline"><a href="/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/" class="post-title-link" itemprop="url">聊一下 SpringBoot 中动态切换数据源的方法</a></h2><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间:2021-09-26 17:41:49" itemprop="dateCreated datePublished" datetime="2021-09-26T17:41:49+08:00">2021-09-26</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间:2022-06-11 22:45:11" itemprop="dateModified" datetime="2022-06-11T22:45:11+08:00">2022-06-11</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Java/SpringBoot/" itemprop="url" rel="index"><span itemprop="name">SpringBoot</span></a> </span></span><span id="/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/" class="post-meta-item leancloud_visitors" data-flag-title="聊一下 SpringBoot 中动态切换数据源的方法" title="阅读次数"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数:</span> <span class="leancloud-visitors-count"></span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-comment"></i> </span><span class="post-meta-item-text">Disqus:</span> <a title="disqus" href="/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/#disqus_thread" itemprop="discussionUrl"><span class="post-comments-count disqus-comment-count" data-disqus-identifier="2021/09/26/聊一下-SpringBoot-中动态切换数据源的方法/" itemprop="commentCount"></span></a></span></div></div></header><div class="post-body" itemprop="articleBody"><p>其实这个表示有点不太对,应该是 Druid 动态切换数据源的方法,只是应用在了 springboot 框架中,准备代码准备了半天,之前在一次数据库迁移中使用了,发现 Druid 还是很强大的,用来做动态数据源切换很方便。</p><p>首先这里的场景跟我原来用的有点点区别,在项目中使用的是通过配置中心控制数据源切换,统一切换,而这里的例子多加了个可以根据接口注解配置</p><p>第一部分是最核心的,如何基于 Spring JDBC 和 Druid 来实现数据源切换,是继承了<code>org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource</code> 这个类,他的<code>determineCurrentLookupKey</code>方法会被调用来获得用来决定选择那个数据源的对象,也就是 lookupKey,也可以通过这个类看到就是通过这个 lookupKey 来路由找到数据源。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DynamicDataSource</span> <span class="token keyword">extends</span> <span class="token class-name">AbstractRoutingDataSource</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Override</span>
|
|
|
<span class="token keyword">protected</span> <span class="token class-name">Object</span> <span class="token function">determineCurrentLookupKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">DatabaseContextHolder</span><span class="token punctuation">.</span><span class="token function">getDatabaseType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> <span class="token class-name">DatabaseContextHolder</span><span class="token punctuation">.</span><span class="token function">getDatabaseType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">return</span> <span class="token class-name">DatabaseType</span><span class="token punctuation">.</span>MASTER1<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>而如何使用这个 lookupKey 呢,就涉及到我们的 DataSource 配置了,原来就是我们可以直接通过spring 的 jdbc 配置数据源,像这样</p><p><img data-src="https://img.nicksxs.com/uPic/VQPrT3.png"></p><p>现在我们要使用 Druid 作为数据源了,然后配置 <code>DynamicDataSource</code>的参数,通过 key 来选择对应的 DataSource,也就是下面配的 master1 和 master2</p><pre class="line-numbers language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master1<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.alibaba.druid.pool.DruidDataSource<span class="token punctuation">"</span></span> <span class="token attr-name">init-method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>init<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name">destroy-method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>close<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>driverClassName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.mysql.cj.jdbc.Driver<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${master1.demo.datasource.url}<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>username</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${master1.demo.datasource.username}<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>password</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${master1.demo.datasource.password}<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>initialSize</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>minIdle</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>maxActive</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>maxWait</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>60000<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>timeBetweenEvictionRunsMillis</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>60000<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>minEvictableIdleTimeMillis</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>300000<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>validationQuery</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SELECT <span class="token punctuation">'</span>x<span class="token punctuation">'</span><span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>testWhileIdle</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>testOnBorrow</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>testOnReturn</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>poolPreparedStatements</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>maxPoolPreparedStatementPerConnectionSize</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>connectionProperties</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>config.decrypt=true<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>filters</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stat,config<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
|
|
|
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master2<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.alibaba.druid.pool.DruidDataSource<span class="token punctuation">"</span></span> <span class="token attr-name">init-method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>init<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name">destroy-method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>close<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>driverClassName</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.mysql.cj.jdbc.Driver<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>url</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${master2.demo.datasource.url}<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>username</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${master2.demo.datasource.username}<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>password</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>${master2.demo.datasource.password}<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>initialSize</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>minIdle</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>maxActive</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>maxWait</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>60000<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>timeBetweenEvictionRunsMillis</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>60000<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>minEvictableIdleTimeMillis</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>300000<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>validationQuery</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>SELECT <span class="token punctuation">'</span>x<span class="token punctuation">'</span><span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>testWhileIdle</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>true<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>testOnBorrow</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>testOnReturn</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>poolPreparedStatements</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>maxPoolPreparedStatementPerConnectionSize</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>20<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>connectionProperties</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>config.decrypt=true<span class="token punctuation">"</span></span>
|
|
|
<span class="token attr-name"><span class="token namespace">p:</span>filters</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stat,config<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
|
|
|
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.nicksxs.springdemo.config.DynamicDataSource<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>targetDataSources<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>map</span> <span class="token attr-name">key-type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>java.lang.String<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
|
|
|
<span class="token comment"><!-- master --></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>entry</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master1<span class="token punctuation">"</span></span> <span class="token attr-name">value-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master1<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
|
|
|
<span class="token comment"><!-- slave --></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>entry</span> <span class="token attr-name">key</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master2<span class="token punctuation">"</span></span> <span class="token attr-name">value-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master2<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>map</span><span class="token punctuation">></span></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>defaultTargetDataSource<span class="token punctuation">"</span></span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>master1<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span>
|
|
|
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>现在就要回到头上,介绍下这个<code>DatabaseContextHolder</code>,这里使用了 ThreadLocal 存放这个 DatabaseType,为啥要用这个是因为前面说的我们想要让接口层面去配置不同的数据源,要把持相互隔离不受影响,就使用了 ThreadLocal,关于它也可以看我前面写的一篇文章<a href="https://nicksxs.me/2021/05/30/%E8%81%8A%E8%81%8A%E4%BC%A0%E8%AF%B4%E4%B8%AD%E7%9A%84-ThreadLocal/">聊聊传说中的 ThreadLocal</a>,而 DatabaseType 就是个简单的枚举</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DatabaseContextHolder</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">DatabaseType</span><span class="token punctuation">></span></span> databaseTypeThreadLocal <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThreadLocal</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">DatabaseType</span> <span class="token function">getDatabaseType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> databaseTypeThreadLocal<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">putDatabaseType</span><span class="token punctuation">(</span><span class="token class-name">DatabaseType</span> databaseType<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
databaseTypeThreadLocal<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>databaseType<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">clearDatabaseType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
databaseTypeThreadLocal<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">DatabaseType</span> <span class="token punctuation">{</span>
|
|
|
<span class="token function">MASTER1</span><span class="token punctuation">(</span><span class="token string">"master1"</span><span class="token punctuation">,</span> <span class="token string">"1"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
|
<span class="token function">MASTER2</span><span class="token punctuation">(</span><span class="token string">"master2"</span><span class="token punctuation">,</span> <span class="token string">"2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
|
|
|
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">String</span> value<span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token class-name">DatabaseType</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">String</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> name<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> value<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">DatabaseType</span> <span class="token function">getDatabaseType</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>MASTER2<span class="token punctuation">.</span>name<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> MASTER2<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">return</span> MASTER1<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这边可以看到就是通过动态地通过<code>putDatabaseType</code>设置<code>lookupKey</code>来进行数据源切换,要通过接口注解配置来进行设置的话,我们就需要一个注解</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>RUNTIME<span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span>METHOD<span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">DataSource</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">String</span> <span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这个注解可以配置在我的接口方法上,比如这样</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">StudentService</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@DataSource</span><span class="token punctuation">(</span><span class="token string">"master1"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token class-name">Student</span> <span class="token function">queryOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@DataSource</span><span class="token punctuation">(</span><span class="token string">"master2"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token class-name">Student</span> <span class="token function">queryAnother</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通过切面来进行数据源的设置</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Aspect</span>
|
|
|
<span class="token annotation punctuation">@Component</span>
|
|
|
<span class="token annotation punctuation">@Order</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DataSourceAspect</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Pointcut</span><span class="token punctuation">(</span><span class="token string">"execution(* com.nicksxs.springdemo.service..*.*(..))"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">pointCut</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
|
|
|
<span class="token annotation punctuation">@Before</span><span class="token punctuation">(</span><span class="token string">"pointCut()"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token class-name">JoinPoint</span> point<span class="token punctuation">)</span>
|
|
|
<span class="token punctuation">{</span>
|
|
|
<span class="token class-name">Object</span> target <span class="token operator">=</span> point<span class="token punctuation">.</span><span class="token function">getTarget</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">String</span> method <span class="token operator">=</span> point<span class="token punctuation">.</span><span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span><span class="token punctuation">[</span><span class="token punctuation">]</span> classz <span class="token operator">=</span> target<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getInterfaces</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span><span class="token punctuation">[</span><span class="token punctuation">]</span> parameterTypes <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">MethodSignature</span><span class="token punctuation">)</span> point<span class="token punctuation">.</span><span class="token function">getSignature</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
|
|
|
<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getParameterTypes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">Method</span> m <span class="token operator">=</span> classz<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span>method<span class="token punctuation">,</span> parameterTypes<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"method"</span><span class="token operator">+</span> m<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>m<span class="token punctuation">.</span><span class="token function">isAnnotationPresent</span><span class="token punctuation">(</span><span class="token class-name">DataSource</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">DataSource</span> data <span class="token operator">=</span> m<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">DataSource</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"dataSource:"</span><span class="token operator">+</span>data<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">DatabaseContextHolder</span><span class="token punctuation">.</span><span class="token function">putDatabaseType</span><span class="token punctuation">(</span><span class="token class-name">DatabaseType</span><span class="token punctuation">.</span><span class="token function">getDatabaseType</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@After</span><span class="token punctuation">(</span><span class="token string">"pointCut()"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">after</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">DatabaseContextHolder</span><span class="token punctuation">.</span><span class="token function">clearDatabaseType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通过接口判断是否带有注解跟是注解的值,DatabaseType 的配置不太好,不过先忽略了,然后在切点后进行清理</p><p>这是我 master1 的数据,</p><p><img data-src="https://img.nicksxs.com/uPic/sdQuJo.png"></p><p>master2 的数据</p><p><img data-src="https://img.nicksxs.com/uPic/fXK1Wk.png"></p><p>然后跑一下简单的 demo,</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Override</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
LOGGER<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"run here"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>studentService<span class="token punctuation">.</span><span class="token function">queryOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>studentService<span class="token punctuation">.</span><span class="token function">queryAnother</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>看一下运行结果</p><p><img data-src="https://img.nicksxs.com/uPic/42VAeq.png"></p><p>其实这个方法应用场景不止可以用来迁移数据库,还能实现精细化的读写数据源分离之类的,算是做个简单记录和分享。</p></div><footer class="post-footer"><div class="post-eof"></div></footer></article></div><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content"><link itemprop="mainEntityOfPage" href="https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/uploads/avatar.jpg"><meta itemprop="name" content="Nicksxs"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Nicksxs's Blog"><meta itemprop="description" content="learn from zero,技术博客,Nicksxs,史学森"></span><span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork"><meta itemprop="name" content="undefined | Nicksxs's Blog"><meta itemprop="description" content=""></span><header class="post-header"><h2 class="post-title" itemprop="name headline"><a href="/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/" class="post-title-link" itemprop="url">聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点</a></h2><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间:2021-09-19 22:56:31" itemprop="dateCreated datePublished" datetime="2021-09-19T22:56:31+08:00">2021-09-19</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间:2022-06-11 22:45:11" itemprop="dateModified" datetime="2022-06-11T22:45:11+08:00">2022-06-11</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/Java/SpringBoot/" itemprop="url" rel="index"><span itemprop="name">SpringBoot</span></a> </span></span><span id="/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/" class="post-meta-item leancloud_visitors" data-flag-title="聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点" title="阅读次数"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数:</span> <span class="leancloud-visitors-count"></span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-comment"></i> </span><span class="post-meta-item-text">Disqus:</span> <a title="disqus" href="/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/#disqus_thread" itemprop="discussionUrl"><span class="post-comments-count disqus-comment-count" data-disqus-identifier="2021/09/19/聊一下-SpringBoot-中使用的-cglib-作为动态代理中的一个注意点/" itemprop="commentCount"></span></a></span></div></div></header><div class="post-body" itemprop="articleBody"><p>这个话题是由一次组内同学分享引出来的,首先在 springboot 2.x 开始默认使用了 cglib 作为 aop 的实现,这里也稍微讲一下,在一个 1.x 的老项目里,可以看到AopAutoConfiguration 是这样的</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Configuration</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnClass</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token class-name">EnableAspectJAutoProxy</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name">Aspect</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name">Advice</span><span class="token punctuation">.</span><span class="token keyword">class</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnProperty</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"spring.aop"</span><span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token string">"auto"</span><span class="token punctuation">,</span> havingValue <span class="token operator">=</span> <span class="token string">"true"</span><span class="token punctuation">,</span> matchIfMissing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AopAutoConfiguration</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Configuration</span>
|
|
|
<span class="token annotation punctuation">@EnableAspectJAutoProxy</span><span class="token punctuation">(</span>proxyTargetClass <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnProperty</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"spring.aop"</span><span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token string">"proxy-target-class"</span><span class="token punctuation">,</span> havingValue <span class="token operator">=</span> <span class="token string">"false"</span><span class="token punctuation">,</span> matchIfMissing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">JdkDynamicAutoProxyConfiguration</span> <span class="token punctuation">{</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Configuration</span>
|
|
|
<span class="token annotation punctuation">@EnableAspectJAutoProxy</span><span class="token punctuation">(</span>proxyTargetClass <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnProperty</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"spring.aop"</span><span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token string">"proxy-target-class"</span><span class="token punctuation">,</span> havingValue <span class="token operator">=</span> <span class="token string">"true"</span><span class="token punctuation">,</span> matchIfMissing <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">CglibAutoProxyConfiguration</span> <span class="token punctuation">{</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>而在 2.x 中变成了这样</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Configuration</span><span class="token punctuation">(</span>proxyBeanMethods <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnProperty</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"spring.aop"</span><span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token string">"auto"</span><span class="token punctuation">,</span> havingValue <span class="token operator">=</span> <span class="token string">"true"</span><span class="token punctuation">,</span> matchIfMissing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AopAutoConfiguration</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Configuration</span><span class="token punctuation">(</span>proxyBeanMethods <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnClass</span><span class="token punctuation">(</span><span class="token class-name">Advice</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">AspectJAutoProxyingConfiguration</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Configuration</span><span class="token punctuation">(</span>proxyBeanMethods <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@EnableAspectJAutoProxy</span><span class="token punctuation">(</span>proxyTargetClass <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnProperty</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"spring.aop"</span><span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token string">"proxy-target-class"</span><span class="token punctuation">,</span> havingValue <span class="token operator">=</span> <span class="token string">"false"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">JdkDynamicAutoProxyConfiguration</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Configuration</span><span class="token punctuation">(</span>proxyBeanMethods <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@EnableAspectJAutoProxy</span><span class="token punctuation">(</span>proxyTargetClass <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
|
|
<span class="token annotation punctuation">@ConditionalOnProperty</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">"spring.aop"</span><span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token string">"proxy-target-class"</span><span class="token punctuation">,</span> havingValue <span class="token operator">=</span> <span class="token string">"true"</span><span class="token punctuation">,</span>
|
|
|
matchIfMissing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">CglibAutoProxyConfiguration</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>为何会加载 AopAutoConfiguration 在前面的文章<a href="https://nicksxs.me/2021/07/11/%E8%81%8A%E8%81%8ASpringBoot-%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/">聊聊 SpringBoot 自动装配</a>里已经介绍过,有兴趣的可以看下,可以发现 springboot 在 2.x 版本开始使用 cglib 作为默认的动态代理实现。</p><p>然后就是出现的问题了,代码是这样的,一个简单的基于 springboot 的带有数据库的插入,对插入代码加了事务注解,</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Mapper</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">StudentMapper</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 就是插入一条数据</span>
|
|
|
<span class="token annotation punctuation">@Insert</span><span class="token punctuation">(</span><span class="token string">"insert into student(name, age)"</span> <span class="token operator">+</span> <span class="token string">"values ('nick', '18')"</span><span class="token punctuation">)</span>
|
|
|
<span class="token keyword">public</span> <span class="token class-name">Long</span> <span class="token function">insert</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Component</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StudentManager</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Resource</span>
|
|
|
<span class="token keyword">private</span> <span class="token class-name">StudentMapper</span> studentMapper<span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">public</span> <span class="token class-name">Long</span> <span class="token function">createStudent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> studentMapper<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Component</span>
|
|
|
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StudentServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">StudentService</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Resource</span>
|
|
|
<span class="token keyword">private</span> <span class="token class-name">StudentManager</span> studentManager<span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token comment">// 自己引用</span>
|
|
|
<span class="token annotation punctuation">@Resource</span>
|
|
|
<span class="token keyword">private</span> <span class="token class-name">StudentServiceImpl</span> studentService<span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Override</span>
|
|
|
<span class="token annotation punctuation">@Transactional</span>
|
|
|
<span class="token keyword">public</span> <span class="token class-name">Long</span> <span class="token function">createStudent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">Long</span> id <span class="token operator">=</span> studentManager<span class="token punctuation">.</span><span class="token function">createStudent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">Long</span> id2 <span class="token operator">=</span> studentService<span class="token punctuation">.</span><span class="token function">createStudent2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token number">1L</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token annotation punctuation">@Transactional</span>
|
|
|
<span class="token keyword">private</span> <span class="token class-name">Long</span> <span class="token function">createStudent2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// Integer t = Integer.valueOf("aaa");</span>
|
|
|
<span class="token keyword">return</span> studentManager<span class="token punctuation">.</span><span class="token function">createStudent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>第一个公有方法 createStudent 首先调用了 manager 层的创建方法,然后再通过引入的 studentService 调用了createStudent2,我们先跑一下看看会出现啥情况,果不其然报错了,正是这个报错让我纠结了很久</p><p><img data-src="https://img.nicksxs.com/uPic/EdR7oB.png" alt="EdR7oB"></p><p>报了个空指针,而且是在 createStudent2 已经被调用到了,在它的内部,报的 studentManager 是 null,首先 cglib 作为动态代理它是通过继承的方式来实现的,相当于是会在调用目标对象的代理方法时调用 cglib 生成的子类,具体的代理切面逻辑在子类实现,然后在调用目标对象的目标方法,但是继承的方式对于 final 和私有方法其实是没法进行代理的,因为没法继承,所以我最开始的想法是应该通过 studentService 调用 createStudent2 的时候就报错了,也就是不会进入这个方法内部,后面才发现犯了个特别二的错误,继承的方式去调用父类的私有方法,对于 Java 来说是可以调用到的,父类的私有方法并不由子类的InstanceKlass维护,只能通过子类的InstanceKlass找到Java类对应的_super,这样间接地访问。也就是说子类其实是可以访问的,那为啥访问了会报空指针呢,这里报的是studentManager 是空的,可以往依赖注入方面去想,如果忽略依赖注入,我这个studentManager 的确是 null,那是不是就没有被依赖注入呢,但是为啥前面那个可以呢</p><p>这个问题着实查了很久,不废话来看代码</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Override</span>
|
|
|
<span class="token keyword">protected</span> <span class="token class-name">Object</span> <span class="token function">invokeJoinpoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>methodProxy <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 这里的 target 就是被代理的 bean</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>methodProxy<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>target<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>arguments<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">invokeJoinpoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这个是<code>org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation</code>的代码,其实它在这里不是直接调用 super 也就是父类的方法,而是通过 methodProxy 调用 target 目标对象的方法,也就是原始的 studentService bean 的方法,这样子 spring 管理的已经做好依赖注入的 bean 就能正常起作用,否则就会出现上面的问题,因为 cglib 其实是通过继承来实现,通过将调用转移到子类上加入代理逻辑,我们在简单使用的时候会直接 invokeSuper() 调用父类的方法,但是在这里 spring 的场景里需要去支持 spring 的功能逻辑,所以上面的问题就可以开始来解释了,因为 createStudent 是公共方法,cglib 可以对其进行继承代理,但是在执行逻辑的时候其实是通过调用目标对象,也就是 spring 管理的被代理的目标对象的 bean 调用的 createStudent,而对于下面的 createStudent2 方法因为是私有方法,不会走代理逻辑,也就不会有调用回目标对象的逻辑,只是通过继承关系,在子类中没有这个方法,所以会通过子类的InstanceKlass找到这个类对应的_super,然后调用父类的这个私有方法,这里要搞清楚一个点,从这个代理类直接找到其父类然后调用这个私有方法,这个类是由 cglib 生成的,不是被 spring 管理起来经过依赖注入的 bean,所以是没有 studentManager 这个依赖的,也就出现了前面的问题</p><p>而在前面提到的cglib通过methodProxy调用到目标对象,目标对象是在什么时候设置的呢,其实是在bean的生命周期中,org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization这个接口的在bean的初始化过程中,会调用实现了这个接口的方法,</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Override</span>
|
|
|
<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">postProcessAfterInitialization</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>bean <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">Object</span> cacheKey <span class="token operator">=</span> <span class="token function">getCacheKey</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>earlyProxyReferences<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">)</span> <span class="token operator">!=</span> bean<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> <span class="token function">wrapIfNecessary</span><span class="token punctuation">(</span>bean<span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> cacheKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">return</span> bean<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>具体的逻辑在 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary这个方法里</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">protected</span> <span class="token class-name">Object</span> <span class="token function">getCacheKey</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span> beanClass<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token class-name">FactoryBean</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">isAssignableFrom</span><span class="token punctuation">(</span>beanClass<span class="token punctuation">)</span> <span class="token operator">?</span>
|
|
|
<span class="token class-name">BeanFactory</span><span class="token punctuation">.</span>FACTORY_BEAN_PREFIX <span class="token operator">+</span> beanName <span class="token operator">:</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> beanClass<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token comment">/**
|
|
|
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
|
|
|
* @param bean the raw bean instance
|
|
|
* @param beanName the name of the bean
|
|
|
* @param cacheKey the cache key for metadata access
|
|
|
* @return a proxy wrapping the bean, or the raw bean instance as-is
|
|
|
*/</span>
|
|
|
<span class="token keyword">protected</span> <span class="token class-name">Object</span> <span class="token function">wrapIfNecessary</span><span class="token punctuation">(</span><span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">,</span> <span class="token class-name">Object</span> cacheKey<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>targetSourcedBeans<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> bean<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Boolean</span><span class="token punctuation">.</span>FALSE<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">return</span> bean<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isInfrastructureClass</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">shouldSkip</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> <span class="token class-name">Boolean</span><span class="token punctuation">.</span>FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> bean<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token comment">// Create proxy if we have advice.</span>
|
|
|
<span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> specificInterceptors <span class="token operator">=</span> <span class="token function">getAdvicesAndAdvisorsForBean</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>specificInterceptors <span class="token operator">!=</span> DO_NOT_PROXY<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> <span class="token class-name">Boolean</span><span class="token punctuation">.</span>TRUE<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">Object</span> proxy <span class="token operator">=</span> <span class="token function">createProxy</span><span class="token punctuation">(</span>
|
|
|
bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> specificInterceptors<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">SingletonTargetSource</span><span class="token punctuation">(</span>bean<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>proxyTypes<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> proxy<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> proxy<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>advisedBeans<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> <span class="token class-name">Boolean</span><span class="token punctuation">.</span>FALSE<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> bean<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>然后在 <code>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy</code> 中创建了代理类</p></div><footer class="post-footer"><div class="post-eof"></div></footer></article></div><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content"><link itemprop="mainEntityOfPage" href="https://nicksxs.me/2021/09/12/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%BA%8C/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/uploads/avatar.jpg"><meta itemprop="name" content="Nicksxs"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Nicksxs's Blog"><meta itemprop="description" content="learn from zero,技术博客,Nicksxs,史学森"></span><span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork"><meta itemprop="name" content="undefined | Nicksxs's Blog"><meta itemprop="description" content=""></span><header class="post-header"><h2 class="post-title" itemprop="name headline"><a href="/2021/09/12/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%BA%8C/" class="post-title-link" itemprop="url">聊一下 RocketMQ 的消息存储二</a></h2><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间:2021-09-12 20:49:18" itemprop="dateCreated datePublished" datetime="2021-09-12T20:49:18+08:00">2021-09-12</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间:2022-06-11 22:45:11" itemprop="dateModified" datetime="2022-06-11T22:45:11+08:00">2022-06-11</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/" itemprop="url" rel="index"><span itemprop="name">MQ</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/RocketMQ/" itemprop="url" rel="index"><span itemprop="name">RocketMQ</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/RocketMQ/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/" itemprop="url" rel="index"><span itemprop="name">消息队列</span></a> </span></span><span id="/2021/09/12/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%BA%8C/" class="post-meta-item leancloud_visitors" data-flag-title="聊一下 RocketMQ 的消息存储二" title="阅读次数"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数:</span> <span class="leancloud-visitors-count"></span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-comment"></i> </span><span class="post-meta-item-text">Disqus:</span> <a title="disqus" href="/2021/09/12/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%BA%8C/#disqus_thread" itemprop="discussionUrl"><span class="post-comments-count disqus-comment-count" data-disqus-identifier="2021/09/12/聊一下-RocketMQ-的消息存储二/" itemprop="commentCount"></span></a></span></div></div></header><div class="post-body" itemprop="articleBody"><h3 id="CommitLog-结构"><a href="#CommitLog-结构" class="headerlink" title="CommitLog 结构"></a>CommitLog 结构</h3><p>CommitLog 是 rocketmq 的服务端,也就是 broker 存储消息的的文件,跟 kafka 一样,也是顺序写入,当然消息是变长的,生成的规则是每个文件的默认1G =1024 * 1024 * 1024,commitlog的文件名fileName,名字长度为20位,左边补零,剩余为起始偏移量;比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1 073 741 824Byte;当这个文件满了,第二个文件名字为00000000001073741824,起始偏移量为1073741824, 消息存储的时候会顺序写入文件,当文件满了则写入下一个文件,代码中的定义</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">// CommitLog file size,default is 1G</span>
|
|
|
<span class="token keyword">private</span> <span class="token keyword">int</span> mapedFileSizeCommitLog <span class="token operator">=</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p><img data-src="https://img.nicksxs.com/uPic/kLahwW.png" alt="kLahwW"></p><p>本地跑个 demo 验证下,也是这样,这里奇妙有几个比较巧妙的点(个人观点),首先文件就刚好是 1G,并且按照大小偏移量去生成下一个文件,这样获取消息的时候按大小算一下就知道在哪个文件里了,</p><p>代码中写入 CommitLog 的逻辑可以从这开始看</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">PutMessageResult</span> <span class="token function">putMessage</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token class-name">MessageExtBrokerInner</span> msg<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// Set the storage time</span>
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setStoreTimestamp</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// Set the message body BODY CRC (consider the most appropriate setting</span>
|
|
|
<span class="token comment">// on the client)</span>
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setBodyCRC</span><span class="token punctuation">(</span><span class="token class-name">UtilAll</span><span class="token punctuation">.</span><span class="token function">crc32</span><span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// Back to Results</span>
|
|
|
<span class="token class-name">AppendMessageResult</span> result <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token class-name">StoreStatsService</span> storeStatsService <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">getStoreStatsService</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token class-name">String</span> topic <span class="token operator">=</span> msg<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">int</span> queueId <span class="token operator">=</span> msg<span class="token punctuation">.</span><span class="token function">getQueueId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">final</span> <span class="token keyword">int</span> tranType <span class="token operator">=</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span><span class="token function">getTransactionValue</span><span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getSysFlag</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>tranType <span class="token operator">==</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span>TRANSACTION_NOT_TYPE
|
|
|
<span class="token operator">||</span> tranType <span class="token operator">==</span> <span class="token class-name">MessageSysFlag</span><span class="token punctuation">.</span>TRANSACTION_COMMIT_TYPE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// Delay Delivery</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getDelayTimeLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getDelayTimeLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">getScheduleMessageService</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getMaxDelayLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setDelayTimeLevel</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">getScheduleMessageService</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getMaxDelayLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
topic <span class="token operator">=</span> <span class="token class-name">ScheduleMessageService</span><span class="token punctuation">.</span>SCHEDULE_TOPIC<span class="token punctuation">;</span>
|
|
|
queueId <span class="token operator">=</span> <span class="token class-name">ScheduleMessageService</span><span class="token punctuation">.</span><span class="token function">delayLevel2QueueId</span><span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getDelayTimeLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token comment">// Backup real topic, queueId</span>
|
|
|
<span class="token class-name">MessageAccessor</span><span class="token punctuation">.</span><span class="token function">putProperty</span><span class="token punctuation">(</span>msg<span class="token punctuation">,</span> <span class="token class-name">MessageConst</span><span class="token punctuation">.</span>PROPERTY_REAL_TOPIC<span class="token punctuation">,</span> msg<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">MessageAccessor</span><span class="token punctuation">.</span><span class="token function">putProperty</span><span class="token punctuation">(</span>msg<span class="token punctuation">,</span> <span class="token class-name">MessageConst</span><span class="token punctuation">.</span>PROPERTY_REAL_QUEUE_ID<span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getQueueId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setPropertiesString</span><span class="token punctuation">(</span><span class="token class-name">MessageDecoder</span><span class="token punctuation">.</span><span class="token function">messageProperties2String</span><span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getProperties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setTopic</span><span class="token punctuation">(</span>topic<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setQueueId</span><span class="token punctuation">(</span>queueId<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">long</span> eclipseTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">MappedFile</span> unlockMappedFile <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">MappedFile</span> mappedFile <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileQueue<span class="token punctuation">.</span><span class="token function">getLastMappedFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
putMessageLock<span class="token punctuation">.</span><span class="token function">lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//spin or ReentrantLock ,depending on store config</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">long</span> beginLockTimestamp <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">getSystemClock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>beginTimeInLock <span class="token operator">=</span> beginLockTimestamp<span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token comment">// Here settings are stored timestamp, in order to ensure an orderly</span>
|
|
|
<span class="token comment">// global</span>
|
|
|
msg<span class="token punctuation">.</span><span class="token function">setStoreTimestamp</span><span class="token punctuation">(</span>beginLockTimestamp<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">==</span> mappedFile <span class="token operator">||</span> mappedFile<span class="token punctuation">.</span><span class="token function">isFull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileQueue<span class="token punctuation">.</span><span class="token function">getLastMappedFile</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Mark: NewFile may be cause noise</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">==</span> mappedFile<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"create mapped file1 error, topic: "</span> <span class="token operator">+</span> msg<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" clientAddr: "</span> <span class="token operator">+</span> msg<span class="token punctuation">.</span><span class="token function">getBornHostString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
beginTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PutMessageResult</span><span class="token punctuation">(</span><span class="token class-name">PutMessageStatus</span><span class="token punctuation">.</span>CREATE_MAPEDFILE_FAILED<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
result <span class="token operator">=</span> mappedFile<span class="token punctuation">.</span><span class="token function">appendMessage</span><span class="token punctuation">(</span>msg<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>appendMessageCallback<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">switch</span> <span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">getStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">case</span> PUT_OK<span class="token operator">:</span>
|
|
|
<span class="token keyword">break</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">case</span> END_OF_FILE<span class="token operator">:</span>
|
|
|
unlockMappedFile <span class="token operator">=</span> mappedFile<span class="token punctuation">;</span>
|
|
|
<span class="token comment">// Create a new file, re-write the message</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileQueue<span class="token punctuation">.</span><span class="token function">getLastMappedFile</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">==</span> mappedFile<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// XXX: warn and notify me</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"create mapped file2 error, topic: "</span> <span class="token operator">+</span> msg<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" clientAddr: "</span> <span class="token operator">+</span> msg<span class="token punctuation">.</span><span class="token function">getBornHostString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
beginTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PutMessageResult</span><span class="token punctuation">(</span><span class="token class-name">PutMessageStatus</span><span class="token punctuation">.</span>CREATE_MAPEDFILE_FAILED<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
result <span class="token operator">=</span> mappedFile<span class="token punctuation">.</span><span class="token function">appendMessage</span><span class="token punctuation">(</span>msg<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>appendMessageCallback<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">break</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">case</span> MESSAGE_SIZE_EXCEEDED<span class="token operator">:</span>
|
|
|
<span class="token keyword">case</span> PROPERTIES_SIZE_EXCEEDED<span class="token operator">:</span>
|
|
|
beginTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PutMessageResult</span><span class="token punctuation">(</span><span class="token class-name">PutMessageStatus</span><span class="token punctuation">.</span>MESSAGE_ILLEGAL<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">case</span> UNKNOWN_ERROR<span class="token operator">:</span>
|
|
|
beginTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PutMessageResult</span><span class="token punctuation">(</span><span class="token class-name">PutMessageStatus</span><span class="token punctuation">.</span>UNKNOWN_ERROR<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">default</span><span class="token operator">:</span>
|
|
|
beginTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PutMessageResult</span><span class="token punctuation">(</span><span class="token class-name">PutMessageStatus</span><span class="token punctuation">.</span>UNKNOWN_ERROR<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
eclipseTimeInLock <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">getSystemClock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> beginLockTimestamp<span class="token punctuation">;</span>
|
|
|
beginTimeInLock <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
|
|
|
putMessageLock<span class="token punctuation">.</span><span class="token function">unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>eclipseTimeInLock <span class="token operator">></span> <span class="token number">500</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"[NOTIFYME]putMessage in lock cost time(ms)={}, bodyLength={} AppendMessageResult={}"</span><span class="token punctuation">,</span> eclipseTimeInLock<span class="token punctuation">,</span> msg<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">!=</span> unlockMappedFile <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isWarmMapedFileEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>defaultMessageStore<span class="token punctuation">.</span><span class="token function">unlockMappedFile</span><span class="token punctuation">(</span>unlockMappedFile<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token class-name">PutMessageResult</span> putMessageResult <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PutMessageResult</span><span class="token punctuation">(</span><span class="token class-name">PutMessageStatus</span><span class="token punctuation">.</span>PUT_OK<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token comment">// Statistics</span>
|
|
|
storeStatsService<span class="token punctuation">.</span><span class="token function">getSinglePutMessageTopicTimesTotal</span><span class="token punctuation">(</span>msg<span class="token punctuation">.</span><span class="token function">getTopic</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">incrementAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
storeStatsService<span class="token punctuation">.</span><span class="token function">getSinglePutMessageTopicSizeTotal</span><span class="token punctuation">(</span>topic<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addAndGet</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">getWroteBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token function">handleDiskFlush</span><span class="token punctuation">(</span>result<span class="token punctuation">,</span> putMessageResult<span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token function">handleHA</span><span class="token punctuation">(</span>result<span class="token punctuation">,</span> putMessageResult<span class="token punctuation">,</span> msg<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">return</span> putMessageResult<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>前面也看到在CommitLog 目录下是有大小为 1G 的文件组成,在实现逻辑中,其实是通过 <code>org.apache.rocketmq.store.MappedFileQueue</code> ,内部是存的一个<code>MappedFile</code>的队列,对于写入的场景每次都是通过<code>org.apache.rocketmq.store.MappedFileQueue#getLastMappedFile()</code> 获取最后一个文件,如果还没有创建,或者最后这个文件已经满了,那就调用 <code>org.apache.rocketmq.store.MappedFileQueue#getLastMappedFile(long)</code></p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">MappedFile</span> <span class="token function">getLastMappedFile</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token keyword">long</span> startOffset<span class="token punctuation">,</span> <span class="token keyword">boolean</span> needCreate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">long</span> createOffset <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// 调用前面的方法,只是从 mappedFileQueue 获取最后一个</span>
|
|
|
<span class="token class-name">MappedFile</span> mappedFileLast <span class="token operator">=</span> <span class="token function">getLastMappedFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token comment">// 如果为空,计算下创建的偏移量</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>mappedFileLast <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
createOffset <span class="token operator">=</span> startOffset <span class="token operator">-</span> <span class="token punctuation">(</span>startOffset <span class="token operator">%</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token comment">// 如果不为空,但是当前的文件写满了</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>mappedFileLast <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> mappedFileLast<span class="token punctuation">.</span><span class="token function">isFull</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 前一个的偏移量加上单个文件的偏移量,也就是 1G</span>
|
|
|
createOffset <span class="token operator">=</span> mappedFileLast<span class="token punctuation">.</span><span class="token function">getFileFromOffset</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileSize<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>createOffset <span class="token operator">!=</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token operator">&&</span> needCreate<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 根据 createOffset 转换成文件名进行创建</span>
|
|
|
<span class="token class-name">String</span> nextFilePath <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>storePath <span class="token operator">+</span> <span class="token class-name">File</span><span class="token punctuation">.</span>separator <span class="token operator">+</span> <span class="token class-name">UtilAll</span><span class="token punctuation">.</span><span class="token function">offset2FileName</span><span class="token punctuation">(</span>createOffset<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">String</span> nextNextFilePath <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>storePath <span class="token operator">+</span> <span class="token class-name">File</span><span class="token punctuation">.</span>separator
|
|
|
<span class="token operator">+</span> <span class="token class-name">UtilAll</span><span class="token punctuation">.</span><span class="token function">offset2FileName</span><span class="token punctuation">(</span>createOffset <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">MappedFile</span> mappedFile <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token comment">// 这里如果allocateMappedFileService 存在,就提交请求</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>allocateMappedFileService <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>allocateMappedFileService<span class="token punctuation">.</span><span class="token function">putRequestAndReturnMappedFile</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">,</span>
|
|
|
nextNextFilePath<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 否则就直接创建</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MappedFile</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mappedFileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"create mappedFile exception"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>mappedFile <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>mappedFiles<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
mappedFile<span class="token punctuation">.</span><span class="token function">setFirstCreateInQueue</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>mappedFiles<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>mappedFile<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">return</span> mappedFile<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">return</span> mappedFileLast<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>首先看下直接创建的,</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">MappedFile</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token class-name">String</span> fileName<span class="token punctuation">,</span> <span class="token keyword">final</span> <span class="token keyword">int</span> fileSize<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
|
|
|
<span class="token function">init</span><span class="token punctuation">(</span>fileName<span class="token punctuation">,</span> fileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token class-name">String</span> fileName<span class="token punctuation">,</span> <span class="token keyword">final</span> <span class="token keyword">int</span> fileSize<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>fileName <span class="token operator">=</span> fileName<span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>fileSize <span class="token operator">=</span> fileSize<span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>file <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">File</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>fileFromOffset <span class="token operator">=</span> <span class="token class-name">Long</span><span class="token punctuation">.</span><span class="token function">parseLong</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>file<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">boolean</span> ok <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token function">ensureDirOK</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>file<span class="token punctuation">.</span><span class="token function">getParent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 通过 RandomAccessFile 创建 fileChannel</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>fileChannel <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RandomAccessFile</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>file<span class="token punctuation">,</span> <span class="token string">"rw"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getChannel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// 做 mmap 映射</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>mappedByteBuffer <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fileChannel<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">MapMode</span><span class="token punctuation">.</span>READ_WRITE<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> fileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
TOTAL_MAPPED_VIRTUAL_MEMORY<span class="token punctuation">.</span><span class="token function">addAndGet</span><span class="token punctuation">(</span>fileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
TOTAL_MAPPED_FILES<span class="token punctuation">.</span><span class="token function">incrementAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
ok <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">FileNotFoundException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"create file channel "</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fileName <span class="token operator">+</span> <span class="token string">" Failed. "</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">throw</span> e<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"map file "</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fileName <span class="token operator">+</span> <span class="token string">" Failed. "</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">throw</span> e<span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>ok <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fileChannel <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>fileChannel<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如果是提交给<code>AllocateMappedFileService</code>的话就用到了一些异步操作</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">MappedFile</span> <span class="token function">putRequestAndReturnMappedFile</span><span class="token punctuation">(</span><span class="token class-name">String</span> nextFilePath<span class="token punctuation">,</span> <span class="token class-name">String</span> nextNextFilePath<span class="token punctuation">,</span> <span class="token keyword">int</span> fileSize<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">int</span> canSubmitRequests <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isTransientStorePoolEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isFastFailIfNoBufferInStorePool</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
|
<span class="token operator">&&</span> <span class="token class-name">BrokerRole</span><span class="token punctuation">.</span>SLAVE <span class="token operator">!=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBrokerRole</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">//if broker is slave, don't fast fail even no buffer in pool</span>
|
|
|
canSubmitRequests <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getTransientStorePool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remainBufferNumbs</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token comment">// 将请求放在 requestTable 中</span>
|
|
|
<span class="token class-name">AllocateRequest</span> nextReq <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AllocateRequest</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">,</span> fileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">boolean</span> nextPutOK <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">putIfAbsent</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">,</span> nextReq<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// requestTable 使用了 concurrentHashMap,用文件名作为 key,防止并发</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>nextPutOK<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 这里判断了是否可以提交到 TransientStorePool,涉及读写分离,后面再细聊</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>canSubmitRequests <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"[NOTIFYME]TransientStorePool is not enough, so create mapped file error, "</span> <span class="token operator">+</span>
|
|
|
<span class="token string">"RequestQueueSize : {}, StorePoolSize: {}"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getTransientStorePool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remainBufferNumbs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token comment">// 塞到阻塞队列中</span>
|
|
|
<span class="token keyword">boolean</span> offerOK <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">offer</span><span class="token punctuation">(</span>nextReq<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>offerOK<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"never expected here, add a request to preallocate queue failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
canSubmitRequests<span class="token operator">--</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token comment">// 这里的两个提交我猜测是为了多生成一个 CommitLog,</span>
|
|
|
<span class="token class-name">AllocateRequest</span> nextNextReq <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AllocateRequest</span><span class="token punctuation">(</span>nextNextFilePath<span class="token punctuation">,</span> fileSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">boolean</span> nextNextPutOK <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">putIfAbsent</span><span class="token punctuation">(</span>nextNextFilePath<span class="token punctuation">,</span> nextNextReq<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>nextNextPutOK<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>canSubmitRequests <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"[NOTIFYME]TransientStorePool is not enough, so skip preallocate mapped file, "</span> <span class="token operator">+</span>
|
|
|
<span class="token string">"RequestQueueSize : {}, StorePoolSize: {}"</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getTransientStorePool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">remainBufferNumbs</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>nextNextFilePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">boolean</span> offerOK <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">offer</span><span class="token punctuation">(</span>nextNextReq<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>offerOK<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"never expected here, add a request to preallocate queue failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>hasException<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getServiceName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" service has exception. so return null"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token class-name">AllocateRequest</span> result <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 这里就异步等着</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>result <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">boolean</span> waitOK <span class="token operator">=</span> result<span class="token punctuation">.</span><span class="token function">getCountDownLatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span>waitTimeOut<span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span><span class="token punctuation">.</span>MILLISECONDS<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>waitOK<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"create mmap timeout "</span> <span class="token operator">+</span> result<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> result<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>nextFilePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">getMappedFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"find preallocate mmap failed, this never happen"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getServiceName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" service has exception. "</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>而真正去执行文件操作的就是 <code>AllocateMappedFileService</code>的 run 方法</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getServiceName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" service started"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isStopped</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">mmapOperation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
|
|
|
<span class="token punctuation">}</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getServiceName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" service end"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">mmapOperation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">boolean</span> isSuccess <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">AllocateRequest</span> req <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 从阻塞队列里获取请求</span>
|
|
|
req <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token class-name">AllocateRequest</span> expectedRequest <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestTable<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">==</span> expectedRequest<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"this mmap request expired, maybe cause timeout "</span> <span class="token operator">+</span> req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" "</span>
|
|
|
<span class="token operator">+</span> req<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>expectedRequest <span class="token operator">!=</span> req<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"never expected here, maybe cause timeout "</span> <span class="token operator">+</span> req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" "</span>
|
|
|
<span class="token operator">+</span> req<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">", req:"</span> <span class="token operator">+</span> req <span class="token operator">+</span> <span class="token string">", expectedRequest:"</span> <span class="token operator">+</span> expectedRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">getMappedFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">long</span> beginTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
|
|
|
<span class="token class-name">MappedFile</span> mappedFile<span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isTransientStorePoolEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 通过 transientStorePool 创建</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token class-name">ServiceLoader</span><span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token class-name">MappedFile</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">iterator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
mappedFile<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> req<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> messageStore<span class="token punctuation">.</span><span class="token function">getTransientStorePool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RuntimeException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"Use default implementation."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token comment">// 默认创建</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MappedFile</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> req<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> messageStore<span class="token punctuation">.</span><span class="token function">getTransientStorePool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
|
|
|
<span class="token comment">// 默认创建</span>
|
|
|
mappedFile <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MappedFile</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> req<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token keyword">long</span> eclipseTime <span class="token operator">=</span> <span class="token class-name">UtilAll</span><span class="token punctuation">.</span><span class="token function">computeEclipseTimeMilliseconds</span><span class="token punctuation">(</span>beginTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>eclipseTime <span class="token operator">></span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">int</span> queueSize <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>requestQueue<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"create mappedFile spent time(ms) "</span> <span class="token operator">+</span> eclipseTime <span class="token operator">+</span> <span class="token string">" queue size "</span> <span class="token operator">+</span> queueSize
|
|
|
<span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> req<span class="token punctuation">.</span><span class="token function">getFilePath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" "</span> <span class="token operator">+</span> req<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
<span class="token comment">// pre write mappedFile</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>mappedFile<span class="token punctuation">.</span><span class="token function">getFileSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">>=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
|
<span class="token punctuation">.</span><span class="token function">getMapedFileSizeCommitLog</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
|
|
|
<span class="token operator">&&</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isWarmMapedFileEnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
mappedFile<span class="token punctuation">.</span><span class="token function">warmMappedFile</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getFlushDiskType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>messageStore<span class="token punctuation">.</span><span class="token function">getMessageStoreConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getFlushLeastPagesWhenWarmMapedFile</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
|
|
|
req<span class="token punctuation">.</span><span class="token function">setMappedFile</span><span class="token punctuation">(</span>mappedFile<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>hasException <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
|
|
|
isSuccess <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getServiceName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" interrupted, possibly by shutdown."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>hasException <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">IOException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getServiceName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" service has exception. "</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">this</span><span class="token punctuation">.</span>hasException <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">!=</span> req<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
requestQueue<span class="token punctuation">.</span><span class="token function">offer</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">try</span> <span class="token punctuation">{</span>
|
|
|
<span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> ignored<span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
|
|
|
<span class="token keyword">if</span> <span class="token punctuation">(</span>req <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> isSuccess<span class="token punctuation">)</span>
|
|
|
<span class="token comment">// 通知前面等待的</span>
|
|
|
req<span class="token punctuation">.</span><span class="token function">getCountDownLatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></div><footer class="post-footer"><div class="post-eof"></div></footer></article></div><div class="post-block"><article itemscope itemtype="http://schema.org/Article" class="post-content"><link itemprop="mainEntityOfPage" href="https://nicksxs.me/2021/09/04/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="image" content="/uploads/avatar.jpg"><meta itemprop="name" content="Nicksxs"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Nicksxs's Blog"><meta itemprop="description" content="learn from zero,技术博客,Nicksxs,史学森"></span><span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork"><meta itemprop="name" content="undefined | Nicksxs's Blog"><meta itemprop="description" content=""></span><header class="post-header"><h2 class="post-title" itemprop="name headline"><a href="/2021/09/04/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8/" class="post-title-link" itemprop="url">聊一下 RocketMQ 的消息存储之 MMAP</a></h2><div class="post-meta-container"><div class="post-meta"><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar"></i> </span><span class="post-meta-item-text">发表于</span> <time title="创建时间:2021-09-04 10:29:41" itemprop="dateCreated datePublished" datetime="2021-09-04T10:29:41+08:00">2021-09-04</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-calendar-check"></i> </span><span class="post-meta-item-text">更新于</span> <time title="修改时间:2022-06-11 22:45:11" itemprop="dateModified" datetime="2022-06-11T22:45:11+08:00">2022-06-11</time> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-folder"></i> </span><span class="post-meta-item-text">分类于</span> <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/" itemprop="url" rel="index"><span itemprop="name">MQ</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/RocketMQ/" itemprop="url" rel="index"><span itemprop="name">RocketMQ</span></a> </span>, <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/MQ/RocketMQ/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/" itemprop="url" rel="index"><span itemprop="name">消息队列</span></a> </span></span><span id="/2021/09/04/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8/" class="post-meta-item leancloud_visitors" data-flag-title="聊一下 RocketMQ 的消息存储之 MMAP" title="阅读次数"><span class="post-meta-item-icon"><i class="far fa-eye"></i> </span><span class="post-meta-item-text">阅读次数:</span> <span class="leancloud-visitors-count"></span> </span><span class="post-meta-item"><span class="post-meta-item-icon"><i class="far fa-comment"></i> </span><span class="post-meta-item-text">Disqus:</span> <a title="disqus" href="/2021/09/04/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8/#disqus_thread" itemprop="discussionUrl"><span class="post-comments-count disqus-comment-count" data-disqus-identifier="2021/09/04/聊一下-RocketMQ-的消息存储/" itemprop="commentCount"></span></a></span></div></div></header><div class="post-body" itemprop="articleBody"><p>这是个很大的话题了,可能会分成两部分说,第一部分就是所谓的零拷贝 ( zero-copy ),这一块其实也不新鲜,我对零拷贝的概念主要来自<a target="_blank" rel="noopener" href="https://www.linuxjournal.com/article/6345">这篇文章</a>,个人感觉写得非常好,在 rocketmq 中,最大的一块存储就是消息存储,也就是 CommitLog ,当然还有 ConsumeQueue 和 IndexFile,以及其他一些文件,CommitLog 的存储是以一个 1G 大小的文件作为存储单位,写完了就再建一个,那么如何提高这 1G 文件的读写效率呢,就是 mmap,传统意义的读写文件,read,write 都需要由系统调用,来回地在用户态跟内核态进行拷贝切换,</p><pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token function">read</span><span class="token punctuation">(</span>file<span class="token punctuation">,</span> tmp_buf<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token function">write</span><span class="token punctuation">(</span>socket<span class="token punctuation">,</span> tmp_buf<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p><img data-src="https://img.nicksxs.com/uPic/vms95Z.jpg" alt="vms95Z"></p><p>如上面的图显示的,要在用户态跟内核态进行切换,数据还需要在内核缓冲跟用户缓冲之间拷贝多次,</p><blockquote><ol><li>第一步是调用 read,需要在用户态切换成内核态,<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Direct_memory_access">DMA</a>模块从磁盘中读取文件,并存储在内核缓冲区,相当于是第一次复制</li><li>数据从内核缓冲区被拷贝到用户缓冲区,read 调用返回,伴随着内核态又切换成用户态,完成了第二次复制</li><li>然后是write 写入,这里也会伴随着用户态跟内核态的切换,数据从用户缓冲区被复制到内核空间缓冲区,完成了第三次复制,这次有点不一样的是数据不是在内核缓冲区了,会复制到 socket buffer 中。</li><li>write 系统调用返回,又切换回了用户态,然后数据由 DMA 拷贝到协议引擎。</li></ol></blockquote><p>如此就能看出其实默认的读写操作代价是非常大的,而在 rocketmq 等高性能中间件中都有使用的零拷贝技术,其中 rocketmq 使用的是 mmap</p><h3 id="mmap"><a href="#mmap" class="headerlink" title="mmap"></a>mmap</h3><p>mmap基于 OS 的 <a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Mmap">mmap</a> 的内存映射技术,通过<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Memory_management_unit">MMU</a> 映射文件,将文件直接映射到用户态的内存地址,使得对文件的操作不再是 write/read,而转化为直接对内存地址的操作,使随机读写文件和读写内存相似的速度。</p><blockquote><p>mmap 把文件映射到用户空间里的虚拟内存,省去了从内核缓冲区复制到用户空间的过程,文件中的位置在虚拟内存中有了对应的地址,可以像操作内存一样操作这个文件,这样的文件读写文件方式少了数据从内核缓存到用户空间的拷贝,效率很高。</p></blockquote><pre class="line-numbers language-c" data-language="c"><code class="language-c">tmp_buf <span class="token operator">=</span> <span class="token function">mmap</span><span class="token punctuation">(</span>file<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token function">write</span><span class="token punctuation">(</span>socket<span class="token punctuation">,</span> tmp_buf<span class="token punctuation">,</span> len<span class="token punctuation">)</span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p><img data-src="https://img.nicksxs.com/uPic/I68mFx.jpg" alt="I68mFx"></p><blockquote><p>第一步:mmap系统调用使得文件内容被DMA引擎复制到内核缓冲区。然后该缓冲区与用户进程共享,在内核和用户内存空间之间不进行任何拷贝。</p><p>第二步:写系统调用使得内核将数据从原来的内核缓冲区复制到与套接字相关的内核缓冲区。</p><p>第三步:第三次拷贝发生在DMA引擎将数据从内核套接字缓冲区传递给协议引擎时。</p><p>通过使用mmap而不是read,我们将内核需要拷贝的数据量减少了一半。当大量的数据被传输时,这将有很好的效果。然而,这种改进并不是没有代价的;在使用mmap+write方法时,有一些隐藏的陷阱。例如当你对一个文件进行内存映射,然后在另一个进程截断同一文件时调用写。你的写系统调用将被总线错误信号SIGBUS打断,因为你执行了一个错误的内存访问。该信号的默认行为是杀死进程并dumpcore–这对网络服务器来说不是最理想的操作。</p><p>有两种方法可以解决这个问题。</p><p>第一种方法是为SIGBUS信号安装一个信号处理程序,然后在处理程序中简单地调用返回。通过这样做,写系统调用会返回它在被打断之前所写的字节数,并将errno设置为成功。让我指出,这将是一个糟糕的解决方案,一个治标不治本的解决方案。因为SIGBUS预示着进程出了严重的问题,所以不鼓励使用这种解决方案。</p><p>第二个解决方案涉及内核的文件租赁(在Windows中称为 “机会锁”)。这是解决这个问题的正确方法。通过在文件描述符上使用租赁,你与内核在一个特定的文件上达成租约。然后你可以向内核请求一个读/写租约。当另一个进程试图截断你正在传输的文件时,内核会向你发送一个实时信号,即RT_SIGNAL_LEASE信号。它告诉你内核即将终止你对该文件的写或读租约。在你的程序访问一个无效的地址和被SIGBUS信号杀死之前,你的写调用会被打断了。写入调用的返回值是中断前写入的字节数,errno将被设置为成功。下面是一些示例代码,显示了如何从内核中获得租约。</p><pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">fcntl</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> F_SETSIG<span class="token punctuation">,</span> RT_SIGNAL_LEASE<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
|
|
|
<span class="token function">perror</span><span class="token punctuation">(</span><span class="token string">"kernel lease set signal"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span>
|
|
|
<span class="token comment">/* l_type can be F_RDLCK F_WRLCK */</span>
|
|
|
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">fcntl</span><span class="token punctuation">(</span>fd<span class="token punctuation">,</span> F_SETLEASE<span class="token punctuation">,</span> l_type<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
|
|
|
<span class="token function">perror</span><span class="token punctuation">(</span><span class="token string">"kernel lease set type"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
|
|
|
<span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
|
|
|
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></blockquote></div><footer class="post-footer"><div class="post-eof"></div></footer></article></div><nav class="pagination"><a class="extend prev" rel="prev" href="/page/10/"><i class="fa fa-angle-left" aria-label="上一页"></i></a><a class="page-number" href="/">1</a><span class="space">…</span><a class="page-number" href="/page/10/">10</a><span class="page-number current">11</span><a class="page-number" href="/page/12/">12</a><span class="space">…</span><a class="page-number" href="/page/35/">35</a><a class="extend next" rel="next" href="/page/12/"><i class="fa fa-angle-right" aria-label="下一页"></i></a></nav></div></main><footer class="footer"><div class="footer-inner"><div class="copyright">© <span itemprop="copyrightYear">2022</span> <span class="with-love"><i class="fa fa-heart"></i> </span><span class="author" itemprop="copyrightHolder">Nicksxs</span></div><div class="busuanzi-count"><span class="post-meta-item" id="busuanzi_container_site_uv"><span class="post-meta-item-icon"><i class="fa fa-user"></i> </span><span class="site-uv" title="总访客量"><span id="busuanzi_value_site_uv"></span> </span></span><span class="post-meta-item" id="busuanzi_container_site_pv"><span class="post-meta-item-icon"><i class="fa fa-eye"></i> </span><span class="site-pv" title="总访问量"><span id="busuanzi_value_site_pv"></span></span></span></div></div></footer><script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.5.7/jquery.fancybox.min.js" integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin="anonymous"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script><script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/next-boot.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.0/search.js" integrity="sha256-vXZMYLEqsROAXkEw93GGIvaB2ab+QW6w3+1ahD9nXXA=" crossorigin="anonymous"></script><script src="/js/third-party/search/local-search.js"></script><script src="/js/third-party/fancybox.js"></script><script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><script class="next-config" data-name="leancloud_visitors" type="application/json">{"enable":true,"app_id":"ysza182Vghlqjdt7QiwGLLJy-gzGzoHsz","app_key":"s9GDqbn7gnGGkusf66YRVccw","server_url":"https://leancloud.cn","security":true}</script><script src="/js/third-party/statistics/lean-analytics.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/quicklink/2.2.0/quicklink.umd.js" integrity="sha256-4kQf9z5ntdQrzsBC3YSHnEz02Z9C1UeW/E9OgnvlzSY=" crossorigin="anonymous"></script><script class="next-config" data-name="quicklink" type="application/json">{"enable":false,"home":false,"archive":false,"delay":true,"timeout":3000,"priority":true,"url":"https://nicksxs.me/page/11/"}</script><script src="/js/third-party/quicklink.js"></script><script class="next-config" data-name="disqus" type="application/json">{"enable":true,"shortname":"nicksxs","count":true,"i18n":{"disqus":"disqus"}}</script><script src="/js/third-party/comments/disqus.js"></script></body></html>
|