blob: f02e6a77f0108d8d606fbb8ae333d26bd1900598 [file] [log] [blame]
<!doctype html><html lang=en class=no-js><head><meta name=ROBOTS content="INDEX, FOLLOW"><link rel=canonical href=https://cn.dubbo.apache.org/en/blog/2018/08/14/source-code-analysis-of-spring-boot-dubbo-app-start-and-stop/><script>var _hmt=_hmt||[];(function(){var e,t=document.createElement("script");t.src="https://hm.baidu.com/hm.js?3b78f49ba47181e4d998a66b689446e9",e=document.getElementsByTagName("script")[0],e.parentNode.insertBefore(t,e)})()</script><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta http-equiv=Content-Security-Policy content="frame-src *"><meta name=generator content="Hugo 0.122.0"><link rel="shortcut icon" type=image/png href=/imgs/favicon.png><link rel=apple-touch-icon href=/favicons/apple-touch-icon-180x180.png sizes=180x180><link rel=manifest href=/manifest.webmanifest><title>Source code analysis of spring-boot+Dubbo App start and stop | Apache Dubbo</title><meta property="og:title" content="Source code analysis of spring-boot+Dubbo App start and stop">
<meta property="og:description" content="This article introduces the implementation details of app start and stop in `dubbo-spring-boot-project`.
"><meta property="og:type" content="article"><meta property="og:url" content="https://cn.dubbo.apache.org/en/blog/2018/08/14/source-code-analysis-of-spring-boot-dubbo-app-start-and-stop/"><meta property="article:section" content="blog"><meta property="article:published_time" content="2018-08-14T00:00:00+00:00"><meta property="article:modified_time" content="2020-12-22T13:19:33+08:00"><meta itemprop=name content="Source code analysis of spring-boot+Dubbo App start and stop"><meta itemprop=description content="This article introduces the implementation details of app start and stop in `dubbo-spring-boot-project`.
"><meta itemprop=datePublished content="2018-08-14T00:00:00+00:00"><meta itemprop=dateModified content="2020-12-22T13:19:33+08:00"><meta itemprop=wordCount content="1337"><meta itemprop=keywords content><meta name=twitter:card content="summary"><meta name=twitter:title content="Source code analysis of spring-boot+Dubbo App start and stop"><meta name=twitter:description content="This article introduces the implementation details of app start and stop in `dubbo-spring-boot-project`.
"><script async src="https://www.googletagmanager.com/gtag/js?id=G-NM6FFMT51J"></script><script>var doNotTrack=!1;if(!doNotTrack){window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag("js",new Date),gtag("config","G-NM6FFMT51J",{anonymize_ip:!1})}</script><link rel=preload href=/scss/main.min.f77e221bcdbe0cadb996060fe82063c747b60c229a1f8bbf0ee529adbadd84fa.css as=style><link href=/scss/main.min.f77e221bcdbe0cadb996060fe82063c747b60c229a1f8bbf0ee529adbadd84fa.css rel=stylesheet integrity><script src=/js/jquery-3.5.1.min.js integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin=anonymous></script><meta name=theme-color content="#326ce5"><link rel=stylesheet href=/css/feature-states.css><meta name=description content="This article introduces the implementation details of app start and stop in `dubbo-spring-boot-project`.
"><meta property="og:description" content="This article introduces the implementation details of app start and stop in `dubbo-spring-boot-project`.
"><meta name=twitter:description content="This article introduces the implementation details of app start and stop in `dubbo-spring-boot-project`.
"><meta property="og:url" content="https://cn.dubbo.apache.org/en/blog/2018/08/14/source-code-analysis-of-spring-boot-dubbo-app-start-and-stop/"><meta property="og:title" content="Source code analysis of spring-boot+Dubbo App start and stop"><meta name=twitter:title content="Source code analysis of spring-boot+Dubbo App start and stop"><meta name=twitter:image:alt content="Apache Dubbo"><meta property="og:type" content="article"><meta name=viewport content="width=device-width"><script async defer src=/js/github-buttons.js></script><link href=/css/community.css rel=stylesheet><link href=/css/contactus.css rel=stylesheet><link href=/css/language.css rel=stylesheet><script src=/js/script.js></script></head><body class="td-page td-documentation"><header><nav class="js-navbar-scroll navbar navbar-expand navbar-dark flex-column flex-md-row td-navbar" data-auto-burger=primary><a class=navbar-brand href=/en/><span class=navbar-logo></span><span class="text-uppercase font-weight-bold">Apache Dubbo</span></a><div class="td-navbar-nav-scroll ml-md-auto" id=main_navbar><ul class="navbar-nav mt-2 mt-lg-0"><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/en/overview/><span>Overview</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/en/docs3-v2/><span>SDK Manual</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class="nav-link active" href=/en/blog/><span class=active>Blog</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=/en/download/><span>Download</span></a></li><li class="nav-item mr-4 mb-2 mb-lg-0"><a class=nav-link href=https://start.dubbo.apache.org/bootstrap.html target=_blank><span>Initializer</span><i class='fas fa-external-link-alt'></i></a></li><li class="nav-item dropdown d-lg-block"><a class="nav-link dropdown-toggle" href=# id=navbarDropdownMenuLink role=button data-toggle=dropdown aria-haspopup=true aria-expanded=false>English</a><div class="dropdown-menu dropdown-menu-right" aria-labelledby=navbarDropdownMenuLink><a class=dropdown-item href=/zh-cn/>δΈ­ζ–‡</a></div></li><li class="nav-item dropdown d-lg-block"><div class="nav-item d-none d-lg-block"></div></li></ul></div></nav><section class="header-hero text-white pb-0 light-text"></section></header><div class="container-fluid td-outer"><div class=td-main><div class="row flex-md-nowrap"><div class="col-12 col-md-3 col-xl-2 td-sidebar d-print-none"><script>$(function(){$("#td-section-nav a").removeClass("active"),$("#td-section-nav #m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop").addClass("active"),$("#td-section-nav #m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop-li span").addClass("td-sidebar-nav-active-item"),$("#td-section-nav #m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop").parents("li").addClass("active-path"),$("#td-section-nav li.active-path").addClass("show"),$("#td-section-nav li.active-path").children("input").prop("checked",!0),$("#td-section-nav #m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop-li").siblings("li").addClass("show"),$("#td-section-nav #m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop-li").children("ul").children("li").addClass("show"),$("#td-sidebar-menu").toggleClass("d-none")})</script><div id=td-sidebar-menu class="td-sidebar__inner d-none"><div id=content-mobile><form class="td-sidebar__search d-flex align-items-center"><button class="btn btn-link td-sidebar__toggle d-md-none p-0 ml-3 fas fa-bars" type=button data-toggle=collapse data-target=#td-section-nav aria-controls=td-docs-nav aria-expanded=false aria-label="Toggle section navigation"></button></form></div><div id=content-desktop></div><nav class="collapse td-sidebar-nav foldable-nav" id=td-section-nav><ul class="td-sidebar-nav__section pr-md-3 ul-0"><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-enblog-li><ul class=ul-1><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-enblognews-li><input type=checkbox id=m-enblognews-check>
<label for=m-enblognews-check><a href=/en/blog/news/ title="Articles About Apache Dubbo" class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-enblognews><span>Articles</span></a></label><ul class="ul-2 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20240131tracing-dubbo-with-opentelemetry-li><input type=checkbox id=m-enblog20240131tracing-dubbo-with-opentelemetry-check>
<label for=m-enblog20240131tracing-dubbo-with-opentelemetry-check><a href=/en/blog/2024/01/31/tracing-dubbo-with-opentelemetry/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20240131tracing-dubbo-with-opentelemetry><span>Tracing Dubbo With OpenTelemetry</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20231023introduction-to-apache-dubbo-plugin-for-intellij-idea-li><input type=checkbox id=m-enblog20231023introduction-to-apache-dubbo-plugin-for-intellij-idea-check>
<label for=m-enblog20231023introduction-to-apache-dubbo-plugin-for-intellij-idea-check><a href=/en/blog/2023/10/23/introduction-to-apache-dubbo-plugin-for-intellij-idea/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20231023introduction-to-apache-dubbo-plugin-for-intellij-idea><span>Introduction to Apache Dubbo plugin for IntelliJ IDEA</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20230415advanced-cloud-native-dubbo-32-officially-released-li><input type=checkbox id=m-enblog20230415advanced-cloud-native-dubbo-32-officially-released-check>
<label for=m-enblog20230415advanced-cloud-native-dubbo-32-officially-released-check><a href=/en/blog/2023/04/15/advanced-cloud-native-dubbo-3.2-officially-released/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20230415advanced-cloud-native-dubbo-32-officially-released><span>Advanced cloud native - Dubbo 3.2 officially released</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20220504how-to-proxy-dubbo-service-in-apache-shenyu-gateway-li><input type=checkbox id=m-enblog20220504how-to-proxy-dubbo-service-in-apache-shenyu-gateway-check>
<label for=m-enblog20220504how-to-proxy-dubbo-service-in-apache-shenyu-gateway-check><a href=/en/blog/2022/05/04/how-to-proxy-dubbo-service-in-apache-shenyu-gateway/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20220504how-to-proxy-dubbo-service-in-apache-shenyu-gateway><span>How to proxy Dubbo service in Apache ShenYu Gateway</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20220118makes-it-more-convenient-for-you-to-proxy-dubbo-services-in-apache-apisix-li><input type=checkbox id=m-enblog20220118makes-it-more-convenient-for-you-to-proxy-dubbo-services-in-apache-apisix-check>
<label for=m-enblog20220118makes-it-more-convenient-for-you-to-proxy-dubbo-services-in-apache-apisix-check><a href=/en/blog/2022/01/18/makes-it-more-convenient-for-you-to-proxy-dubbo-services-in-apache-apisix/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20220118makes-it-more-convenient-for-you-to-proxy-dubbo-services-in-apache-apisix><span>Makes it More Convenient for You to Proxy Dubbo Services in Apache APISIX</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190826service-test-li><input type=checkbox id=m-enblog20190826service-test-check>
<label for=m-enblog20190826service-test-check><a href=/en/blog/2019/08/26/service-test/ title="Dubbo Admin service test" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190826service-test><span>Service test in dubbo admin</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190811tracing-dubbo-service-with-apache-skywalking-li><input type=checkbox id=m-enblog20190811tracing-dubbo-service-with-apache-skywalking-check>
<label for=m-enblog20190811tracing-dubbo-service-with-apache-skywalking-check><a href=/en/blog/2019/08/11/tracing-dubbo-service-with-apache-skywalking/ title="Tracing Dubbo service with Apache Skywalking" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190811tracing-dubbo-service-with-apache-skywalking><span>Use apache skywalking in dubbo</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190502dubbo-extensible-mechanism-source-code-analysis-part-2-li><input type=checkbox id=m-enblog20190502dubbo-extensible-mechanism-source-code-analysis-part-2-check>
<label for=m-enblog20190502dubbo-extensible-mechanism-source-code-analysis-part-2-check><a href=/en/blog/2019/05/02/dubbo-extensible-mechanism-source-code-analysis-part-2/ title="Dubbo extensible mechanism source code analysis - part 2" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190502dubbo-extensible-mechanism-source-code-analysis-part-2><span>Dubbo extensible mechanism - part 2</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190425dubbo-extensible-mechanism-source-code-analysis-part-1-li><input type=checkbox id=m-enblog20190425dubbo-extensible-mechanism-source-code-analysis-part-1-check>
<label for=m-enblog20190425dubbo-extensible-mechanism-source-code-analysis-part-1-check><a href=/en/blog/2019/04/25/dubbo-extensible-mechanism-source-code-analysis-part-1/ title="Dubbo extensible mechanism source code analysis - part 1" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190425dubbo-extensible-mechanism-source-code-analysis-part-1><span>Dubbo extensible mechanism - part 1</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190220implementation-background-and-practice-of-dubbo-client-asynchronous-interface-li><input type=checkbox id=m-enblog20190220implementation-background-and-practice-of-dubbo-client-asynchronous-interface-check>
<label for=m-enblog20190220implementation-background-and-practice-of-dubbo-client-asynchronous-interface-check><a href=/en/blog/2019/02/20/implementation-background-and-practice-of-dubbo-client-asynchronous-interface/ title="Implementation background and practice of Dubbo client asynchronous interface" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190220implementation-background-and-practice-of-dubbo-client-asynchronous-interface><span>Dubbo Async Client</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190220implementation-background-and-practice-of-dubbo-server-asynchronous-interface-li><input type=checkbox id=m-enblog20190220implementation-background-and-practice-of-dubbo-server-asynchronous-interface-check>
<label for=m-enblog20190220implementation-background-and-practice-of-dubbo-server-asynchronous-interface-check><a href=/en/blog/2019/02/20/implementation-background-and-practice-of-dubbo-server-asynchronous-interface/ title="Implementation background and practice of Dubbo server asynchronous interface" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190220implementation-background-and-practice-of-dubbo-server-asynchronous-interface><span>Dubbo Async Server</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20190117how-to-use-seata-to-ensure-consistency-between-dubbo-microservices-li><input type=checkbox id=m-enblog20190117how-to-use-seata-to-ensure-consistency-between-dubbo-microservices-check>
<label for=m-enblog20190117how-to-use-seata-to-ensure-consistency-between-dubbo-microservices-check><a href=/en/blog/2019/01/17/how-to-use-seata-to-ensure-consistency-between-dubbo-microservices/ title="How to use Seata to ensure consistency between Dubbo Microservices" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20190117how-to-use-seata-to-ensure-consistency-between-dubbo-microservices><span>Use Seata in Dubbo</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20181210the-fifth-dubbo-meetup-has-been-held-in-hangzhou-li><input type=checkbox id=m-enblog20181210the-fifth-dubbo-meetup-has-been-held-in-hangzhou-check>
<label for=m-enblog20181210the-fifth-dubbo-meetup-has-been-held-in-hangzhou-check><a href=/en/blog/2018/12/10/the-fifth-dubbo-meetup-has-been-held-in-hangzhou/ title="The fifth Dubbo meetup has been held in Hangzhou" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20181210the-fifth-dubbo-meetup-has-been-held-in-hangzhou><span>The fifth Dubbo meetup</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20181107dubbo-integrates-with-nacos-to-become-a-registry-li><input type=checkbox id=m-enblog20181107dubbo-integrates-with-nacos-to-become-a-registry-check>
<label for=m-enblog20181107dubbo-integrates-with-nacos-to-become-a-registry-check><a href=/en/blog/2018/11/07/dubbo-integrates-with-nacos-to-become-a-registry/ title="Dubbo Integrates with Nacos to Become a Registry" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20181107dubbo-integrates-with-nacos-to-become-a-registry><span>Use Dubbo with Nacos</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20181005introduction-to-the-dubbo-protocol-li><input type=checkbox id=m-enblog20181005introduction-to-the-dubbo-protocol-check>
<label for=m-enblog20181005introduction-to-the-dubbo-protocol-check><a href=/en/blog/2018/10/05/introduction-to-the-dubbo-protocol/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20181005introduction-to-the-dubbo-protocol><span>Introduction to the Dubbo protocol</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180930integrate-dubbo-with-kubernetes-li><input type=checkbox id=m-enblog20180930integrate-dubbo-with-kubernetes-check>
<label for=m-enblog20180930integrate-dubbo-with-kubernetes-check><a href=/en/blog/2018/09/30/integrate-dubbo-with-kubernetes/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180930integrate-dubbo-with-kubernetes><span>Integrate Dubbo with Kubernetes</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180902how-to-prepare-an-apache-release-li><input type=checkbox id=m-enblog20180902how-to-prepare-an-apache-release-check>
<label for=m-enblog20180902how-to-prepare-an-apache-release-check><a href=/en/blog/2018/09/02/how-to-prepare-an-apache-release/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180902how-to-prepare-an-apache-release><span>How to prepare an Apache Release</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180902how-to-implement-a-fully-asynchronous-calls-chain-based-on-dubbo-li><input type=checkbox id=m-enblog20180902how-to-implement-a-fully-asynchronous-calls-chain-based-on-dubbo-check>
<label for=m-enblog20180902how-to-implement-a-fully-asynchronous-calls-chain-based-on-dubbo-check><a href=/en/blog/2018/09/02/how-to-implement-a-fully-asynchronous-calls-chain-based-on-dubbo/ title="How to implement a fully asynchronous calls chain based on Dubbo" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180902how-to-implement-a-fully-asynchronous-calls-chain-based-on-dubbo><span>New Async Call</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180826the-fourth-dubbo-meetup-has-been-held-in-chengdu-li><input type=checkbox id=m-enblog20180826the-fourth-dubbo-meetup-has-been-held-in-chengdu-check>
<label for=m-enblog20180826the-fourth-dubbo-meetup-has-been-held-in-chengdu-check><a href=/en/blog/2018/08/26/the-fourth-dubbo-meetup-has-been-held-in-chengdu/ title="The fourth Dubbo meetup has been held in Chengdu" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180826the-fourth-dubbo-meetup-has-been-held-in-chengdu><span>The fourth Dubbo meetup</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814dubbo-basic-usage-dubbo-consumer-configuration-li><input type=checkbox id=m-enblog20180814dubbo-basic-usage-dubbo-consumer-configuration-check>
<label for=m-enblog20180814dubbo-basic-usage-dubbo-consumer-configuration-check><a href=/en/blog/2018/08/14/dubbo-basic-usage-dubbo-consumer-configuration/ title=" Dubbo Basic Usage - Dubbo Consumer Configuration" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814dubbo-basic-usage-dubbo-consumer-configuration><span>Dubbo Consumer Configuration</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814dubbo-several-ways-about-synchronousasynchronous-invoke-li><input type=checkbox id=m-enblog20180814dubbo-several-ways-about-synchronousasynchronous-invoke-check>
<label for=m-enblog20180814dubbo-several-ways-about-synchronousasynchronous-invoke-check><a href=/en/blog/2018/08/14/dubbo-several-ways-about-synchronous/asynchronous-invoke/ title="Dubbo: Several ways about synchronous/asynchronous invoke" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814dubbo-several-ways-about-synchronousasynchronous-invoke><span>Dubbo Invoke</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814dubbo-basic-usage--dubbo-provider-configuration-li><input type=checkbox id=m-enblog20180814dubbo-basic-usage--dubbo-provider-configuration-check>
<label for=m-enblog20180814dubbo-basic-usage--dubbo-provider-configuration-check><a href=/en/blog/2018/08/14/dubbo-basic-usage--dubbo-provider-configuration/ title="Dubbo Basic Usage -- Dubbo Provider Configuration" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814dubbo-basic-usage--dubbo-provider-configuration><span>Dubbo Provider Configuration</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814manipulating-services-dynamically-via-qos-li><input type=checkbox id=m-enblog20180814manipulating-services-dynamically-via-qos-check>
<label for=m-enblog20180814manipulating-services-dynamically-via-qos-check><a href=/en/blog/2018/08/14/manipulating-services-dynamically-via-qos/ title="Manipulating Services Dynamically via QoS" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814manipulating-services-dynamically-via-qos><span>Dubbo QoS Introduction</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop-li><input type=checkbox id=m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop-check>
<label for=m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop-check><a href=/en/blog/2018/08/14/source-code-analysis-of-spring-boot-dubbo-app-start-and-stop/ title="Source code analysis of spring-boot+Dubbo App start and stop" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814source-code-analysis-of-spring-boot-dubbo-app-start-and-stop><span>Dubbo start/stop in spring boot</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814implementation-of-cross-language-calls-by-dubbo2js-li><input type=checkbox id=m-enblog20180814implementation-of-cross-language-calls-by-dubbo2js-check>
<label for=m-enblog20180814implementation-of-cross-language-calls-by-dubbo2js-check><a href=/en/blog/2018/08/14/implementation-of-cross-language-calls-by-dubbo2.js/ title="Implementation of cross-language calls by Dubbo2.js" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814implementation-of-cross-language-calls-by-dubbo2js><span>dubbo2.js introduction</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814generic-invoke-of-dubbo-li><input type=checkbox id=m-enblog20180814generic-invoke-of-dubbo-check>
<label for=m-enblog20180814generic-invoke-of-dubbo-check><a href=/en/blog/2018/08/14/generic-invoke-of-dubbo/ title="Generic invoke of Dubbo" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814generic-invoke-of-dubbo><span>Generic invoke</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180814native-image-using-graalvm-li><input type=checkbox id=m-enblog20180814native-image-using-graalvm-check>
<label for=m-enblog20180814native-image-using-graalvm-check><a href=/en/blog/2018/08/14/native-image-using-graalvm/ title="Native Image using GraalVM" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180814native-image-using-graalvm><span>Native Image</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180810dubbos-load-balance-li><input type=checkbox id=m-enblog20180810dubbos-load-balance-check>
<label for=m-enblog20180810dubbos-load-balance-check><a href=/en/blog/2018/08/10/dubbos-load-balance/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180810dubbos-load-balance><span>Dubbo's Load Balance</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180807use-annotations-in-dubbo-li><input type=checkbox id=m-enblog20180807use-annotations-in-dubbo-check>
<label for=m-enblog20180807use-annotations-in-dubbo-check><a href=/en/blog/2018/08/07/use-annotations-in-dubbo/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180807use-annotations-in-dubbo><span>Use Annotations In Dubbo</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180807using-zookeeper-in-dubbo-li><input type=checkbox id=m-enblog20180807using-zookeeper-in-dubbo-check>
<label for=m-enblog20180807using-zookeeper-in-dubbo-check><a href=/en/blog/2018/08/07/using-zookeeper-in-dubbo/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180807using-zookeeper-in-dubbo><span>Using Zookeeper in Dubbo</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180807dubbo-101-li><input type=checkbox id=m-enblog20180807dubbo-101-check>
<label for=m-enblog20180807dubbo-101-check><a href=/en/blog/2018/08/07/dubbo-101/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180807dubbo-101><span>Your First Dubbo Demo</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180730the-third-dubbo-meetup-has-been-held-in-shenzhen-li><input type=checkbox id=m-enblog20180730the-third-dubbo-meetup-has-been-held-in-shenzhen-check>
<label for=m-enblog20180730the-third-dubbo-meetup-has-been-held-in-shenzhen-check><a href=/en/blog/2018/07/30/the-third-dubbo-meetup-has-been-held-in-shenzhen/ title="The third Dubbo meetup has been held in Shenzhen" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180730the-third-dubbo-meetup-has-been-held-in-shenzhen><span>The third Dubbo meetup</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180727sentinel-the-flow-sentinel-of-dubbo-services-li><input type=checkbox id=m-enblog20180727sentinel-the-flow-sentinel-of-dubbo-services-check>
<label for=m-enblog20180727sentinel-the-flow-sentinel-of-dubbo-services-check><a href=/en/blog/2018/07/27/sentinel-the-flow-sentinel-of-dubbo-services/ title="Sentinel: The flow sentinel of Dubbo services" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180727sentinel-the-flow-sentinel-of-dubbo-services><span>Introduce sentinel</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180712tracking-with-pinpoint-li><input type=checkbox id=m-enblog20180712tracking-with-pinpoint-check>
<label for=m-enblog20180712tracking-with-pinpoint-check><a href=/en/blog/2018/07/12/tracking-with-pinpoint/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180712tracking-with-pinpoint><span>Tracking with Pinpoint</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180701your-first-dubbo-filter-li><input type=checkbox id=m-enblog20180701your-first-dubbo-filter-check>
<label for=m-enblog20180701your-first-dubbo-filter-check><a href=/en/blog/2018/07/01/your-first-dubbo-filter/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180701your-first-dubbo-filter><span>Your First Dubbo Filter</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180623the-second-dubbo-shanghai-meetup-has-been-held-successfully-li><input type=checkbox id=m-enblog20180623the-second-dubbo-shanghai-meetup-has-been-held-successfully-check>
<label for=m-enblog20180623the-second-dubbo-shanghai-meetup-has-been-held-successfully-check><a href=/en/blog/2018/06/23/the-second-dubbo-shanghai-meetup-has-been-held-successfully/ title="The second Dubbo Shanghai meetup has been held successfully" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180623the-second-dubbo-shanghai-meetup-has-been-held-successfully><span>The second Dubbo meetup</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180512the-first-dubbo-meetup-has-been-held-in-beijing-li><input type=checkbox id=m-enblog20180512the-first-dubbo-meetup-has-been-held-in-beijing-check>
<label for=m-enblog20180512the-first-dubbo-meetup-has-been-held-in-beijing-check><a href=/en/blog/2018/05/12/the-first-dubbo-meetup-has-been-held-in-beijing/ title="The first Dubbo meetup has been held in Beijing" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180512the-first-dubbo-meetup-has-been-held-in-beijing><span>The first Dubbo meetup</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180502the-apachecon-na-schedule-has-been-announced-li><input type=checkbox id=m-enblog20180502the-apachecon-na-schedule-has-been-announced-check>
<label for=m-enblog20180502the-apachecon-na-schedule-has-been-announced-check><a href=/en/blog/2018/05/02/the-apachecon-na-schedule-has-been-announced/ title="The ApacheCon NA schedule has been announced" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180502the-apachecon-na-schedule-has-been-announced><span>ApacheCon NA</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180425the-gsocgoogle-summer-of-code-2018-li><input type=checkbox id=m-enblog20180425the-gsocgoogle-summer-of-code-2018-check>
<label for=m-enblog20180425the-gsocgoogle-summer-of-code-2018-check><a href=/en/blog/2018/04/25/the-gsocgoogle-summer-of-code-2018/ title="The GSoC(Google Summer of Code) 2018" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180425the-gsocgoogle-summer-of-code-2018><span>GSoC 2018</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20180422dubbo-roadmap-is-announced-in-qcon-beijing-2018-li><input type=checkbox id=m-enblog20180422dubbo-roadmap-is-announced-in-qcon-beijing-2018-check>
<label for=m-enblog20180422dubbo-roadmap-is-announced-in-qcon-beijing-2018-check><a href=/en/blog/2018/04/22/dubbo-roadmap-is-announced-in-qcon-beijing-2018/ title="Dubbo roadmap is announced in QCon Beijing 2018" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20180422dubbo-roadmap-is-announced-in-qcon-beijing-2018><span>QCon Beijing 2018</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-enblogproposals-li><input type=checkbox id=m-enblogproposals-check>
<label for=m-enblogproposals-check><a href=/en/blog/proposals/ title="Proposals About Apache Dubbo" class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-enblogproposals><span>Proposals</span></a></label><ul class="ul-2 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog10101application-level-service-discovery-li><input type=checkbox id=m-enblog10101application-level-service-discovery-check>
<label for=m-enblog10101application-level-service-discovery-check><a href=/en/blog/1/01/01/application-level-service-discovery/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog10101application-level-service-discovery><span>Application-Level Service Discovery</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog10101enhanced-http-standard-capabilities-of-triple-protocol-li><input type=checkbox id=m-enblog10101enhanced-http-standard-capabilities-of-triple-protocol-check>
<label for=m-enblog10101enhanced-http-standard-capabilities-of-triple-protocol-check><a href=/en/blog/1/01/01/enhanced-http-standard-capabilities-of-triple-protocol/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog10101enhanced-http-standard-capabilities-of-triple-protocol><span>Enhanced HTTP Standard Capabilities of Triple Protocol</span></a></label></li></ul></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id=m-enblogreleases-li><input type=checkbox id=m-enblogreleases-check>
<label for=m-enblogreleases-check><a href=/en/blog/releases/ title="New Releases" class="align-left pl-0 td-sidebar-link td-sidebar-link__section" id=m-enblogreleases><span>Releases</span></a></label><ul class="ul-2 foldable"><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog202109202714-release-note-li><input type=checkbox id=m-enblog202109202714-release-note-check>
<label for=m-enblog202109202714-release-note-check><a href=/en/blog/2021/09/20/2.7.14-release-note/ title="2.7.14 Release Note" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog202109202714-release-note><span>2.7.14</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog202108233021-release-note-li><input type=checkbox id=m-enblog202108233021-release-note-check>
<label for=m-enblog202108233021-release-note-check><a href=/en/blog/2021/08/23/3.0.2.1-release-note/ title="3.0.2.1 Release Note" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog202108233021-release-note><span>3.0.2.1</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20210818302-release-note-li><input type=checkbox id=m-enblog20210818302-release-note-check>
<label for=m-enblog20210818302-release-note-check><a href=/en/blog/2021/08/18/3.0.2-release-note/ title="3.0.2 Release Note" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20210818302-release-note><span>3.0.2</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20210702301-release-note-li><input type=checkbox id=m-enblog20210702301-release-note-check>
<label for=m-enblog20210702301-release-note-check><a href=/en/blog/2021/07/02/3.0.1-release-note/ title="3.0.1 Release Note" class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20210702301-release-note><span>3.0.1</span></a></label></li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id=m-enblog20200518past-releases-li><input type=checkbox id=m-enblog20200518past-releases-check>
<label for=m-enblog20200518past-releases-check><a href=/en/blog/2020/05/18/past-releases/ class="align-left pl-0 td-sidebar-link td-sidebar-link__page" id=m-enblog20200518past-releases><span>Past Releases</span></a></label></li></ul></li></ul></li></ul></nav></div></div><main class="col-12 col-md-9 col-xl-8 pl-md-5" role=main><nav aria-label=breadcrumb class=td-breadcrumbs><ol class=breadcrumb><li class=breadcrumb-item><a href=https://cn.dubbo.apache.org/en/blog/>Blog</a></li><li class=breadcrumb-item><a href=https://cn.dubbo.apache.org/en/blog/news/>Articles</a></li><li class="breadcrumb-item active" aria-current=page><a href=https://cn.dubbo.apache.org/en/blog/2018/08/14/source-code-analysis-of-spring-boot-dubbo-app-start-and-stop/ aria-disabled=true class="btn-link disabled">Dubbo start/stop in spring boot</a></li></ol></nav><section id=deprecation-warning><div class="content deprecation-warning pageinfo outdated-blog"><p>This article is more than one year old. Older articles may contain outdated content. Check that the information in the page has not become incorrect since its publication.</p></div></section><div class=td-content><h1>Source code analysis of spring-boot+Dubbo App start and stop</h1><div class=lead>This article introduces the implementation details of app start and stop in <code>dubbo-spring-boot-project</code>.</div><div class="td-byline mb-4"><time datetime=2018-08-14 class=text-muted>Tuesday, August 14, 2018</time></div><header class=article-meta></header><h2 id=introduction>Introduction</h2><p><a href=https://github.com/apache/dubbo-spring-boot-project>Dubbo Spring Boot</a> project is dedicated to simplifying the development of the Dubbo RPC framework in the Spring Boot application. It also integrates the feature of Spring Boot:</p><ul><li><a href=https://github.com/apache/dubbo-spring-boot-project/blob/master/dubbo-spring-boot-autoconfigure>Autoconfigure</a> (ex: Annotation driver, Autoconfigure, etc.)</li><li><a href=https://github.com/apache/dubbo-spring-boot-project/blob/master/dubbo-spring-boot-actuator>Production-Ready</a> (ex: Security, Healthy check, Externalize configuration, etc.)</li></ul><h2 id=the-analysis-of-dubboconsumer-startup>The analysis of DubboConsumer startup</h2><p>Have you ever thought about this : since the <code>DubboConsumerDemo</code> application in <code>dubbo-spring-boot-project</code> has only one line of code, why not just exit directly when the <code>main</code> method is executed?</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>@SpringBootApplication</span>(scanBasePackages <span style=color:#719e07>=</span> <span style=color:#2aa198>&#34;com.alibaba.boot.dubbo.demo.consumer.controller&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#268bd2>class</span> <span style=color:#268bd2>DubboConsumerDemo</span> {
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#268bd2>static</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>main</span>(String<span style=color:#719e07>[]</span> args) {
</span></span><span style=display:flex><span> SpringApplication.run(DubboConsumerDemo.class,args);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>}
</span></span></code></pre></div><p>In fact, to answer this question, we need to abstract it first, that is, under what circumstances will a JVM process exit?</p><p>Take Java 8 as an example. By referring to the JVM language specification[1], there is a clear description in Section 12.8:</p><blockquote><p>A program terminates all its activity and <em>exits</em> when one of two things happens:</p><ul><li>All the threads that are not daemon threads terminate.</li><li>Some thread invokes the <code>exit</code> method of class <code>Runtime</code> or class <code>System</code>, and the <code>exit</code> operation is not forbidden by the security manager.</li></ul></blockquote><p>Therefore, in view of the above situation, we judge that there must be some non-daemon thread not exiting. All thread information can be seen by <code>jstack</code>, including whether they are daemon threads, and <code>jstack</code> can be used to find out which threads are non-daemon.</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-sh data-lang=sh><span style=display:flex><span>➜ jstack <span style=color:#2aa198>57785</span> | grep tid | grep -v <span style=color:#2aa198>&#34;daemon&#34;</span>
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;container-0&#34;</span> <span style=color:#586e75>#37 prio=5 os_prio=31 tid=0x00007fbe312f5800 nid=0x7103 waiting on condition [0x0000700010144000]</span>
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;container-1&#34;</span> <span style=color:#586e75>#49 prio=5 os_prio=31 tid=0x00007fbe3117f800 nid=0x7b03 waiting on condition [0x0000700010859000]</span>
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;DestroyJavaVM&#34;</span> <span style=color:#586e75>#83 prio=5 os_prio=31 tid=0x00007fbe30011000 nid=0x2703 waiting on condition [0x0000000000000000]</span>
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;VM Thread&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe3005e800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x3703 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;GC Thread#0&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe30013800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x5403 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;GC Thread#1&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe30021000 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x5303 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;GC Thread#2&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe30021800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x2d03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;GC Thread#3&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe30022000 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x2f03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Main Marker&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe30040800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x5203 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Conc#0&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe30041000 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x4f03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Refine#0&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe31044800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x4e03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Refine#1&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe31045800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x4d03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Refine#2&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe31046000 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x4c03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Refine#3&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe31047000 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x4b03 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;G1 Young RemSet Sampling&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe31047800 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x3603 runnable
</span></span><span style=display:flex><span><span style=color:#2aa198>&#34;VM Periodic Task Thread&#34;</span> <span style=color:#268bd2>os_prio</span><span style=color:#719e07>=</span><span style=color:#2aa198>31</span> <span style=color:#268bd2>tid</span><span style=color:#719e07>=</span>0x00007fbe31129000 <span style=color:#268bd2>nid</span><span style=color:#719e07>=</span>0x6703 waiting on condition
</span></span></code></pre></div><blockquote><p>We can find all the thread digests by <code>grep tid</code> here, and find the line that doesn&rsquo;t contain the daemon keyword by <code>grep -v</code> command.</p></blockquote><p>We can get some information from the above results:</p><ul><li>There are two &ldquo;suspicious&rdquo; threads : <code>container-0</code>, <code>container-1</code>. They are non-daemon thread in wait state.</li><li>There are alse some threads about GC, and threads that start with <code>VM</code>. They are also some non-daemon threads, but they are most likely the JVM&rsquo;s own threads, which we can ignore for now.</li></ul><p>In summary, we can infer that it is likely that the <code>container-0</code> and <code>container-1</code> cause the JVM to not exit. Now let&rsquo;s search through the source code to find out who created the two threads.</p><p>By the source code analysis of Spring-boot, we can find these code in the <code>startDaemonAwaitThread</code> method of <code>org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer</code>.</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span> <span style=color:#268bd2>private</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>startDaemonAwaitThread</span>() {
</span></span><span style=display:flex><span> Thread awaitThread <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> Thread(<span style=color:#2aa198>&#34;container-&#34;</span> <span style=color:#719e07>+</span> (containerCounter.get())) {
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>run</span>() {
</span></span><span style=display:flex><span> TomcatEmbeddedServletContainer.this.tomcat.getServer().await();
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span> };
</span></span><span style=display:flex><span> awaitThread.setContextClassLoader(getClass().getClassLoader());
</span></span><span style=display:flex><span> awaitThread.setDaemon(<span style=color:#cb4b16>false</span>);
</span></span><span style=display:flex><span> awaitThread.start();
</span></span><span style=display:flex><span> }
</span></span></code></pre></div><p>Let&rsquo;s add a breakpoint in this method, and focus on the call stack:</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-plain data-lang=plain><span style=display:flex><span>initialize:115, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
</span></span><span style=display:flex><span>&lt;init&gt;:84, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
</span></span><span style=display:flex><span>getTomcatEmbeddedServletContainer:554, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat)
</span></span><span style=display:flex><span>getEmbeddedServletContainer:179, TomcatEmbeddedServletContainerFactory (org.springframework.boot.context.embedded.tomcat)
</span></span><span style=display:flex><span>createEmbeddedServletContainer:164, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
</span></span><span style=display:flex><span>onRefresh:134, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
</span></span><span style=display:flex><span>refresh:537, AbstractApplicationContext (org.springframework.context.support)
</span></span><span style=display:flex><span>refresh:122, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
</span></span><span style=display:flex><span>refresh:693, SpringApplication (org.springframework.boot)
</span></span><span style=display:flex><span>refreshContext:360, SpringApplication (org.springframework.boot)
</span></span><span style=display:flex><span>run:303, SpringApplication (org.springframework.boot)
</span></span><span style=display:flex><span>run:1118, SpringApplication (org.springframework.boot)
</span></span><span style=display:flex><span>run:1107, SpringApplication (org.springframework.boot)
</span></span><span style=display:flex><span>main:35, DubboConsumerDemo (com.alibaba.boot.dubbo.demo.consumer.bootstrap)
</span></span></code></pre></div><p>It can be seen that during the startup process of the Spring-boot application, the above method is executed since the execution of Tomcat exposes the HTTP service by default. Also, all threads started by Tomcat are daemon threads by default, such as the Acceptor of the listening request, threads in working threads, etc. Thus the JVM will also exit after the startup is complete in there is no extra control here. Therefore, it is necessary to explicitly start a thread and continue to wait under certain conditions, thereby avoid thread exit.</p><p>Let&rsquo;s dig deeper to find out how the thread stay alive in Tomcat&rsquo;s <code>this.tomcat.getServer().await()</code> method.</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span><span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>await</span>() {
</span></span><span style=display:flex><span> <span style=color:#586e75>// ...</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span>( port<span style=color:#719e07>==-</span>1 ) {
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> {
</span></span><span style=display:flex><span> awaitThread <span style=color:#719e07>=</span> Thread.currentThread();
</span></span><span style=display:flex><span> <span style=color:#719e07>while</span>(<span style=color:#719e07>!</span>stopAwait) {
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> {
</span></span><span style=display:flex><span> Thread.sleep( 10000 );
</span></span><span style=display:flex><span> } <span style=color:#719e07>catch</span>( InterruptedException ex ) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// continue and check the flag</span>
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> } <span style=color:#719e07>finally</span> {
</span></span><span style=display:flex><span> awaitThread <span style=color:#719e07>=</span> <span style=color:#cb4b16>null</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> <span style=color:#719e07>return</span>;
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> <span style=color:#586e75>// ...</span>
</span></span><span style=display:flex><span> }
</span></span></code></pre></div><p>In the await method, the current thread checks the variable <code>stopAwait</code> every 10 seconds in a while loop. It is a <code>volatile</code> variable that is used to ensure that the current thread can see the change immediately after the variable being modified by another thread. If there is no change, it will stay in the loop. This is the reason why the thread does not exit, which is also the reason that the entire Spring-boot application doesn&rsquo;t exit.</p><p>Since Spring-boot application enables port 8080 and 8081(management port) at the same time, there are actually two Tomcats. So there are two threads named <code>container-0</code> and <code>container-1</code>.</p><p>Next, let&rsquo;s see how this Spring-boot application exits.</p><h2 id=the-analysis-of-dubboconsumer-exit>The analysis of DubboConsumer exit</h2><p>As mentioned in the previous description, there is a thread that checks the variable <code>stopAwait</code> continuously. So there must be a thread to modify <code>stopAwait</code> at Stop, thus break the while loop. But who is modifying this variable?</p><p>By analyzing the source code, we can see that there is only one method that modifies <code>stopAwait</code> : <code>org.apache.catalina.core.StandardServer#stopAwait</code>. To figure out who is calling this method, we add a breakpoint here.</p><blockquote><p>Note that after adding a breakpoint in Intellij IDEA&rsquo;s Debug mode, we also need to type <code>kill -s INT $PID</code> or <code>kill -s TERM $PID</code> in command line to trigger the breakpoint. Due to buggy IDEA, a single click to the stop button won&rsquo;t trigger the breakpoint.</p></blockquote><p>You can see the method is called by a thread called <code>Thread-3</code>:</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span>stopAwait:390, StandardServer (org.apache.catalina.core)
</span></span><span style=display:flex><span>stopInternal:819, StandardServer (org.apache.catalina.core)
</span></span><span style=display:flex><span>stop:226, LifecycleBase (org.apache.catalina.util)
</span></span><span style=display:flex><span>stop:377, Tomcat (org.apache.catalina.startup)
</span></span><span style=display:flex><span>stopTomcat:241, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
</span></span><span style=display:flex><span>stop:295, TomcatEmbeddedServletContainer (org.springframework.boot.context.embedded.tomcat)
</span></span><span style=display:flex><span>stopAndReleaseEmbeddedServletContainer:306, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
</span></span><span style=display:flex><span>onClose:155, EmbeddedWebApplicationContext (org.springframework.boot.context.embedded)
</span></span><span style=display:flex><span>doClose:1014, AbstractApplicationContext (org.springframework.context.support)
</span></span><span style=display:flex><span>run:929, AbstractApplicationContext$2 (org.springframework.context.support)
</span></span></code></pre></div><p>Through source code analysis, it was executed by Spring&rsquo;s registered <code>ShutdownHook</code>.</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>registerShutdownHook</span>() {
</span></span><span style=display:flex><span> <span style=color:#719e07>if</span> (<span style=color:#719e07>this</span>.shutdownHook <span style=color:#719e07>==</span> <span style=color:#cb4b16>null</span>) {
</span></span><span style=display:flex><span> <span style=color:#586e75>// No shutdown hook registered yet.</span>
</span></span><span style=display:flex><span> <span style=color:#719e07>this</span>.shutdownHook <span style=color:#719e07>=</span> <span style=color:#719e07>new</span> Thread() {
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>run</span>() {
</span></span><span style=display:flex><span> <span style=color:#268bd2>synchronized</span> (startupShutdownMonitor) {
</span></span><span style=display:flex><span> doClose();
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> };
</span></span><span style=display:flex><span> Runtime.getRuntime().addShutdownHook(<span style=color:#719e07>this</span>.shutdownHook);
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span></code></pre></div><p>By reffering the Java API documentation[2], we found that ShutdownHook will be executed under the following two cases.</p><blockquote><p>The Java virtual machine <em>shuts down</em> in response to two kinds of events:</p><ul><li>The program <em>exits</em> normally, when the last non-daemon thread exits or when the <code>exit</code> (equivalently, <a href=https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#exit-int-><code>System.exit</code></a>) method is invoked, or</li><li>The virtual machine is <em>terminated</em> in response to a user interrupt, such as typing <code>^C</code>, or a system-wide event, such as user logoff or system shutdown.</li></ul></blockquote><ol><li>So it&rsquo;s either a call of <code>System.exit()</code></li><li>Respond to external signals, such as Ctrl+C(actually sent as SIGINT signal), or <code>SIGTERM</code> signal (<code>kill $PID</code> will send <code>SIGTERM</code> signal by default)</li></ol><p>Therefore, the normal application will execute the above ShutdownHook during the stop process (except <code>kill -9 $PID</code>). Its function is not only to close the Tomcat, but also to perform other cleanup work. It is unnecessary to go into details.</p><h2 id=summary>Summary</h2><ol><li>During the startup of <code>DubboConsumer</code>, an independent non-daemon thread is launched to query the status of the variable continuously, thus the process can&rsquo;t exit.</li><li>To stop the <code>DubboConsumer</code>, one should call ShutdownHook to change the variable to let the thread break the loop.</li></ol><h2 id=problems>Problems</h2><p>In the example of DubboProvider, we see that Provider doesn&rsquo;t start Tomcat to provide HTTP service, then how does the program stays alive without exiting? We will answer this question in the next article.</p><h3 id=notice>Notice</h3><p>By running the following unit test which create a thread in <code>Intellij IDEA</code> , we are surprised to find that the program exits with less than 1000s. Why?(The thread being created is a non-daemon thread)</p><div class=highlight><pre tabindex=0 style=color:#93a1a1;background-color:#002b36;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-java data-lang=java><span style=display:flex><span> <span style=color:#268bd2>@Test</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>test</span>() {
</span></span><span style=display:flex><span> <span style=color:#719e07>new</span> Thread(<span style=color:#719e07>new</span> Runnable() {
</span></span><span style=display:flex><span> <span style=color:#268bd2>@Override</span>
</span></span><span style=display:flex><span> <span style=color:#268bd2>public</span> <span style=color:#dc322f>void</span> <span style=color:#268bd2>run</span>() {
</span></span><span style=display:flex><span> <span style=color:#719e07>try</span> {
</span></span><span style=display:flex><span> Thread.sleep(1000000);
</span></span><span style=display:flex><span> } <span style=color:#719e07>catch</span> (InterruptedException e) {
</span></span><span style=display:flex><span> e.printStackTrace();
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }
</span></span><span style=display:flex><span> }).start();
</span></span><span style=display:flex><span> }
</span></span></code></pre></div><p>[1] <a href=https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8>https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8</a></p><p>[2] <a href=https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook>https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook</a></p><ul class="list-unstyled d-flex justify-content-between align-items-center mb-0 pt-5"><li><a href=/en/blog/2018/08/14/implementation-of-cross-language-calls-by-dubbo2.js/ aria-label="Previous - Implementation of cross-language calls by Dubbo2.js" class="btn btn-primary"><span class=mr-1>←</span>Previous</a></li><li><a href=/en/blog/2018/08/14/manipulating-services-dynamically-via-qos/ aria-label="Next - Manipulating Services Dynamically via QoS" class="btn btn-primary">Next<span class=ml-1>β†’</span></a></li></ul></div><div id=pre-footer><h2>Feedback</h2><p class=feedback--prompt>Was this page helpful?</p><button class="btn btn-primary mb-4 feedback--yes">Yes</button>
<button class="btn btn-primary mb-4 feedback--no">No</button></div><script>const yes=document.querySelector(".feedback--yes"),no=document.querySelector(".feedback--no");document.querySelectorAll(".feedback--link").forEach(e=>{e.href=e.href+window.location.pathname});const sendFeedback=e=>{gtag||console.log("!gtag"),gtag("event","click",{event_category:"Helpful",event_label:window.location.pathname,value:e})},disableButtons=()=>{yes.disabled=!0,yes.classList.add("feedback--button__disabled"),no.disabled=!0,no.classList.add("feedback--button__disabled")};yes.addEventListener("click",()=>{sendFeedback(1),disableButtons(),document.querySelector(".feedback--response").classList.remove("feedback--response__hidden")}),no.addEventListener("click",()=>{sendFeedback(0),disableButtons(),document.querySelector(".feedback--response").classList.remove("feedback--response__hidden")})</script></main><div class="d-none d-xl-block col-xl-2 td-toc d-print-none"><div class="td-page-meta ml-2 pb-1 pt-2 mb-0"><a href=https://github.com/apache/dubbo-website/edit/master/content/en/blog/news/spring-boot-dubbo-start-stop-analysis.md target=_blank><i class="fa fa-edit fa-fw"></i> Edit this page</a>
<a href="https://github.com/apache/dubbo-website/new/master/content/en/blog/news/spring-boot-dubbo-start-stop-analysis.md?filename=change-me.md&amp;value=---%0Atitle%3A+%22Long+Page+Title%22%0AlinkTitle%3A+%22Short+Nav+Title%22%0Aweight%3A+100%0Adescription%3A+%3E-%0A+++++Page+description+for+heading+and+indexes.%0A---%0A%0A%23%23+Heading%0A%0AEdit+this+template+to+create+your+new+page.%0A%0A%2A+Give+it+a+good+name%2C+ending+in+%60.md%60+-+e.g.+%60getting-started.md%60%0A%2A+Edit+the+%22front+matter%22+section+at+the+top+of+the+page+%28weight+controls+how+its+ordered+amongst+other+pages+in+the+same+directory%3B+lowest+number+first%29.%0A%2A+Add+a+good+commit+message+at+the+bottom+of+the+page+%28%3C80+characters%3B+use+the+extended+description+field+for+more+detail%29.%0A%2A+Create+a+new+branch+so+you+can+preview+your+new+file+and+request+a+review+via+Pull+Request.%0A" target=_blank><i class="fa fa-edit fa-fw"></i> Create child page</a>
<a href="https://github.com/apache/dubbo-website/issues/new?title=Source%20code%20analysis%20of%20spring-boot+Dubbo%20App%20start%20and%20stop" target=_blank><i class="fab fa-github fa-fw"></i> Create an issue</a>
<a href=https://github.com/apache/dubbo/issues/new target=_blank><i class="fas fa-tasks fa-fw"></i> Create project issue</a></div><nav id=TableOfContents><ul><li><a href=#introduction>Introduction</a></li><li><a href=#the-analysis-of-dubboconsumer-startup>The analysis of DubboConsumer startup</a></li><li><a href=#the-analysis-of-dubboconsumer-exit>The analysis of DubboConsumer exit</a></li><li><a href=#summary>Summary</a></li><li><a href=#problems>Problems</a><ul><li><a href=#notice>Notice</a></li></ul></li></ul></nav><div class="taxonomy taxonomy-terms-cloud taxo-tags"><h5 class=taxonomy-title>Tags</h5><ul class=taxonomy-terms><li><a class=taxonomy-term href=https://cn.dubbo.apache.org/en/tags/ecosystem/ data-taxonomy-term=ecosystem><span class=taxonomy-label>ecosystem</span><span class=taxonomy-count>1</span></a></li><li><a class=taxonomy-term href=https://cn.dubbo.apache.org/en/tags/news/ data-taxonomy-term=news><span class=taxonomy-label>news</span><span class=taxonomy-count>1</span></a></li><li><a class=taxonomy-term href=https://cn.dubbo.apache.org/en/tags/opentelemetry/ data-taxonomy-term=opentelemetry><span class=taxonomy-label>OpenTelemetry</span><span class=taxonomy-count>1</span></a></li><li><a class=taxonomy-term href=https://cn.dubbo.apache.org/en/tags/tracing/ data-taxonomy-term=tracing><span class=taxonomy-label>tracing</span><span class=taxonomy-count>1</span></a></li></ul></div></div></div></div></div><footer class="bg-dark py-5 row d-print-none footer-margin-0"><div class="container-fluid mx-sm-5"><div class=row><div class="col-6 col-sm-4 text-xs-center order-sm-2"><ul class="list-inline mb-0"><li class="list-inline-item mx-2 h3" data-toggle=tooltip data-placement=top title="Dubbo mailing list archive" aria-label="Dubbo mailing list archive"><a class=text-white target=_blank rel="noopener noreferrer" href=https://lists.apache.org/list.html?dev@dubbo.apache.org><i class="fa fa-envelope"></i></a></li></ul></div><div class="col-6 col-sm-4 text-right text-xs-center order-sm-3"><ul class="list-inline mb-0"><li class="list-inline-item mx-2 h3" data-toggle=tooltip data-placement=top title=GitHub aria-label=GitHub><a class=text-white target=_blank rel="noopener noreferrer" href=https://github.com/apache/dubbo><i class="fab fa-github"></i></a></li><li class="list-inline-item mx-2 h3" data-toggle=tooltip data-placement=top title="Subscribe to mailing list" aria-label="Subscribe to mailing list"><a class=text-white target=_blank rel="noopener noreferrer" href=mailto:dev-subscribe@dubbo.apache.org><i class="fa fa-envelope"></i></a></li></ul></div><div class="col-12 col-sm-4 text-center py-2 order-sm-2"><small class=text-white>&copy; 2024 The Apache Software Foundation. Apache and the Apache feather logo are trademarks of The Apache Software Foundation. All Rights Reserved</small></div></div></div></footer><div class="row pt-2 pb-2 footer-margin-0"><div class="container-fluid mx-sm-5"><div class=text-center id=my-footer><img alt=apache_logo src=/imgs/apache_logo.png><ul><li><a href=https://www.apache.org>Foundation</a></li><li><a href=https://www.apache.org/licenses/>License</a></li><li><a href=https://dubbo.apache.org/en/overview/notices/>Security</a></li><li><a href=https://www.apache.org/events/current-event>Events</a></li><li><a href=https://www.apache.org/foundation/sponsorship.html>Sponsorship</a></li><li><a href=https://privacy.apache.org/policies/privacy-policy-public.html>Privacy</a></li><li><a href=https://www.apache.org/foundation/thanks.html>Thanks</a></li></ul></div></div></div><script src=/js/popper.min.js integrity=sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49 crossorigin=anonymous></script><script src=/js/bootstrap.min.js integrity=sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy crossorigin=anonymous></script><script src=/js/main.min.b075178d232d3b0039b3cb6af2fc2e9d90071820167a60f4eea3a79169975ee8.js integrity="sha256-sHUXjSMtOwA5s8tq8vwunZAHGCAWemD07qOnkWmXXug=" crossorigin=anonymous></script><script async src=https://widget.kapa.ai/kapa-widget.bundle.js data-website-id=d763c4f2-f871-400b-aeca-d986c4af73c2 data-project-name="Apache Dubbo" data-project-color=#E8442E data-button-text="Ask AI" data-search-mode-enabled=true data-modal-open-on-command-k=true data-modal-disclaimer="The AI supports multiple languages, but it may not be accessible in China due to recaptcha, a proxy is required." data-project-logo=https://pbs.twimg.com/profile_images/1011849068283191302/FJbH5vbF_400x400.jpg data-modal-example-questions="What is Apache Dubbo?,How to run Apache Dubbo?" data-button-position-top data-button-position-right=20px data-button-position-bottom=200px data-button-position-left></script><script>(function(e,t,n,s){e[s]=e[s]||[];var a=t.getElementsByTagName(n)[0],i=t.createElement(n);i.async=!0,i.id="beacon-aplus",i.setAttribute("exparams","userid=&aplus&sidx=aplusSidex&ckx=aplusCkx"),i.src="//g.alicdn.com/alilog/mlog/aplus_v2.js",i.crossorigin="anonymous",a.parentNode.insertBefore(i,a)})(window,document,"script","aplus_queue"),function(e){var t=e.createElement("script");t.type="text/javascript",t.async=!0,t.src="//g.alicdn.com/aes/??tracker/3.3.4/index.js,tracker-plugin-pv/3.0.5/index.js,tracker-plugin-event/3.0.0/index.js,tracker-plugin-autolog/3.0.3/index.js,tracker-plugin-survey/3.0.3/index.js,tracker-plugin-jserror/3.0.3/index.js,tracker-plugin-resourceError/3.0.3/index.js",t.onload=function(){window.AES_CONFIG=window.AES_CONFIG||{env:"prod"},window.aes=new AES({pid:"zN245h",user_type:6}),window.AESPluginAutologConfig={exposure:"auto"},window.AEMPluginInstances=[aes.use(AESPluginPV,window.AESPluginPVConfig||{enableHistory:!0}),aes.use(AESPluginEvent,window.AESPluginEventConfig||{}),aes.use(AESPluginSurvey,window.AESPluginEventConfig||{}),aes.use(AESPluginAutolog,window.AESPluginAutologConfig||{}),aes.use(AESPluginJSError,window.AESPluginJSError||{}),aes.use(AESPluginResourceError,window.AESPluginResourceError||{})]},setTimeout(function(){e.getElementsByTagName("body")[0].appendChild(t)},800)}(document)</script></body></html>