OnWXWWPPXX (function() { window.appData = JSON.parse(decodeURIComponent(“%7B%22me%22%3A%7B%22work_id%22%3A%22222822%22%2C%22avatar_url%22%3A%22https%3A%2F%2Fyuque.antfin-inc.com%2Fr%2Favatar_buc%2F222822%22%2C%22isActive%22%3Atrue%2C%22isInactive%22%3Afalse%2C%22isDeactivated%22%3Afalse%2C%22isTerminated%22%3Afalse%2C%22isBanned%22%3Afalse%2C%22isBlocked%22%3Afalse%2C%22isMuted%22%3Afalse%2C%22isExtcontact%22%3Afalse%2C%22email%22%3A%22gui**%40alibaba-inc.com%22%2C%22mobile%22%3A%22%22%2C%22isPaid%22%3Afalse%2C%22hasPaidBefore%22%3Afalse%2C%22id%22%3A224034%2C%22space_id%22%3A0%2C%22type%22%3A%22User%22%2C%22login%22%3A%22guiling.cyt%22%2C%22name%22%3A%22%E9%AC%BC%E7%81%B5%22%2C%22description%22%3Anull%2C%22avatar%22%3Anull%2C%22owner_id%22%3Anull%2C%22topics_count%22%3A0%2C%22public_topics_count%22%3A0%2C%22members_count%22%3A0%2C%22books_count%22%3A4%2C%22public_books_count%22%3A2%2C%22followers_count%22%3A1%2C%22following_count%22%3A0%2C%22account_id%22%3Anull%2C%22role%22%3A1%2C%22status%22%3A1%2C%22public%22%3A1%2C%22wants_email%22%3Atrue%2C%22wants_marketing_email%22%3Atrue%2C%22topic_updated_at_ms%22%3A0%2C%22deleted_slug%22%3Anull%2C%22language%22%3A%22zh-cn%22%2C%22organization_id%22%3A0%2C%22emp_type%22%3A%22%E6%AD%A3%E5%BC%8F%20-%20%E6%AD%A3%E5%BC%8F%E5%91%98%E5%B7%A5%22%2C%22group_department_updated_at%22%3Anull%2C%22member_level%22%3Anull%2C%22expired_at%22%3Anull%2C%22scene%22%3Anull%2C%22source%22%3Anull%2C%22max_member%22%3Anull%2C%22created_at%22%3A%222019-06-27T05%3A08%3A48.000Z%22%2C%22updated_at%22%3A%222021-04-12T07%3A50%3A11.000Z%22%2C%22grains_sum%22%3A34%2C%22punish_expired_at%22%3Anull%2C%22deleted_at%22%3Anull%2C%22hasPassword%22%3Atrue%2C%22canCreateOrg%22%3Atrue%2C%22hasJoinedQuan%22%3Atrue%2C%22is_admin%22%3Afalse%7D%2C%22settings%22%3A%7B%22head_html%22%3A%22%3Clink%20href%3D%5C%22https%3A%2F%2Fgw.alipayobjects.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fmdap.alipay.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fcdn.nlark.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fcdn.yuque.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fkcart.alipay.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fcdn-pri.nlark.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fg.yuque.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fmdap.yuque.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fintranetproxy.alipay.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fyuque.alibaba-inc.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%5Cn%3Clink%20href%3D%5C%22https%3A%2F%2Fyuque.antfin-inc.com%5C%22%20rel%3D%5C%22dns-prefetch%5C%22%20%2F%3E%22%2C%22disable_quan%22%3Afalse%2C%22quan_nav_list_ids%22%3A%5B%22300001%22%2C%22100001%22%2C%22100002%22%5D%2C%22footer_html%22%3A%22%3Cscript%3E%20window.addEventListener(‘load’%2C%20function()%20%7B%20var%20secScript%20%3D%20document.createElement(‘script’)%3B%20secScript.src%20%3D%20’https%3A%2F%2Frender.alipay.com%2Fp%2Fs%2Fofficerd%2Findex.js’%3B%20document.body.appendChild(secScript)%3B%20%7D)%3B%20%3C%2Fscript%3E%22%2C%22watermark_enable%22%3A%22%22%2C%22home_aside_html%22%3A%22%22%2C%22index_banner_html%22%3A%22%22%2C%22doc_banner_html%22%3A%22%22%2C%22doc_aside_html%22%3A%22%22%2C%22public_space_doc_search_enable%22%3Afalse%2C%22lark_official_labels%22%3A%5B%5D%2C%22lake_enabled_groups%22%3A%22%22%2C%22image_proxy_root%22%3A%22%22%2C%22miniapp_code_enable%22%3Afalse%2C%22max_import_task_count%22%3A5%2C%22validation_code_need_captcha%22%3Afalse%2C%22vms_code_service_off%22%3Afalse%2C%22enable_member_popup_act%22%3Atrue%2C%22fu_que_entry_enabled_pages%22%3A%5B%5D%2C%22enable_search%22%3Atrue%2C%22enable_serviceworker%22%3Atrue%2C%22enable_lazyload_card%22%3A%22codeblock%2Cimage%22%2C%22help_center_group_id%22%3A0%2C%22conference_gift_num%22%3A0%2C%22conference_live_show%22%3Afalse%7D%2C%22env%22%3A%22prod%22%2C%22space%22%3A%7B%22host%22%3A%22https%3A%2F%2Fyuque.antfin.com%22%2C%22displayName%22%3A%22%E8%AF%AD%E9%9B%80%22%2C%22logo_url%22%3A%22https%3A%2F%2Fgw.alipayobjects.com%2Fzos%2Fbasement%2Fskylark%2F0abe7b2714792688448236679d347e%2Favatar%2F512.png%22%2C%22small_logo_url%22%3A%22https%3A%2F%2Fgw.alipayobjects.com%2Fzos%2Fbasement%2Fskylark%2F0abe7b2714792688448236679d347e%2Favatar%2F512.png%3Fx-oss-process%3Dimage%2Fresize%2Cm_fill%2Cw_80%2Ch_80%22%2C%22medium_logo_url%22%3A%22https%3A%2F%2Fgw.alipayobjects.com%2Fzos%2Fbasement%2Fskylark%2F0abe7b2714792688448236679d347e%2Favatar%2F512.png%3Fx-oss-process%3Dimage%2Fresize%2Cm_fill%2Cw_160%2Ch_160%22%2C%22large_logo_url%22%3A%22https%3A%2F%2Fgw.alipayobjects.com%2Fzos%2Fbasement%2Fskylark%2F0abe7b2714792688448236679d347e%2Favatar%2F512.png%3Fx-oss-process%3Dimage%2Fresize%2Cm_fill%2Cw_320%2Ch_320%22%2C%22login%22%3A%22%22%2C%22status%22%3A0%2C%22account_id%22%3A0%2C%22enable_password%22%3Atrue%2C%22enable_watermark%22%3Afalse%2C%22id%22%3A0%2C%22name%22%3A%22%E8%AF%AD%E9%9B%80%22%2C%22description%22%3A%22%22%2C%22hasDepartment%22%3Atrue%7D%2C%22organization%22%3Anull%2C%22isYuque%22%3Afalse%2C%22supportOnlineViewer%22%3Atrue%2C%22isEnterprise%22%3Afalse%2C%22defaultSpaceHost%22%3A%22https%3A%2F%2Fyuque.antfin-inc.com%22%2C%22timestamp%22%3A1618300983068%2C%22traceId%22%3A%220b927cab16183009828538748e51cc%22%2C%22siteTip%22%3A%7B%22id%22%3A700030%2C%22content%22%3A%22%3Cimg%20src%3D%5C%22https%3A%2F%2Fgw.alipayobjects.com%2Fmdn%2Frms%2Fafts%2Fimg%2FA*Fg_TQpx32aUAAAAAAAAAAAAAARQnAQ%5C%22%20width%3D%5C%22100%25%5C%22%20%2F%3E%5Cn%3Cdiv%20style%3D%5C%22margin%3A%2024px%2080px%200%3B%5C%22%3E%5Cn%3Cdiv%20style%3D%5C%22width%3A500px%3B%5C%22%3E%5Cn%3Cdiv%20style%3D%5C%22font-size%3A24px%3Bpadding-bottom%3A8px%3Bpadding-top%3A0px%3Bcolor%3A%23000%3Bfont-weight%3Abold%3B%5C%22%3E%F0%9F%93%A8%20%E6%96%B0%E5%B7%A5%E4%BD%9C%E5%8F%B0%E4%B8%8A%E7%BA%BF%EF%BC%81%3C%2Fdiv%3E%5Cn%3Cdiv%3E%5Cn%3Cp%3E%E6%9B%B4%E5%BF%AB%EF%BC%81%E4%B8%80%E7%A7%92%E6%89%BE%E5%88%B0%E7%9F%A5%E8%AF%86%E5%BA%93%3C%2Fp%3E%5Cn%3Cp%3E%E6%B8%85%E7%88%BD%EF%BC%81%E4%BF%A1%E6%81%AF%E6%B5%81%E4%BA%95%E4%BA%95%E6%9C%89%E6%9D%A1%3C%2Fp%3E%5Cn%3Cp%3E%E6%9B%B4%E9%9D%93%EF%BC%81%E5%85%A8%E6%96%B0%E8%A7%86%E8%A7%89%E9%A3%8E%E6%A0%BC%3C%2Fp%3E%5Cn%5Cn%3C%2Fdiv%3E%5Cn%3Cdiv%20style%3D%5C%22padding-top%3A10px%3B%5C%22%3E%3Cp%3E%3Ca%20href%3D%5C%22https%3A%2F%2Fyuque.antfin.com%2Flark%2Fopen%2Fgv5nfh%5C%22%20target%3D%5C%22_blank%5C%22%3E%20%E4%BA%86%E8%A7%A3%E8%AF%A6%E6%83%85%3C%2Fa%3E%3C%2Fp%3E%3C%2Fdiv%3E%5Cn%3C%2Fdiv%3E%5Cn%3C%2Fdiv%3E%5Cn%3Cdiv%20style%3D%5C%22clear%3Aboth%5C%22%3E%3C%2Fdiv%3E%5Cn%3C%2Fdiv%3E%22%2C%22type%22%3A%22global%22%2C%22user_id%22%3Anull%2C%22created_at%22%3A%222021-01-18T06%3A29%3A00.000Z%22%2C%22updated_at%22%3A%222021-01-18T06%3A29%3A00.000Z%22%7D%2C%22siteName%22%3A%22%E8%AF%AD%E9%9B%80%22%2C%22readTip%22%3A%7B%22global%22%3A700030%2C%22editor%22%3A4%2C%22card%22%3A1%2C%22toc%22%3A1%2C%22doc_editor_help%22%3A1%2C%22toc_editor_help%22%3A1%2C%22invite_register_guide%22%3A1%2C%22feature_new_catalog_2%22%3A1%2C%22doc_editor_collab%22%3A1%2C%22feature_vote%22%3A1%2C%22feature_doc_add_resource%22%3A1%2C%22feature_mind%22%3A1%2C%22feature_book_custom_index_landing%22%3A1%2C%22feature_note_release%22%3A1%7D%2C%22imageServiceDomains%22%3A%5B%22cdn.yuque.com%22%2C%22cdn.nlark.com%22%2C%22img.shields.io%22%2C%22travis-ci.org%22%2C%22api.travis-ci.org%22%2C%22npm.packagequality.com%22%2C%22snyk.io%22%2C%22coveralls.io%22%2C%22badgen.now.sh%22%2C%22badgen.net%22%2C%22packagephobia.now.sh%22%2C%22duing.alibaba-inc.com%22%2C%22npm.alibaba-inc.com%22%2C%22web.npm.alibaba-inc.com%22%2C%22npmjs.com%22%2C%22npmjs.org%22%2C%22npg.dockerlab.alipay.net%22%2C%22cp.alibaba.net%22%2C%22private-alipayobjects.alipay.com%22%2C%22googleusercontent.com%22%2C%22lh3.googleusercontent.com%22%2C%22user-images.githubusercontent.com%22%2C%22jarvis.alipay.net%22%2C%22alipay.net%22%2C%22webmail.alibaba-inc.com%22%2C%22wiki.1verge.test%22%2C%22confluence.lzd.co%22%2C%22lzd.co%22%2C%22doc.ucweb.local%22%2C%22work.alibaba.net%22%2C%22work.alibaba-inc.com%22%2C%22lark-assets-prod-aliyun.oss-accelerate.aliyuncs.com%22%2C%22img01.daily.taobaocdn.net%22%2C%22img02.daily.taobaocdn.net%22%2C%22img03.daily.taobaocdn.net%22%2C%22img04.daily.taobaocdn.net%22%2C%22lh1.googleusercontent.com%22%2C%22lh2.googleusercontent.com%22%2C%22lh3.googleusercontent.com%22%2C%22lh4.googleusercontent.com%22%2C%22lh5.googleusercontent.com%22%2C%22lh6.googleusercontent.com%22%2C%22lh7.googleusercontent.com%22%2C%22lh8.googleusercontent.com%22%2C%22lh9.googleusercontent.com%22%2C%22raw.githubusercontent.com%22%2C%22github.com%22%2C%22doc.alipay.net%22%2C%22wa.ucdns.uc.cn%22%2C%22marketing.aliyun-inc.com%22%2C%22lark-temp.oss-cn-hangzhou.aliyuncs.com%22%2C%22yuque.antfin-inc.com%22%2C%22yuque.antfin.com%22%2C%22cdn.nlark.com%22%5D%2C%22sharePlatforms%22%3A%5B%22dingtalk%22%5D%2C%22locale%22%3A%22zh-cn%22%2C%22sharePage%22%3Atrue%2C%22share%22%3A%7B%22id%22%3A1346364%2C%22token%22%3A%2279669dd7-2707-4655-9fa1-b177a10f2d31%22%2C%22target_type%22%3A%22Doc%22%2C%22target_id%22%3A12071284%2C%22scope%22%3A0%2C%22status%22%3A0%2C%22created_at%22%3A%222020-11-13T02%3A05%3A05.000Z%22%2C%22updated_at%22%3A%222020-11-13T02%3A05%3A05.000Z%22%2C%22password_enable%22%3Afalse%2C%22_serializer%22%3A%22web.share%22%7D%2C%22matchCondition%22%3A%7B%22page%22%3A%22docShare%22%2C%22fileType%22%3A%22Doc%22%7D%2C%22forbidLoginCard%22%3Atrue%2C%22loginCardPV%22%3A0%2C%22group%22%3A%7B%22id%22%3A212690%2C%22type%22%3A%22User%22%2C%22login%22%3A%22xinan.cj%22%2C%22name%22%3A%22%E8%BE%9B%E5%AE%89%22%2C%22description%22%3Anull%2C%22avatar_url%22%3A%22https%3A%2F%2Fyuque.antfin-inc.com%2Fr%2Favatar_buc%2F209015%22%2C%22owner_id%22%3Anull%2C%22books_count%22%3A3%2C%22public_books_count%22%3A1%2C%22topics_count%22%3A0%2C%22public_topics_count%22%3A0%2C%22members_count%22%3A0%2C%22public%22%3A1%2C%22scene%22%3Anull%2C%22created_at%22%3A%222019-05-13T05%3A21%3A18.000Z%22%2C%22updated_at%22%3A%222021-04-09T08%3A45%3A17.000Z%22%2C%22organization_id%22%3A0%2C%22isPaid%22%3Atrue%2C%22member_level%22%3A1%2C%22grains_sum%22%3A0%2C%22status%22%3A1%2C%22organization%22%3Anull%2C%22owners%22%3Anull%2C%22_serializer%22%3A%22web.group%22%7D%2C%22book%22%3A%7B%22content_updated_at%22%3A%222021-04-09T08%3A45%3A46.718Z%22%2C%22toc_yml%22%3A%22-%20type%3A%20META%5Cn%20%20count%3A%2026%5Cn%20%20display_level%3A%201%5Cn%20%20tail_type%3A%20SLUG%5Cn%20%20base_version_id%3A%20101029345%5Cn%20%20max_level%3A%201%5Cn%20%20published%3A%20true%5Cn%20%20last_updated_at%3A%20’2021-04-09T08%3A45%3A46.815Z’%5Cn%20%20version_id%3A%20105686780%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20FY2022%E8%A7%84%E5%88%92%5Cn%20%20uuid%3A%20w27yH4YIOTEAStqU%5Cn%20%20url%3A%20vmmibv%5Cn%20%20prev_uuid%3A%20’’%5Cn%20%20sibling_uuid%3A%20Z2PUXHzZJidUXeHb%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2044148797%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2044148797%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20Hbase%E5%AD%A6%E4%B9%A0%5Cn%20%20uuid%3A%20Z2PUXHzZJidUXeHb%5Cn%20%20url%3A%20ukdghk%5Cn%20%20prev_uuid%3A%20w27yH4YIOTEAStqU%5Cn%20%20sibling_uuid%3A%201jGacBgjuTwN1rlV%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2013246833%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2013246833%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20hbase%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%5Cn%20%20uuid%3A%201jGacBgjuTwN1rlV%5Cn%20%20url%3A%20gf1bhr%5Cn%20%20prev_uuid%3A%20Z2PUXHzZJidUXeHb%5Cn%20%20sibling_uuid%3A%20DlvcyM6kn9yQXcJb%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2025671903%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2025671903%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20Spring%E5%AE%B9%E5%99%A8%5Cn%20%20uuid%3A%20DlvcyM6kn9yQXcJb%5Cn%20%20url%3A%20smndes%5Cn%20%20prev_uuid%3A%201jGacBgjuTwN1rlV%5Cn%20%20sibling_uuid%3A%20yfvYywxUR2kniUoL%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2012071284%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2012071284%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E7%B1%BB%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6%E4%B8%8Epandora%E5%AD%A6%E4%B9%A0%5Cn%20%20uuid%3A%20yfvYywxUR2kniUoL%5Cn%20%20url%3A%20kbthcx%5Cn%20%20prev_uuid%3A%20DlvcyM6kn9yQXcJb%5Cn%20%20sibling_uuid%3A%20rH0xslUSkprW1YFy%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2011409713%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2011409713%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E7%94%9F%E6%84%8F%E5%8F%82%E8%B0%8B%E4%BA%8C%E5%A5%97%E5%9F%9F%E5%90%8D%5Cn%20%20uuid%3A%20rH0xslUSkprW1YFy%5Cn%20%20url%3A%20xd6kt9%5Cn%20%20prev_uuid%3A%20yfvYywxUR2kniUoL%5Cn%20%20sibling_uuid%3A%20H9EJDIQ-DWDyxOCU%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2010847278%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2010847278%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E7%94%9F%E6%84%8F%E5%8F%82%E8%B0%8B%E5%B0%8F%E7%A8%8B%E5%BA%8F%E9%89%B4%E6%9D%83%E6%96%B9%E6%A1%88%E8%B0%83%E7%A0%94%5Cn%20%20uuid%3A%20H9EJDIQ-DWDyxOCU%5Cn%20%20url%3A%20bcstin%5Cn%20%20prev_uuid%3A%20rH0xslUSkprW1YFy%5Cn%20%20sibling_uuid%3A%20snSnvsA6luMNDAca%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2010416690%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2010416690%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E8%BE%9B%E5%AE%89S1%20OKR%5Cn%20%20uuid%3A%20snSnvsA6luMNDAca%5Cn%20%20url%3A%20spz1m0%5Cn%20%20prev_uuid%3A%20H9EJDIQ-DWDyxOCU%5Cn%20%20sibling_uuid%3A%20’377587%3Azhurbmubyfxpc3z7’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%2010140474%5Cn%20%20level%3A%200%5Cn%20%20id%3A%2010140474%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%E5%B9%B3%E5%8F%B0DataWin%5Cn%20%20uuid%3A%20’377587%3Azhurbmubyfxpc3z7’%5Cn%20%20url%3A%20dheflo%5Cn%20%20prev_uuid%3A%20snSnvsA6luMNDAca%5Cn%20%20sibling_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%206395755%5Cn%20%20level%3A%200%5Cn%20%20id%3A%206395755%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20UNCREATED_DOC%5Cn%20%20title%3A%20%E9%A1%B9%E7%9B%AE%5Cn%20%20uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20url%3A%20eai7ok%5Cn%20%20prev_uuid%3A%20’377587%3Azhurbmubyfxpc3z7’%5Cn%20%20sibling_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20child_uuid%3A%20’377587%3Aodmnk8ue03p249n0’%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%20’’%5Cn%20%20level%3A%200%5Cn%20%20id%3A%20’’%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E6%A0%87%E9%A2%98%E4%BC%98%E5%8C%96%E6%80%BB%E7%BB%93%5Cn%20%20uuid%3A%20’377587%3Aodmnk8ue03p249n0’%5Cn%20%20url%3A%20lqzbns%5Cn%20%20prev_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20sibling_uuid%3A%20’377587%3Agbe1b4ycod7ohrf0’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20doc_id%3A%204323472%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204323472%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E5%93%81%E7%B1%BB-%E8%BF%9E%E5%B8%A6%26%E7%AB%9E%E5%93%81%5Cn%20%20uuid%3A%20’377587%3Agbe1b4ycod7ohrf0’%5Cn%20%20url%3A%20vwz6gr%5Cn%20%20prev_uuid%3A%20’377587%3Aodmnk8ue03p249n0’%5Cn%20%20sibling_uuid%3A%20’377587%3Ayhza21r4g5nykbhu’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20doc_id%3A%204647297%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204647297%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E7%94%9F%E6%84%8F%E5%8F%82%E8%B0%8B%E4%B8%BB%E8%A6%81%E5%BA%94%E7%94%A8%E4%B8%8E%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF%5Cn%20%20uuid%3A%20’377587%3Ayhza21r4g5nykbhu’%5Cn%20%20url%3A%20pu9l2d%5Cn%20%20prev_uuid%3A%20’377587%3Agbe1b4ycod7ohrf0’%5Cn%20%20sibling_uuid%3A%20’377587%3Afg5pz5nvc7ymp4hi’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20doc_id%3A%204804501%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204804501%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E5%86%85%E5%AE%B93.0%E6%80%BB%E7%BB%93%5Cn%20%20uuid%3A%20’377587%3Afg5pz5nvc7ymp4hi’%5Cn%20%20url%3A%20rwnili%5Cn%20%20prev_uuid%3A%20’377587%3Ayhza21r4g5nykbhu’%5Cn%20%20sibling_uuid%3A%20’’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20doc_id%3A%204178659%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204178659%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20UNCREATED_DOC%5Cn%20%20title%3A%20%E5%AD%A6%E4%B9%A0%5Cn%20%20uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20url%3A%20xgtwmi%5Cn%20%20prev_uuid%3A%20’377587%3Aoowsl3nxh3r21g1a’%5Cn%20%20sibling_uuid%3A%20’’%5Cn%20%20child_uuid%3A%200XxXZvphZFOXemXO%5Cn%20%20parent_uuid%3A%20’’%5Cn%20%20doc_id%3A%20’’%5Cn%20%20level%3A%200%5Cn%20%20id%3A%20’’%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20dispatchserverlet%5Cn%20%20uuid%3A%200XxXZvphZFOXemXO%5Cn%20%20url%3A%20xqstxy%5Cn%20%20prev_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20sibling_uuid%3A%20Tv8lFbxMLHPz45DK%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%2011988607%5Cn%20%20level%3A%201%5Cn%20%20id%3A%2011988607%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20Spring%20AOP%5Cn%20%20uuid%3A%20Tv8lFbxMLHPz45DK%5Cn%20%20url%3A%20fhf6a4%5Cn%20%20prev_uuid%3A%200XxXZvphZFOXemXO%5Cn%20%20sibling_uuid%3A%20NZYoco9dr8RidQ8p%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%2011988533%5Cn%20%20level%3A%201%5Cn%20%20id%3A%2011988533%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%200%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20Spring%5Cn%20%20uuid%3A%20NZYoco9dr8RidQ8p%5Cn%20%20url%3A%20urrzgo%5Cn%20%20prev_uuid%3A%20Tv8lFbxMLHPz45DK%5Cn%20%20sibling_uuid%3A%20PmwONlnPQxohVBuh%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%2010124010%5Cn%20%20level%3A%201%5Cn%20%20id%3A%2010124010%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E5%8F%8D%E5%B0%84%E4%B8%8E%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%5Cn%20%20uuid%3A%20PmwONlnPQxohVBuh%5Cn%20%20url%3A%20atfzrg%5Cn%20%20prev_uuid%3A%20NZYoco9dr8RidQ8p%5Cn%20%20sibling_uuid%3A%20’377587%3Apmta78zal9hf83mx’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%208647525%5Cn%20%20level%3A%201%5Cn%20%20id%3A%208647525%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20git%5Cn%20%20uuid%3A%20’377587%3Apmta78zal9hf83mx’%5Cn%20%20url%3A%20ndbm4e%5Cn%20%20prev_uuid%3A%20PmwONlnPQxohVBuh%5Cn%20%20sibling_uuid%3A%20’377587%3Adxgqzrycyg9nw1sz’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%206779728%5Cn%20%20level%3A%201%5Cn%20%20id%3A%206779728%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20java%20json%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%20getter%E5%92%8Csetter%E6%96%B9%E6%B3%95%5Cn%20%20uuid%3A%20’377587%3Adxgqzrycyg9nw1sz’%5Cn%20%20url%3A%20ggyage%5Cn%20%20prev_uuid%3A%20’377587%3Apmta78zal9hf83mx’%5Cn%20%20sibling_uuid%3A%20’377587%3Alfrofsglrageh6iy’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%204323474%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204323474%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20%E5%8C%85%E8%A3%85%E7%B1%BB%E4%B8%8E%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E8%A3%85%E7%AE%B1%E6%8B%86%E7%AE%B1%5Cn%20%20uuid%3A%20’377587%3Alfrofsglrageh6iy’%5Cn%20%20url%3A%20tvq9qk%5Cn%20%20prev_uuid%3A%20’377587%3Adxgqzrycyg9nw1sz’%5Cn%20%20sibling_uuid%3A%20’377587%3Axpzgqhpm2fk5whqp’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%204335067%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204335067%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20bpms%E5%B7%A5%E4%BD%9C%E6%B5%81%E5%AE%9E%E6%88%98%5Cn%20%20uuid%3A%20’377587%3Axpzgqhpm2fk5whqp’%5Cn%20%20url%3A%20gsn2xg%5Cn%20%20prev_uuid%3A%20’377587%3Alfrofsglrageh6iy’%5Cn%20%20sibling_uuid%3A%20’377587%3Auf5dz6yyclfzbrpg’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%206675096%5Cn%20%20level%3A%201%5Cn%20%20id%3A%206675096%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20The%20Hadoop%20Distributed%20File%20System%5Cn%20%20uuid%3A%20’377587%3Auf5dz6yyclfzbrpg’%5Cn%20%20url%3A%20cw548i%5Cn%20%20prev_uuid%3A%20’377587%3Axpzgqhpm2fk5whqp’%5Cn%20%20sibling_uuid%3A%20’377587%3Agb105xzr8bt3313g’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%207058065%5Cn%20%20level%3A%201%5Cn%20%20id%3A%207058065%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20oneness%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93%5Cn%20%20uuid%3A%20’377587%3Agb105xzr8bt3313g’%5Cn%20%20url%3A%20adtbzs%5Cn%20%20prev_uuid%3A%20’377587%3Auf5dz6yyclfzbrpg’%5Cn%20%20sibling_uuid%3A%20’377587%3Atug7tg2b9lspthqa’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%204776813%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204776813%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn-%20type%3A%20DOC%5Cn%20%20title%3A%20java%E6%B3%9B%E5%9E%8B%5Cn%20%20uuid%3A%20’377587%3Atug7tg2b9lspthqa’%5Cn%20%20url%3A%20xrsoc6%5Cn%20%20prev_uuid%3A%20’377587%3Agb105xzr8bt3313g’%5Cn%20%20sibling_uuid%3A%20’’%5Cn%20%20child_uuid%3A%20’’%5Cn%20%20parent_uuid%3A%20’377587%3Azkkt8ot63me5ea70’%5Cn%20%20doc_id%3A%204647286%5Cn%20%20level%3A%201%5Cn%20%20id%3A%204647286%5Cn%20%20open_window%3A%201%5Cn%20%20visible%3A%201%5Cn%22%2C%22enable_comment%22%3Atrue%2C%22enable_auto_publish%22%3Afalse%2C%22enable_export%22%3Atrue%2C%22enable_visitor_watermark%22%3Afalse%2C%22copyright_watermark%22%3A%22%22%2C%22image_copyright_watermark%22%3A%22%22%2C%22enable_search_engine%22%3Afalse%2C%22enable_announcement%22%3Atrue%2C%22enable_webhook%22%3Atrue%2C%22enable_trash%22%3Atrue%2C%22enable_document_copy%22%3Atrue%2C%22enable_toc%22%3Atrue%2C%22layout%22%3A%22Book%22%2C%22doc_viewport%22%3A%22fixed%22%2C%22doc_typography%22%3Anull%2C%22isBanned%22%3Afalse%2C%22catalog_display_level%22%3A1%2C%22catalog_tail_type%22%3A%22SLUG%22%2C%22enable_catalog_nodes%22%3Atrue%2C%22id%22%3A377587%2C%22space_id%22%3A0%2C%22type%22%3A%22Book%22%2C%22slug%22%3A%22qx9xwp%22%2C%22name%22%3A%22xinan%22%2C%22description%22%3A%22%22%2C%22toc%22%3A%22-%20%5B%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%E5%B9%B3%E5%8F%B0DataWin%5D(dheflo%20%5C%226395755%5C%22)%5Cn-%20%5B%E9%A1%B9%E7%9B%AE%5D(eai7ok)%5Cn%20%20-%20%5B%E6%A0%87%E9%A2%98%E4%BC%98%E5%8C%96%E6%80%BB%E7%BB%93%5D(lqzbns%20%5C%224323472%5C%22)%5Cn%20%20-%20%5B%E5%93%81%E7%B1%BB-%E8%BF%9E%E5%B8%A6%26%E7%AB%9E%E5%93%81%5D(vwz6gr%20%5C%224647297%5C%22)%5Cn%20%20-%20%5B%E7%94%9F%E6%84%8F%E5%8F%82%E8%B0%8B%E4%B8%BB%E8%A6%81%E5%BA%94%E7%94%A8%E4%B8%8E%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF%5D(pu9l2d%20%5C%224804501%5C%22)%5Cn%20%20-%20%5B%E5%86%85%E5%AE%B93.0%E6%80%BB%E7%BB%93%5D(rwnili%20%5C%224178659%5C%22)%5Cn-%20%5B%E5%AD%A6%E4%B9%A0%5D(xgtwmi)%5Cn%20%20-%20%5Bgit%5D(ndbm4e%20%5C%226779728%5C%22)%5Cn%20%20-%20%5Bjava%20json%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%20getter%E5%92%8Csetter%E6%96%B9%E6%B3%95%5D(ggyage%20%5C%224323474%5C%22)%5Cn%20%20-%20%5B%E5%8C%85%E8%A3%85%E7%B1%BB%E4%B8%8E%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%E8%A3%85%E7%AE%B1%E6%8B%86%E7%AE%B1%5D(tvq9qk%20%5C%224335067%5C%22)%5Cn%20%20-%20%5Bbpms%E5%B7%A5%E4%BD%9C%E6%B5%81%E5%AE%9E%E6%88%98%5D(gsn2xg%20%5C%226675096%5C%22)%5Cn%20%20-%20%5BThe%20Hadoop%20Distributed%20File%20System%5D(cw548i%20%5C%227058065%5C%22)%5Cn%20%20-%20%5Boneness%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93%5D(adtbzs%20%5C%224776813%5C%22)%5Cn%20%20-%20%5Bjava%E6%B3%9B%E5%9E%8B%5D(xrsoc6%20%5C%224647286%5C%22)%22%2C%22body%22%3A%22%7B%5C%22enable_comment%5C%22%3Atrue%2C%5C%22enable_export%5C%22%3Atrue%2C%5C%22catalog_display_level%5C%22%3A1%2C%5C%22catalog_tail_type%5C%22%3A%5C%22SLUG%5C%22%2C%5C%22enable_catalog_nodes%5C%22%3Atrue%7D%22%2C%22user_id%22%3A212690%2C%22creator_id%22%3A212690%2C%22public%22%3A0%2C%22status%22%3A0%2C%22excellent%22%3A0%2C%22menu_type%22%3A0%2C%22items_count%22%3A28%2C%22likes_count%22%3A0%2C%22watches_count%22%3A1%2C%22content_updated_at_ms%22%3A1617957946718%2C%22deleted_slug%22%3Anull%2C%22created_at%22%3A%222019-07-09T06%3A11%3A00.000Z%22%2C%22updated_at%22%3A%222021-04-09T08%3A45%3A46.000Z%22%2C%22pinned_at%22%3Anull%2C%22archived_at%22%3Anull%2C%22collaboration_count%22%3A0%2C%22stack_id%22%3Anull%2C%22rank%22%3Anull%2C%22resource_size%22%3A0%2C%22book_department_updated_at%22%3Anull%2C%22scene%22%3Anull%2C%22source%22%3Anull%2C%22original%22%3Anull%2C%22premium%22%3Anull%2C%22announcement%22%3Anull%2C%22is_trust%22%3A0%2C%22cover%22%3Anull%2C%22index_id%22%3Anull%2C%22toc_updated_at%22%3A%222021-04-09T08%3A45%3A46.000Z%22%2C%22organization_id%22%3A0%2C%22deleted_at%22%3Anull%7D%2C%22doc%22%3A%7B%22meta%22%3A%7B%7D%2C%22content_updated_at%22%3A%222021-03-31T07%3A19%3A43.000Z%22%2C%22body%22%3A%22%22%2C%22body_asl%22%3A%22%22%2C%22body_draft%22%3A%22%22%2C%22body_draft_asl%22%3A%22%22%2C%22premium_body%22%3A%22%22%2C%22premium_body_asl%22%3A%22%22%2C%22premium_body_draft%22%3A%22%22%2C%22premium_body_draft_asl%22%3A%22%22%2C%22isSuspect%22%3Afalse%2C%22full_body%22%3A%22%22%2C%22full_body_asl%22%3A%22%22%2C%22full_body_draft%22%3A%22%22%2C%22full_body_draft_asl%22%3A%22%22%2C%22editor_meta%22%3A%22%7B%5C%22viewport%5C%22%3A%5C%22adapt%5C%22%2C%5C%22typography%5C%22%3A%5C%22classic%5C%22%7D%22%2C%22editor_meta_draft%22%3A%22%7B%5C%22viewport%5C%22%3A%5C%22adapt%5C%22%2C%5C%22typography%5C%22%3A%5C%22classic%5C%22%7D%22%2C%22premium_expired%22%3Afalse%2C%22id%22%3A12071284%2C%22space_id%22%3A0%2C%22type%22%3A%22Doc%22%2C%22sub_type%22%3Anull%2C%22slug%22%3A%22smndes%22%2C%22book_id%22%3A377587%2C%22user_id%22%3A212690%2C%22title%22%3A%22Spring%E5%AE%B9%E5%99%A8%22%2C%22tag%22%3Anull%2C%22cover%22%3A%22https%3A%2F%2Fintranetproxy.alipay.com%2Fskylark%2Flark%2F0%2F2020%2Fpng%2F212690%2F1604286340500-04c33038-e5ec-4785-9320-b3e7a280de44.png%22%2C%22custom_cover%22%3A%22https%3A%2F%2Fintranetproxy.alipay.com%2Fskylark%2Flark%2F0%2F2020%2Fpng%2F212690%2F1603956945170-258b427e-28d7-452e-ac02-d5f330d3970d.png%22%2C%22description%22%3A%22Spring%E5%AE%B9%E5%99%A8%E6%A6%82%E8%BF%B0spring%E7%9A%84%E6%95%B4%E4%BD%93%E6%9E%B6%E6%9E%84%E5%A6%82%E4%B8%8B%EF%BC%8C%E5%85%B6%E4%B8%ADspring%20%E5%AE%B9%E5%99%A8%E4%BD%9C%E4%B8%BAspring%20%E7%9A%84%E5%BA%95%E5%BA%A7%EF%BC%8C%E5%85%B6%E4%BB%96%E5%8A%9F%E8%83%BD%E5%A6%82web%E3%80%81data%20%E7%AD%89%E9%83%BD%E6%98%AF%E5%9F%BA%E4%BA%8Espring%20%E5%AE%B9%E5%99%A8%E5%8F%91%E5%B1%95%E8%B5%B7%E6%9D%A5%EF%BC%8C%E6%9C%AC%E6%96%87%E9%92%88%E5%AF%B9spring%E5%AE%B9%E5%99%A8%E8%BF%9B%E8%A1%8C%E8%AF%A6%E7%BB%86%E7%9A%84%E5%88%86%E6%9E%90%E3%80%82Spring%20%E5%AE%B9%E5%99%A8Bean%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E5%AE%9A%E4%B9%89%E4%BA%86Bean%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8F%8A%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%EF%BC%8CSpring%E5%AE%B9%E5%99%A8%E6%A0%B9%E6%8D%AE%E5%90%84%E7%A7%8D%E5%BD%A2…%22%2C%22custom_description%22%3Anull%2C%22title_draft%22%3Anull%2C%22format%22%3A%22lake%22%2C%22status%22%3A1%2C%22read_status%22%3A1%2C%22view_status%22%3A0%2C%22public%22%3A1%2C%22comments_count%22%3A0%2C%22likes_count%22%3A0%2C%22collaboration_count%22%3A0%2C%22last_editor_id%22%3A212690%2C%22draft_version%22%3A299%2C%22deleted_slug%22%3Anull%2C%22word_count%22%3A7105%2C%22created_at%22%3A%222020-10-26T01%3A49%3A26.000Z%22%2C%22updated_at%22%3A%222021-03-31T07%3A19%3A44.000Z%22%2C%22published_at%22%3A%222021-03-31T07%3A19%3A43.000Z%22%2C%22first_published_at%22%3A%222020-10-30T10%3A28%3A42.000Z%22%2C%22selected_at%22%3Anull%2C%22pinned_at%22%3Anull%2C%22premium_days_count%22%3Anull%2C%22premium_price%22%3Anull%2C%22premium_started_at%22%3Anull%2C%22premium_expired_at%22%3Anull%2C%22doc_meta%22%3A%22%7B%5C%22viewport%5C%22%3A%5C%22adapt%5C%22%2C%5C%22typography%5C%22%3A%5C%22classic%5C%22%7D%22%2C%22doc_meta_draft%22%3A%22%7B%5C%22viewport%5C%22%3A%5C%22adapt%5C%22%2C%5C%22typography%5C%22%3A%5C%22classic%5C%22%7D%22%2C%22deleted_at%22%3Anull%2C%22body_html%22%3A%22%22%2C%22full_body_html%22%3A%22%22%2C%22abilities%22%3A%7B%22read%22%3Atrue%2C%22update%22%3Afalse%2C%22destroy%22%3Afalse%2C%22read_origin%22%3Afalse%7D%2C%22contributors%22%3A%5B%7B%22work_id%22%3A%22209015%22%2C%22avatar_url%22%3A%22https%3A%2F%2Fyuque.antfin-inc.com%2Fr%2Favatar_buc%2F209015%22%2C%22isActive%22%3Atrue%2C%22isInactive%22%3Afalse%2C%22isDeactivated%22%3Afalse%2C%22isTerminated%22%3Afalse%2C%22isBanned%22%3Afalse%2C%22isBlocked%22%3Afalse%2C%22isMuted%22%3Afalse%2C%22isExtcontact%22%3Afalse%2C%22isPaid%22%3Atrue%2C%22hasPaidBefore%22%3Atrue%2C%22id%22%3A212690%2C%22space_id%22%3A0%2C%22type%22%3A%22User%22%2C%22login%22%3A%22xinan.cj%22%2C%22name%22%3A%22%E8%BE%9B%E5%AE%89%22%2C%22description%22%3Anull%2C%22avatar%22%3Anull%2C%22owner_id%22%3Anull%2C%22topics_count%22%3A0%2C%22public_topics_count%22%3A0%2C%22members_count%22%3A0%2C%22books_count%22%3A3%2C%22public_books_count%22%3A1%2C%22followers_count%22%3A0%2C%22following_count%22%3A0%2C%22account_id%22%3Anull%2C%22role%22%3A1%2C%22status%22%3A1%2C%22public%22%3A1%2C%22wants_email%22%3Atrue%2C%22wants_marketing_email%22%3Atrue%2C%22topic_updated_at_ms%22%3A0%2C%22deleted_slug%22%3Anull%2C%22language%22%3A%22zh-cn%22%2C%22organization_id%22%3A0%2C%22emp_type%22%3A%22%E6%AD%A3%E5%BC%8F%20-%20%E6%AD%A3%E5%BC%8F%E5%91%98%E5%B7%A5%22%2C%22group_department_updated_at%22%3Anull%2C%22member_level%22%3A1%2C%22expired_at%22%3A%222123-02-27T15%3A59%3A59.000Z%22%2C%22scene%22%3Anull%2C%22source%22%3Anull%2C%22max_member%22%3Anull%2C%22created_at%22%3A%222019-05-13T05%3A21%3A18.000Z%22%2C%22updated_at%22%3A%222021-04-09T08%3A45%3A17.000Z%22%2C%22grains_sum%22%3A0%2C%22punish_expired_at%22%3Anull%2C%22deleted_at%22%3Anull%7D%5D%2C%22hits%22%3A6%2C%22token%22%3A%2279669dd7-2707-4655-9fa1-b177a10f2d31%22%2C%22ogpTitle%22%3A%22Spring%E5%AE%B9%E5%99%A8%20%C2%B7%20%E8%AF%AD%E9%9B%80%22%7D%2C%22search%22%3A%7B%22display%22%3Atrue%2C%22scope%22%3A%22%2F%22%7D%2C%22prefetch%22%3A%22fetchShareDocData%22%2C%22paymentInfo%22%3A%7B%7D%2C%22enable_payment%22%3Afalse%2C%22userMemberInfo%22%3A%7B%22usage%22%3A%7B%22attachment_size%22%3A152319570%2C%22image_size%22%3A283465860%2C%22video_size%22%3A0%2C%22max_upload_size%22%3A107374182400%2C%22_serializer%22%3A%22web.user_usage_statistics%22%7D%2C%22expired_at%22%3Anull%2C%22countDownDays%22%3Anull%2C%22isAllowRenew%22%3Afalse%2C%22receipt%22%3Anull%2C%22groupOwners%22%3A%5B%5D%2C%22hasOrder%22%3Afalse%7D%2C%22enable_datasheet%22%3Atrue%2C%22enable_baiyan_work_process%22%3Atrue%2C%22topTip%22%3Anull%2C%22login%22%3A%7B%22loginType%22%3A%22normal%22%2C%22enablePlatforms%22%3A%5B%22aone_teambition%22%5D%2C%22isWechatMobileApp%22%3Afalse%7D%2C%22isDesktopApp%22%3Afalse%2C%22isAlipayApp%22%3Afalse%2C%22isDingTalkMiniApp%22%3Afalse%7D”)); })();
Adblocker

Spring容器

Spring容器概述

spring的整体架构如下,其中spring 容器作为spring 的底座,其他功能如web、data 等都是基于spring 容器发展起来,本文针对spring容器进行详细的分析。

Spring 容器

Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据注册表加载、实例化Bean,并建立Bean和Bean的依赖关系,最后将这些准备就绪的Bean放到Bean缓存池中,以供外层的应用程序进行调用。Spring容器包括beanFactory 和applicationContext,整个spring容器就是通过beanFactory和applicationContext来完成bean的配置、注册、实例化、初始化、读取等一些列操作。

applicationContext

抽象类AbstractApplicationContext包含了容器的绝大部分功能,spring容器的启动流程就是在这个类的refresh方法中。下面的子类是应对不同的场景,我们在创建一个spring容器的时候通常会这样做。

  1. //编译路径
  2. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  3. //系统文件路径
  4. FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
  5. //mvc启动方式
  6. XmlWebApplicationContext context = new XmlWebApplicationContext("applicationContext.xml");

beanFactory

DefaulistListTableBeanFactory包含了beanFactory的核心能力,容器启动默认创建DefaulistListTableBeanFactory实例。Spring读取bean的配置创建的beanDefinition对象会存放在bean注册表中,根据beanDefinition对象创建的singleton类型的bean实例会存放在bean缓存池中,bean的注册表和bean的缓存池都由DefaulistListTableBeanFactory维护,由此可见DefaulistListTableBeanFactory在spring容器中的地位。

  1. public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
  2. implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable{}

初始化spring容器

tomcat启动后回调ContextLoaderListener启动spring容器

web容器如tomcat启动时,根据web.xml中的配置,回调监听器ContextLoaderListener ,ContextLoaderListener实现了tomcat的ServletContextListener 接口,通过contextInitialized方法完成webApplicationContext的初始化

  1. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  4. version="4.0">
  5. <context-param>
  6. <param-name>contextConfigLocation</param-name>
  7. <param-value>/WEB-INF/applicationContext.xml</param-value>
  8. </context-param>
  9. <listener>
  10. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  11. </listener>
  12. <servlet>
  13. <servlet-name>dispatcher</servlet-name>
  14. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  15. <load-on-startup>1</load-on-startup>
  16. </servlet>
  17. <servlet-mapping>
  18. <servlet-name>dispatcher</servlet-name>
  19. <url-pattern>*.form</url-pattern>
  20. </servlet-mapping>
  21. </web-app>

初始化过程首先创建一个webApplicationContext,如果没有自定义webApplicationContext会使用默认的默认使用XmlWebApplicationContext,之后会判断XmlWebApplicationContext是否被刷新过,如果没有则调用configureAndRefreshWebApplicationContext刷新容器,获取配置文件的位置参数,一般资源文件配置在applicationContext.xml中,这也是webapplicationContext默认的配置文件,初始化资源,最后调用refresh方法,refreshspring容器启动的核心方法,也是spring容器开始启动的入口。容器启动完成后会把spring的webApplicationContext注入到tomcat的servletContext

  1. //ContextLoaderListener.java
  2. //初始化sping 容器
  3. @Override
  4. public void contextInitialized(ServletContextEvent event) {
  5. initWebApplicationContext(event.getServletContext());
  6. }
  7. //ContextLoader.java
  8. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
  9. ...省略非关键代码
  10. try {
  11. //context为空,则创建一个,默认使用XmlWebApplicationContext
  12. if (this.context == null) {
  13. this.context = createWebApplicationContext(servletContext);
  14. }
  15. //激活context
  16. if (this.context instanceof ConfigurableWebApplicationContext) {
  17. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
  18. if (!cwac.isActive()) {
  19. // The context has not yet been refreshed -> provide services such as
  20. // setting the parent context, setting the application context id, etc
  21. if (cwac.getParent() == null) {
  22. // The context instance was injected without an explicit parent ->
  23. // determine parent for root web application context, if any.
  24. ApplicationContext parent = loadParentContext(servletContext);
  25. cwac.setParent(parent);
  26. }
  27. //核心方法,下面分析
  28. configureAndRefreshWebApplicationContext(cwac, servletContext);
  29. }
  30. }
  31. //把spring WebApplicationContext 注入到tomcat 的servletContext中
  32. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  33. return this.context;
  34. }
  35. }
  36. //ContextLoader.java
  37. protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
  38. //设置servletContext
  39. wac.setServletContext(sc);
  40. String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
  41. //设置context配置位置,一般是applicationContext.xml
  42. if (configLocationParam != null) {
  43. wac.setConfigLocation(configLocationParam);
  44. }
  45. ConfigurableEnvironment env = wac.getEnvironment();
  46. if (env instanceof ConfigurableWebEnvironment) {
  47. //初始化资源
  48. ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
  49. }
  50. customizeContext(sc, wac);
  51. //spring容器的核心方法,真正启动spring的入口
  52. wac.refresh();
  53. }

Spring容器启动过程

  1. //org/springframework/context/support/AbstractApplicationContext.java
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // 准备启动上下文
  5. prepareRefresh();
  6. // 创建DefaultListableBeanFactory,完成bean配置的读取、解析,核心方法,下面分析
  7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  8. // Prepare the bean factory for use in this context.
  9. //设置beanFactory属性,包括classloader、BeanPostProcessor
  10. //注册ApplicationContextAwareProcessor实例实现BeanPostProcessor完成扩展功能(扩展点一节分析)
  11. prepareBeanFactory(beanFactory);
  12. try {
  13. // 调用默认的beanPostProcessor 如 ServletContextAwareProcessor
  14. postProcessBeanFactory(beanFactory);
  15. // Invoke factory processors registered as beans in the context.
  16. //实例化注册的BeanFactoryPostProcessor bean
  17. invokeBeanFactoryPostProcessors(beanFactory);
  18. // Register bean processors that intercept bean creation.
  19. //注册 beanPostProcessor 用来在bean的初始化前后实现扩展逻辑
  20. registerBeanPostProcessors(beanFactory);
  21. // Initialize message source for this context.
  22. initMessageSource();
  23. // Initialize event multicaster for this context.
  24. initApplicationEventMulticaster();
  25. // Initialize other special beans in specific context subclasses.
  26. onRefresh();
  27. // Check for listener beans and register them.
  28. registerListeners();
  29. // 实例化非懒加载单例bean,核心方法下面分析
  30. finishBeanFactoryInitialization(beanFactory);
  31. // Last step: publish corresponding event.
  32. finishRefresh();
  33. }
  34. }
  35. }

bean解析&注册

beanFactory负责管理bean的解析、注册、实例化等操作,所以在bean解析前需要先创建一个beanFactory。如果之前已经创建beanFactory,需要先销毁bean并关闭beanFactory。Spring容器会创建一个DefaultListableBeanFactory实例,这个类非常重要,里面维护了bean的注册表和bean的缓存池,bean的注册表用来存放根据配置解析出的beanDefinition对象;bean的缓存池存放beanDefinition对象实例化出来的bean实例,我们应用平时使用到的bean就是从bean缓存池中取出来的。本小节先介绍bean的解析与注册过程,spring根据配置(xml、注解、java类)解析后的bean会存放在注册表里面,根据注册表实例化bean会存放在缓存池里面。然后在customizeBeanFactory方法中完成一些个性化配置,之后会加载配置的bean到spring的bean注册表

  1. //org/springframework/context/support/AbstractApplicationContext.java
  2. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  3. refreshBeanFactory();
  4. return getBeanFactory();
  5. }
  6. //org/springframework/context/support/AbstractRefreshableApplicationContext.java
  7. protected final void refreshBeanFactory() throws BeansException {
  8. if (hasBeanFactory()) {
  9. destroyBeans();
  10. closeBeanFactory();
  11. }
  12. try {
  13. DefaultListableBeanFactory beanFactory = createBeanFactory();
  14. beanFactory.setSerializationId(getId());
  15. customizeBeanFactory(beanFactory);
  16. //完成bean的解析、注册到spring用起的bean注册表
  17. loadBeanDefinitions(beanFactory);
  18. synchronized (this.beanFactoryMonitor) {
  19. this.beanFactory = beanFactory;
  20. }
  21. }
  22. }

读取bean配置,转换成dom对象

首先创建XmlBeanDefinitionReader,完成环境配置与初始化等,核心是loadBeanDefinitions(beanDefinitionReader),它会从配置文件加载bean,首先获取配置文件的位置,然后从配置文件中解析出resource。其中一系列的重载方法目的是把配置文件从location到获取资源到最终解析成document对象,这个转换过程是location->resource->inputstream->inputsource->document。真正解析bean的时候是解析document里面的element元素。

  1. @Override
  2. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  3. // Create a new XmlBeanDefinitionReader for the given BeanFactory.
  4. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
  5. // Configure the bean definition reader with this context's
  6. // resource loading environment.
  7. beanDefinitionReader.setEnvironment(getEnvironment());
  8. beanDefinitionReader.setResourceLoader(this);
  9. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
  10. // Allow a subclass to provide custom initialization of the reader,
  11. // then proceed with actually loading the bean definitions.
  12. initBeanDefinitionReader(beanDefinitionReader);
  13. loadBeanDefinitions(beanDefinitionReader);
  14. }
  15. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
  16. String[] configLocations = getConfigLocations();
  17. if (configLocations != null) {
  18. for (String configLocation : configLocations) {
  19. reader.loadBeanDefinitions(configLocation);
  20. }
  21. }
  22. }
  23. public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
  24. return loadBeanDefinitions(location, null);
  25. }
  26. public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
  27. //省略非核心代码
  28. ResourceLoader resourceLoader = getResourceLoader();
  29. //如果是正则匹配
  30. if (resourceLoader instanceof ResourcePatternResolver) {
  31. // Resource pattern matching available.
  32. try {
  33. //从配置文件解析resource
  34. Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
  35. int count = loadBeanDefinitions(resources);
  36. }
  37. }
  38. else {
  39. // Can only load single resources by absolute URL.
  40. //从配置文件解析resource
  41. Resource resource = resourceLoader.getResource(location);
  42. int count = loadBeanDefinitions(resource);
  43. }
  44. }
  45. //对resource进行编码
  46. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
  47. return loadBeanDefinitions(new EncodedResource(resource));
  48. }
  49. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
  50. //省略非核心代码
  51. try {
  52. //resource -> inputStream
  53. InputStream inputStream = encodedResource.getResource().getInputStream();
  54. try {
  55. //inputStream->inputSource
  56. InputSource inputSource = new InputSource(inputStream);
  57. if (encodedResource.getEncoding() != null) {
  58. inputSource.setEncoding(encodedResource.getEncoding());
  59. }
  60. return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
  61. }
  62. }
  63. }
  64. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
  65. throws BeanDefinitionStoreException {
  66. try {
  67. //inputsource -> document
  68. Document doc = doLoadDocument(inputSource, resource);
  69. int count = registerBeanDefinitions(doc, resource);
  70. return count;
  71. }
  72. }
  73. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
  74. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
  75. int countBefore = getRegistry().getBeanDefinitionCount();
  76. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
  77. return getRegistry().getBeanDefinitionCount() - countBefore;
  78. }
  79. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  80. this.readerContext = readerContext;
  81. doRegisterBeanDefinitions(doc.getDocumentElement());
  82. }
  83. protected void doRegisterBeanDefinitions(Element root) {
  84. BeanDefinitionParserDelegate parent = this.delegate;
  85. this.delegate = createDelegate(getReaderContext(), root, parent);
  86. //bean 解析前处理
  87. preProcessXml(root);
  88. //真正的解析bean
  89. parseBeanDefinitions(root, this.delegate);
  90. //bean解析后处理
  91. postProcessXml(root);
  92. this.delegate = parent;
  93. }

dom对象解析成beanDefinition对象

经过上面的步骤已经把xml文件转成dom 元素,然后对dom元素从root节点开始解析,包括解析默认节点(如bean)和自定义节点(如context节点),默认的节点包括 impot alias bean等,这里重点看下bean节点的解析processBeanDefinition(ele, delegate)。首先把elemetn解析成beanDefinition并然后封装到一个包装器(重点,真正进行bean解析的地方,下面单独分析)

  1. //org/springframework/beans/factory/xml/DefaultBeanDefinitionDocumentReader.java
  2. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  3. if (delegate.isDefaultNamespace(root)) {
  4. NodeList nl = root.getChildNodes();
  5. for (int i = 0; i < nl.getLength(); i++) {
  6. Node node = nl.item(i);
  7. if (node instanceof Element) {
  8. Element ele = (Element) node;
  9. if (delegate.isDefaultNamespace(ele)) {
  10. parseDefaultElement(ele, delegate);
  11. }
  12. else {
  13. delegate.parseCustomElement(ele);
  14. }
  15. }
  16. }
  17. }
  18. else {
  19. delegate.parseCustomElement(root);
  20. }
  21. }
  22. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
  23. if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
  24. importBeanDefinitionResource(ele);
  25. }
  26. else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
  27. processAliasRegistration(ele);
  28. }
  29. else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
  30. processBeanDefinition(ele, delegate);
  31. }
  32. else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
  33. // recurse
  34. doRegisterBeanDefinitions(ele);
  35. }
  36. }
  37. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  38. //将element元素解析成对beanDefinition,然后封装一个包装器,bean解析核心方法
  39. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  40. if (bdHolder != null) {
  41. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
  42. try {
  43. //注册bean
  44. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
  45. }
  46. // Send registration event.
  47. //注册完成后发送事件,对应的监听器收到事件会处理
  48. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  49. }
  50. }

根据element里面的属性来解析bean,包括获取bean 的id 、name 校验id唯一性等准备工作,重点是通过parseBeanDefinitionElement把element解析成beanDefinition。parseBeanDefinitionElement首先是尝试获取element中bean 的classname 和parentName等属性,然后实例化一个GenericBeanDefinition并注入classname,parentName。最后是逐个解析bean的属性和bean的子节点属性并注入到之前实例化的GenericBeanDefinition中。下图中可以看出element对象包含了定义bean节点的各个属性和子节点的属性。

//BeanDefinitionParserDelegate.java
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    //省略非核心代码
    //获取beanId
    String id = ele.getAttribute(ID_ATTRIBUTE);
    //获取beanName
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    //name支持多个
    List<String> aliases = new ArrayList<>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        aliases.addAll(Arrays.asList(nameArr));
    }
    //如果id为空,则id取第一个name
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isTraceEnabled()) {
            logger.trace("No XML 'id' specified - using '" + beanName +
                         "' as bean name and " + aliases + " as aliases");
        }
    }
    //校验id的唯一性
    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    //beanName解析成beanDefinition 重点
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

    return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

//这里是真正完成bean解析的过程
public AbstractBeanDefinition parseBeanDefinitionElement(
    Element ele, String beanName, @Nullable BeanDefinition containingBean) {

    this.parseState.push(new BeanEntry(beanName));
    //获取classname和parent
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }

    try {
        创建GenerateBeanDefinition实例,注入classname
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        //解析bean节点下的各个属性,如<init-method>
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        //解析bean的子节点属性,如果配置了。比如metaElement constructor-args,property,qualifier等属性
        parseMetaElements(ele, bd);
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

        parseConstructorArgElements(ele, bd);
        parsePropertyElements(ele, bd);
        parseQualifierElements(ele, bd);

        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));

        return bd;
    }
    ...省略异常
    finally {
        this.parseState.pop();
    }

    return null;
}

在xml文件中配置bean的时候可以设置各种各样的属性,如singleton lazy-init init-method等,里面会一一解析。

//BeanDefinitionParserDelegate.java
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                                                            @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    else if (containingBean != null) {
        // Take default from containing bean in case of an inner bean definition.
        bd.setScope(containingBean.getScope());
    }

    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }

    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (isDefaultValue(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));

    if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
        String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    }

    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if (isDefaultValue(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    }
    else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }

    if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    }

    if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
        String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
        bd.setInitMethodName(initMethodName);
    }
    else if (this.defaults.getInitMethod() != null) {
        bd.setInitMethodName(this.defaults.getInitMethod());
        bd.setEnforceInitMethod(false);
    }

    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    }
    else if (this.defaults.getDestroyMethod() != null) {
        bd.setDestroyMethodName(this.defaults.getDestroyMethod());
        bd.setEnforceDestroyMethod(false);
    }

    if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
        bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    }
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }

    return bd;
}

beanDefinition对象注册到spring注册表

然后进行bean的注册,把beanName和beanDefinition放入注册表中,其实就是一个beanDefinitionMap,注册完成后发送事件,对应的监听器收到事件会处理。bean的注册包括beanDefinition的注册和别名的注册。bean注册的过程比较简单,就是把已经解析好的beanDefinition对象存放到注册表beanDefinitionmap中。

//BeanDefinitionReaderUtils.java
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    //用primary name 注册bean
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    //注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}
//DefaultListableBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
    //最关键的就是把beanDefinition存入beanDefinitionMap
    this.beanDefinitionMap.put(beanName, beanDefinition);
    this.beanDefinitionNames.add(beanName);
}

创建bean实例&初始化

refresh()方法中会调用finishBeanFactoryInitialization进行bean的实例化,前面是设置conversion service和注册字符串解析器用来解析配置,设置LoadTimeWeaverAware,停止使用临时类加载器。核心方法是preInstantiateSingletons(),这一步是初始化所有的非lzay-init bean。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
        beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    //初始化所有的非lazy-init bean
    beanFactory.preInstantiateSingletons();
}

首先获取beanNames,遍历beanNames,对于每一个beanName,先判断是否是factoryBean 实现了factoryBean接口的bean属于factoryBean,获取factoryBean和通常的bean有些不同,需要在beanName前加上’&’前缀 ,例如getBean(&${beanName}),不过通常的bean都不属于factoryBean,我们直接看下面的getBean(beanName)方法。

//org/springframework/beans/factory/support/DefaultListableBeanFactory.java
public void preInstantiateSingletons() throws BeansException {
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            //判断是否factoryBean 实现了factoryBean接口的bean属于factoryBean,获取factoryBean需要在beanName加上'&'前缀
            //通常的bean都直接走下面的getBean分支,不属于factoryBean
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                                                    ((SmartFactoryBean<?>) factory)::isEagerInit,
                                                                    getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                //获取bean,重点
                getBean(beanName);
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

首先转换beanName,factoryBean 需要去掉前面的&。然后根据beanName判断bean是否已经被创建,如果创建则直接从内存中返回bean实例。如果没有创建,看是否正在创建bean,是的话抛异常。不是的话则进入bean的创建流程。判断beanFactory是否包含这个beanName所属的beanDefinition,如果不在看是否在parentBeanFactory中,之后合并parent节点,组装完整的beanDefinition。bean在实例化前需要先实例化依赖的bean,这里会涉及到bean 的循环依赖问题。依赖的bean实例化后,完成自己bean的实例化,不同scope的bean实例化的处理方式稍微不同,这里只看单例 bean的实例化createBean(beanName, mbd, args);

public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    //判断bean是否已被创建
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                             "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        //正在创建实例则抛出异常
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // 判断beanDefinition是否在beanFactory中,如果不在看是否在parentBeanFactory
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            //合并parent节点,组装beanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 需要先保障依赖的bean初始化
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // Create bean instance.
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        //创建bean实例,重点
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        // Explicitly remove instance from singleton cache: It might have been put there
                        // eagerly by the creation process, to allow for circular reference resolution.
                        // Also remove any beans that received a temporary reference to the bean.
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                                                    "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                                    "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                                    ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

创建bean实例

确保此时bean class 已经被解析了,拷贝一个beanDefinition以防动态解析的bean class 不能被存储在一个共享的merged bean definition中,然后在拷贝的beanDefinition 设置beanClass。beanPostProcessor可以干预bean的初始化,此处通过resolveBeforeInstantiation可以在bean实例化前返回一个bean实例的代理,如果没有则进行下面的bean实例创建doCreateBean(beanName, mbdToUse, args);

org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        //clone 一个beanDefinition
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // 在bean初始化前的beanPostProcessor处理,它可以返回一个bean实例的代理
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            //创建bean实例
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        ...省略异常处理
    }

doCreateBean是真正创建bean实例的地方,首先从缓存中获取bean实例,获取不到则通过反射创建一个bean实例。mergedBeanDefinitionProcessor可以通过回调postProcessMergedBeanDefinition修改merged bean definition。之后进行bean的初始化,最后注册bean为可销毁的。这里重点看下bean的实例创建

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    // 先从缓存中获取
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    //真正创建bean实例,通过反射创建
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // Allow post-processors to modify the merged bean definition.
    //mergedBeanDefinitionProcessor可以修改merged bean definition.
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                      isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isTraceEnabled()) {
            logger.trace("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
        }
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        populateBean(beanName, mbd, instanceWrapper);
        //初始化bean实例,后面重点分析
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        }
        else {
            throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
        }
    }

    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                        actualDependentBeans.add(dependentBean);
                    }
                }
                if (!actualDependentBeans.isEmpty()) {
                    throw new BeanCurrentlyInCreationException(beanName,
                                                               "Bean with name '" + beanName + "' has been injected into other beans [" +
                                                               StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                                               "] in its raw version as part of a circular reference, but has eventually been " +
                                                               "wrapped. This means that said other beans do not use the final version of the " +
                                                               "bean. This is often the result of over-eager type matching - consider using " +
                                                               "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

首先确保bean class 已经被解析,这样才能实例化对应的对象。实例化bean有多种策略,根据配置选择合适的方法进行实例化

  • 工厂方法初始化
  • 构造函数自动注入初始化
  • 默认无参构造方法初始化

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
      // Make sure bean class is actually resolved at this point.
      Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
      if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                          "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
      }
    
      Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
      if (instanceSupplier != null) {
          return obtainFromSupplier(instanceSupplier, beanName);
      }
    
      if (mbd.getFactoryMethodName() != null) {
          return instantiateUsingFactoryMethod(beanName, mbd, args);
      }
    
      // Shortcut when re-creating the same bean...
      boolean resolved = false;
      boolean autowireNecessary = false;
      if (args == null) {
          synchronized (mbd.constructorArgumentLock) {
              if (mbd.resolvedConstructorOrFactoryMethod != null) {
                  resolved = true;
                  autowireNecessary = mbd.constructorArgumentsResolved;
              }
          }
      }
      if (resolved) {
          if (autowireNecessary) {
              return autowireConstructor(beanName, mbd, null, null);
          }
          else {
              return instantiateBean(beanName, mbd);
          }
      }
    
      // Candidate constructors for autowiring?
      Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
      if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
          mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
          return autowireConstructor(beanName, mbd, ctors, args);
      }
    
      // Preferred constructors for default construction?
      ctors = mbd.getPreferredConstructors();
      if (ctors != null) {
          return autowireConstructor(beanName, mbd, ctors, null);
      }
    
      // No special handling: simply use no-arg constructor.
      return instantiateBean(beanName, mbd);
    }
    

    这里选取最简单的默认无参构造方法来分析,主要看instantiate(mbd, beanName, parent)

    protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
      try {
          Object beanInstance;
          final BeanFactory parent = this;
          if (System.getSecurityManager() != null) {
              beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                                                           getInstantiationStrategy().instantiate(mbd, beanName, parent),
                                                           getAccessControlContext());
          }
          else {
              beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
          }
          BeanWrapper bw = new BeanWrapperImpl(beanInstance);
          initBeanWrapper(bw);
          return bw;
      }
      catch (Throwable ex) {
          throw new BeanCreationException(
              mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
      }
    }
    

    获取bean class 对象 判断是否是接口,如果是接口抛异常。然后通过反射获取构造方法,最后通过instantiateClass(constructorToUse)方法中的ctor.newInstance(args)完成构造函数的newInstance(),至此bean实例化过程完成。 ```java public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don’t override the class with CGLIB if no overrides. if (!bd.hasMethodOverrides()) {

      Constructor<?> constructorToUse;
      synchronized (bd.constructorArgumentLock) {
          constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
          if (constructorToUse == null) {
              final Class<?> clazz = bd.getBeanClass();
              if (clazz.isInterface()) {
                  throw new BeanInstantiationException(clazz, "Specified class is an interface");
              }
              try {
                  if (System.getSecurityManager() != null) {
                      constructorToUse = AccessController.doPrivileged(
                          (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                  }
                  else {
                      constructorToUse = clazz.getDeclaredConstructor();
                  }
                  bd.resolvedConstructorOrFactoryMethod = constructorToUse;
              }
              catch (Throwable ex) {
                  throw new BeanInstantiationException(clazz, "No default constructor found", ex);
              }
          }
      }
      return BeanUtils.instantiateClass(constructorToUse);
    

    } else {

      // Must generate CGLIB subclass.
      return instantiateWithMethodInjection(bd, beanName, owner);
    

    } }

public static T instantiateClass(Constructor ctor, Object… args) throws BeanInstantiationException { Assert.notNull(ctor, “Constructor must not be null”); try { ReflectionUtils.makeAccessible(ctor); //最终实例化的完成 return ctor.newInstance(args); } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, “Is it an abstract class?”, ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, “Is the constructor accessible?”, ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, “Illegal arguments for constructor”, ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, “Constructor threw exception”, ex.getTargetException()); } }


<a name="NJ65E"></a>
### bean的初始化
主要是回调一系列 Aware方法、initMethod方法和 bean post processors对bean初始化进行前处理和后处理。
```java
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

扩展点

BeanPostProcessor

beanPostProcessor是spring为修改bean提供的扩展点,postProcessBeforeInitialization在bean实例化后,初始化前调用,postProcessAfterInitialization在bean初始化后调用。

public interface BeanPostProcessor {

    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

在spring容器的启动入口refresh()方法中完成beanFactory的实例创建后会调用prepareBeanFactory,prepareBeanFactory主要是设置factoryBean的属性,beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))这行代码会创建ApplicationContextAwareProcesso实例并注册到beanFactory。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // Tell the internal bean factory to use the context's class loader etc.
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // Configure the bean factory with context callbacks.
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // Register early post-processor for detecting inner beans as ApplicationListeners.
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

ApplicationContextAwareProcessor实现了BeanPostProcessor重写postProcessBeforeInitialization,里面调用了invokeAwareInterfaces(bean)方法,这里通过回调把spring资源注入到bean。

class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ConfigurableApplicationContext applicationContext;

    private final StringValueResolver embeddedValueResolver;


    /**
     * Create a new ApplicationContextAwareProcessor for the given context.
     */
    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    }


    @Override
    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
            return bean;
        }

        AccessControlContext acc = null;

        if (System.getSecurityManager() != null) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
        }
        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }
        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
        }
        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
        }
        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
        }
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
        }
    }

}

BeanFactoryPostProcessor

BeanFactoryPostProcessor只有postProcessBeanFactory一个接口,postProcessBeanFactory可以在BeanFactory完成实例化后修改容器内部的BeanFactory。在spring容器的启动入口refresh()方法中完成beanFactory的实例创建后会调用,这时候所有的bean都被加载,但是没有bean被初始化。这就允许BeanFactoryPostProcessor重写或者添加配置,甚至可以提前初始化bean。

public interface BeanFactoryPostProcessor {

    /**
     * Modify the application context's internal bean factory after its standard
     * initialization. All bean definitions will have been loaded, but no beans
     * will have been instantiated yet. This allows for overriding or adding
     * properties even to eager-initializing beans.
     * @param beanFactory the bean factory used by the application context
     * @throws org.springframework.beans.BeansException in case of errors
     */
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

public void refresh(){
    // 创建DefaultListableBeanFactory,完成bean配置的读取、解析,核心方法,下面分析
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);

    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);
}

xxxAware接口

若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖。所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源。
Spring 中对beanFactory容器提供的 Aware 接口有:

  1. BeanNameAware:注入当前 bean 对应 beanName;
  2. BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader;
  3. BeanFactoryAware:注入 当前BeanFactory容器 的引用。

    //org/springframework/context/support/ApplicationContextAwareProcessor.java
    private void invokeAwareMethods(final String beanName, final Object bean) {
     if (bean instanceof Aware) {
         if (bean instanceof BeanNameAware) {
             ((BeanNameAware) bean).setBeanName(beanName);
         }
         if (bean instanceof BeanClassLoaderAware) {
             ClassLoader bcl = getBeanClassLoader();
             if (bcl != null) {
                 ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
             }
         }
         if (bean instanceof BeanFactoryAware) {
             ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
         }
     }
    }
    

    Spring对ApplicationContext类型容器也提供了Aware接口,这些 Aware 接口的注入实现,是通过 BeanPostProcessor 的方式注入的,具体过程在beanPostProcessor中已经分析

  4. EnvironmentAware:注入 Enviroment,一般用于获取配置属性;

  5. EmbeddedValueResolverAware:注入 EmbeddedValueResolver(Spring EL解析器),一般用于参数解析;
  6. ApplicationContextAware(ResourceLoader、ApplicationEventPublisherAware、MessageSourceAware):注入 ApplicationContext 容器本身。
    //org/springframework/context/support/ApplicationContextAwareProcessor.java
    private void invokeAwareInterfaces(Object bean) {
     if (bean instanceof EnvironmentAware) {
         ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
     }
     if (bean instanceof EmbeddedValueResolverAware) {
         ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
     }
     if (bean instanceof ResourceLoaderAware) {
         ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
     }
     if (bean instanceof ApplicationEventPublisherAware) {
         ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
     }
     if (bean instanceof MessageSourceAware) {
         ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
     }
     if (bean instanceof ApplicationContextAware) {
         ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
     }
    }
    

    参考文献

    spring源码分析
    spring容器的本质
    https://spring.io/projects/spring-framework
    factoryBean
    beanPostProcessor 和beanFactoryPostProcessor
    spring bean 生命周期