You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1 lines
44 KiB

<!doctypehtml><html lang=zh-CN><meta charset=UTF-8><meta content=width=device-width name=viewport><meta media="(prefers-color-scheme: light)" content=#222 name=theme-color><meta media="(prefers-color-scheme: dark)" content=#222 name=theme-color><meta content="Hexo 7.3.0" name=generator><link href=https://cdnjs.cloudflare.com rel=preconnect><link href=/images/apple-touch-icon-next.png rel=apple-touch-icon sizes=180x180><link href=/images/favicon-32x32-next.png rel=icon sizes=32x32 type=image/png><link href=/images/favicon-16x16-next.png rel=icon sizes=16x16 type=image/png><link color=#222 href=/images/logo.svg rel=mask-icon><meta content=2X6S9P7CAjXjVvw8YyQR8pCu-B0oEu7O9quLgxXuWyA name=google-site-verification><meta content=dV8JGNzi0c name=baidu-site-verification><script>!function(){var t=!1;function e(){var e;t||(t=!0,(e=document.createElement("script")).setAttribute("data-ad-client","ca-pub-7480618470784058"),e.async=!0,e.src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",document.head.appendChild(e))}function a(){"requestIdleCallback"in window?window.requestIdleCallback(e,{timeout:5e3}):window.setTimeout(e,5e3)}"complete"===document.readyState?a():window.addEventListener("load",a,{once:!0})}()</script><link href=/css/main.css rel=stylesheet><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css integrity=sha256-VHqXKFhhMxcpubYf9xiWdCiojEbY9NexQ4jh8AxbvcM= rel=stylesheet><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/6.1.14/fancybox/fancybox.css integrity=sha256-mdaMxrItEW6hMIVJJNPKuX0B7KCSJQVEv3mVY4N2we4= rel=stylesheet><script class=next-config data-name=main type=application/json>{"hostname":"nicksxs.me","root":"/","images":"/images","scheme":"Pisces","darkmode":true,"version":"8.29.0","exturl":false,"sidebar":{"position":"left","width_expanded":320,"width_dual_column":240,"display":"post","padding":18,"offset":12},"hljswrap":true,"codeblock":{"theme":{"light":"default","dark":"stackoverflow-dark"},"prism":{"light":"prism","dark":"prism-dark"},"copy_button":{"enable":true,"style":"default"},"fold":{"enable":false,"height":500},"language":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":true,"nav":null},"stickytabs":false,"motion":{"enable":false,"async":false,"duration":200,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"},"algolia":{"appID":"663Q99OQQD","apiKey":"e461a1371d12cec1491c1153b288a9ed","indexName":"nicksxs","hits":{"per_page":10}}}</script><script defer src=/js/config.js></script><meta content="这个话题是由一次组内同学分享引出来的,首先在 springboot 2.x 开始默认使用了 cglib 作为 aop 的实现,这里也稍微讲一下,在一个 1.x 的老项目里,可以看到AopAutoConfiguration 是这样的" name=description><meta content=article property=og:type><meta content="聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点" property=og:title><meta content=https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/index.html property=og:url><meta content="Nicksxs's Blog" property=og:site_name><meta content="这个话题是由一次组内同学分享引出来的,首先在 springboot 2.x 开始默认使用了 cglib 作为 aop 的实现,这里也稍微讲一下,在一个 1.x 的老项目里,可以看到AopAutoConfiguration 是这样的" property=og:description><meta content=zh_CN property=og:locale><meta content=https://img.nicksxs.me/uPic/EdR7oB.png property=og:image><meta content=2021-09-19T14:56:31.000Z property=article:published_time><meta content=2021-09-19T14:56:31.000Z property=article:modified_time><meta content=Nicksxs property=article:author><meta content=Java property=article:tag><meta content=Spring property=article:tag><meta content=SpringBoot property=article:tag><meta content=cglib property=article:tag><meta content=事务 property=article:tag><meta content=summary name=twitter:card><meta content=https://img.nicksxs.me/uPic/EdR7oB.png name=twitter:image><link href=https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ rel=canonical><script class=next-config data-name=page type=application/json>{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/","path":"2021/09/19/聊一下-SpringBoot-中使用的-cglib-作为动态代理中的一个注意点/","title":"聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点"}</script><script class=next-config data-name=calendar type=application/json>""</script><title>聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点 | Nicksxs's Blog</title><script async src=https://www.googletagmanager.com/gtag/js?id=UA-61358619-1></script><script class=next-config data-name=google_analytics type=application/json>{"tracking_id":"UA-61358619-1","only_pageview":false,"measure_protocol_api_secret":null}</script><script defer src=/js/third-party/analytics/google-analytics.js></script><script defer src=/js/third-party/analytics/baidu-analytics.js></script><script async src=https://hm.baidu.com/hm.js?20f33b3c0c0eff9b1522999c0015646d></script><script crossorigin=anonymous defer integrity=sha256-QnJV4HT5r8i89ovZGRD86iynZqHerEbT2xt69vDM36I= src=https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/6.1.14/fancybox/fancybox.umd.js></script><script defer src=/js/utils.js></script><script defer src=/js/sidebar.js></script><script defer src=/js/next-boot.js></script><script data-algolia-integrity=sha256-o49zoHLDPBm9WLg6AiliAVi3axCRTqe3ltTxLvhzAVg= data-algolia-src=https://cdnjs.cloudflare.com/ajax/libs/algoliasearch/5.36.0/lite/builds/browser.umd.js data-search-src=/js/third-party/search/algolia-search.js src=/js/third-party/search/algolia-search-loader.js></script><script defer src=/js/third-party/fancybox.js></script><noscript><link href=/css/noscript.css rel=stylesheet></noscript><link title="Nicksxs's Blog" href=/atom.xml rel=alternate type=application/atom+xml><body itemscope itemtype=http://schema.org/WebPage><div class=headband></div><main class=main><div class=column><header class=header itemscope itemtype=http://schema.org/WPHeader><div class=site-brand-container><div class=site-nav-toggle><div aria-label=切换导航栏 class=toggle role=button><span class=toggle-line></span><span class=toggle-line></span><span class=toggle-line></span></div></div><div class=site-meta><a class=brand href=/ rel=start><i class=logo-line></i><p class=site-title>Nicksxs's Blog</p><i class=logo-line></i></a><p class=site-subtitle itemprop=description>Java 运行时、生产诊断与 AI 工程实践</div><div class=site-nav-right><div class="toggle popup-trigger" aria-label=搜索 role=button><i class="fa fa-search fa-fw fa-lg"></i></div></div></div><nav class=site-nav><ul class="main-menu menu"><li class="menu-item menu-item-home"><a href=/ rel=section><i class="fa fa-home fa-fw"></i>首页</a><li class="menu-item menu-item-专题"><a href=/topics/ rel=section><i class="fa fa-layer-group fa-fw"></i>专题</a><li class="menu-item menu-item-工具"><a href=/tools/ rel=section><i class="fa fa-toolbox fa-fw"></i>工具</a><li class="menu-item menu-item-about"><a href=/about/ rel=section><i class="fa fa-user fa-fw"></i>关于我</a><li class="menu-item menu-item-tags"><a href=/tags/ rel=section><i class="fa fa-tags fa-fw"></i>标签</a><li class="menu-item menu-item-categories"><a href=/categories/ rel=section><i class="fa fa-th fa-fw"></i>分类</a><li class="menu-item menu-item-archives"><a href=/archives/ rel=section><i class="fa fa-archive fa-fw"></i>归档</a><li class="menu-item menu-item-search"><a class=popup-trigger role=button><i class="fa fa-search fa-fw"></i>搜索</a></ul></nav><div class=search-pop-overlay><div class="popup search-popup"><div class=search-header><span class=search-icon><i class="fa fa-search"></i></span><div class=search-input-container><input autocapitalize=off autocomplete=off class=search-input maxlength=80 placeholder=搜索... spellcheck=false type=search></div><span class=popup-btn-close role=button><i class="fa fa-times-circle"></i></span></div><div class=search-result-container><div class=search-result-icon><i class="fab fa-algolia fa-5x"></i></div></div></div></div></header><aside class=sidebar><div class="sidebar-inner sidebar-overview-active"><ul class=sidebar-nav><li class=sidebar-nav-toc>文章目录<li class=sidebar-nav-overview>站点概览</ul><div class=sidebar-panel-container><div class="post-toc-wrap sidebar-panel"></div><div class="site-overview-wrap sidebar-panel"><div class="site-author animated" itemprop=author itemscope itemtype=http://schema.org/Person><img alt=Nicksxs class=site-author-image itemprop=image src=/uploads/avatar.jpg><p class=site-author-name itemprop=name>Nicksxs<div class=site-description itemprop=description>Nicksxs 的技术博客,深入 Java 运行时与生产诊断、低成本大模型推理和 Agent 工程实践。</div></div><div class="site-state-wrap animated"><nav class=site-state><div class="site-state-item site-state-posts"><a href=/archives/><span class=site-state-item-count>394</span> <span class=site-state-item-name>日志</span></a></div><div class="site-state-item site-state-categories"><a href=/categories/><span class=site-state-item-count>181</span> <span class=site-state-item-name>分类</span></a></div><div class="site-state-item site-state-tags"><a href=/tags/><span class=site-state-item-count>347</span> <span class=site-state-item-name>标签</span></a></div></nav></div><div class="links-of-author animated"><span class=links-of-author-item><a rel="noopener me" title="GitHub → https://github.com/nicksxs" href=https://github.com/nicksxs target=_blank><i class="fab fa-github fa-fw"></i>GitHub</a> </span><span class=links-of-author-item><a rel="noopener me" title="E-Mail → mailto:nicksxs1202@gmail.com" href=mailto:nicksxs1202@gmail.com target=_blank><i class="fa fa-envelope fa-fw"></i>E-Mail</a></span></div><div class="cc-license animated" itemprop=license><a class=cc-opacity href=https://creativecommons.org/licenses/by-nc-sa/4.0/ rel=noopener target=_blank><img alt="Creative Commons" src=https://cdnjs.cloudflare.com/ajax/libs/creativecommons-vocabulary/2020.11.3/assets/license_badges/small/by_nc_sa.svg></a></div><div class="widget-wrap sidebar-tag-cloud"><div class=tag-cloud-tags><a class=tag-cloud-10 href=/tags/Java/ style=font-size:16px>Java</a><a class=tag-cloud-9 href=/tags/leetcode/ style=font-size:15.62px>leetcode</a><a class=tag-cloud-8 href=/tags/LLM/ style=font-size:15.23px>LLM</a><a class=tag-cloud-8 href=/tags/%E7%94%9F%E6%B4%BB/ style=font-size:14.85px>生活</a><a class=tag-cloud-7 href=/tags/%E9%A2%98%E8%A7%A3/ style=font-size:14.46px>题解</a><a class=tag-cloud-6 href=/tags/SpringBoot/ style=font-size:14.08px>SpringBoot</a><a class=tag-cloud-6 href=/tags/MySQL/ style=font-size:14.08px>MySQL</a><a class=tag-cloud-5 href=/tags/C/ style=font-size:13.69px>C++</a><a class=tag-cloud-5 href=/tags/Redis/ style=font-size:13.31px>Redis</a><a class=tag-cloud-4 href=/tags/Tomcat/ style=font-size:12.92px>Tomcat</a><a class=tag-cloud-4 href=/tags/Mybatis/ style=font-size:12.92px>Mybatis</a><a class=tag-cloud-3 href=/tags/%E5%B0%8F%E6%8A%80%E5%B7%A7/ style=font-size:12.54px>小技巧</a><a class=tag-cloud-2 href=/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/ style=font-size:12.15px>数据结构</a><a class=tag-cloud-2 href=/tags/%E6%BA%90%E7%A0%81/ style=font-size:12.15px>源码</a><a class=tag-cloud-2 href=/tags/MQ/ style=font-size:11.77px>MQ</a><a class=tag-cloud-2 href=/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/ style=font-size:11.77px>消息队列</a><a class=tag-cloud-2 href=/tags/RocketMQ/ style=font-size:11.77px>RocketMQ</a><a class=tag-cloud-2 href=/tags/%E8%BF%90%E5%8A%A8/ style=font-size:11.77px>运动</a><a class=tag-cloud-1 href=/tags/php/ style=font-size:11.38px>php</a><a class=tag-cloud-0 href=/tags/Spring/ style=font-size:11px>Spring</a><a class=tag-cloud-0 href=/tags/linux/ style=font-size:11px>linux</a><a class=tag-cloud-0 href=/tags/Docker/ style=font-size:11px>Docker</a><a class=tag-cloud-0 href=/tags/%E5%87%8F%E8%82%A5/ style=font-size:11px>减肥</a><a class=tag-cloud-0 href=/tags/%E8%B7%91%E6%AD%A5/ style=font-size:11px>跑步</a></div></div><div class="affiliate-creative affiliate-creative--sidebar" data-affiliate-id=tencent-cloud-general><a rel="sponsored noopener" aria-label=腾讯云产品优惠 href=https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=2e33a1eedb380997d03618b4a5ba6ca7&from=console target=_blank><img alt=腾讯云服务器、数据库和云产品优惠 decoding=async height=419 loading=lazy src=/uploads/affiliate/tencent-cloud-general.webp width=690> </a><span class=affiliate-disclosure>推广</span></div></div></div></div><div class="sidebar-inner sidebar-blogroll"><div class="links-of-blogroll animated"><div class=links-of-blogroll-title><i class="fa fa-globe fa-fw"></i> 链接</div><ul class=links-of-blogroll-list><li class=links-of-blogroll-item><a href=https://covermusic.cn/ rel=noopener target=_blank title=https://covermusic.cn>69伙伴</a></ul></div></div></aside></div><div class="main-inner post posts-expand"><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article lang=zh-CN><link href=https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="Nicksxs 的技术博客,深入 Java 运行时与生产诊断、低成本大模型推理和 Agent 工程实践。" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点 | Nicksxs's Blog" itemprop=name><meta content="这个话题是由一次组内同学分享引出来的,首先在 springboot 2.x 开始默认使用了 cglib 作为 aop 的实现,这里也稍微讲一下,在一个 1.x 的老项目里,可以看到AopAutoConfiguration 是这样的" itemprop=description></span><header class=post-header><h1 itemprop="name headline" class=post-title>聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点</h1><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2021-09-19 22:56:31" datetime=2021-09-19T22:56:31+08:00>2021-09-19</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/ itemprop=url rel=index><span itemprop=name>Java</span></a> </span>, <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Java/SpringBoot/ itemprop=url rel=index><span itemprop=name>SpringBoot</span></a> </span></span><span class="post-meta-item cloudflare-page-counter" data-title="聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点" data-increment=true data-path=/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=cloudflare-page-counter-count></span></span></div><div class=post-description>这个话题是由一次组内同学分享引出来的,首先在 springboot 2.x 开始默认使用了 cglib 作为 aop 的实现,这里也稍微讲一下,在一个 1.x 的老项目里,可以看到AopAutoConfiguration 是这样的</div></div></header><div class=post-body itemprop=articleBody><p>这个话题是由一次组内同学分享引出来的,首先在 springboot 2.x 开始默认使用了 cglib 作为 aop 的实现,这里也稍微讲一下,在一个 1.x 的老项目里,可以看到AopAutoConfiguration 是这样的<figure class="highlight java"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br></pre><td class=code><pre><span class=line><span class=meta>@Configuration</span></span><br><span class=line><span class=meta>@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })</span></span><br><span class=line><span class=meta>@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)</span></span><br><span class=line><span class=keyword>public</span> <span class=keyword>class</span> <span class="title class_">AopAutoConfiguration</span> {</span><br><span class=line></span><br><span class=line> <span class=meta>@Configuration</span></span><br><span class=line> <span class=meta>@EnableAspectJAutoProxy(proxyTargetClass = false)</span></span><br><span class=line> <span class=meta>@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)</span></span><br><span class=line> <span class=keyword>public</span> <span class=keyword>static</span> <span class=keyword>class</span> <span class="title class_">JdkDynamicAutoProxyConfiguration</span> {</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=meta>@Configuration</span></span><br><span class=line> <span class=meta>@EnableAspectJAutoProxy(proxyTargetClass = true)</span></span><br><span class=line> <span class=meta>@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)</span></span><br><span class=line> <span class=keyword>public</span> <span class=keyword>static</span> <span class=keyword>class</span> <span class="title class_">CglibAutoProxyConfiguration</span> {</span><br><span class=line> }</span><br><span class=line></span><br><span class=line>}</span><br></pre></table></figure><p>而在 2.x 中变成了这样<figure class="highlight java"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br><span class=line>19</span><br><span class=line>20</span><br><span class=line>21</span><br><span class=line>22</span><br><span class=line>23</span><br><span class=line>24</span><br></pre><td class=code><pre><span class=line><span class=meta>@Configuration(proxyBeanMethods = false)</span></span><br><span class=line><span class=meta>@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)</span></span><br><span class=line><span class=keyword>public</span> <span class=keyword>class</span> <span class="title class_">AopAutoConfiguration</span> {</span><br><span class=line></span><br><span class=line> <span class=meta>@Configuration(proxyBeanMethods = false)</span></span><br><span class=line> <span class=meta>@ConditionalOnClass(Advice.class)</span></span><br><span class=line> <span class=keyword>static</span> <span class=keyword>class</span> <span class="title class_">AspectJAutoProxyingConfiguration</span> {</span><br><span class=line></span><br><span class=line> <span class=meta>@Configuration(proxyBeanMethods = false)</span></span><br><span class=line> <span class=meta>@EnableAspectJAutoProxy(proxyTargetClass = false)</span></span><br><span class=line> <span class=meta>@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")</span></span><br><span class=line> <span class=keyword>static</span> <span class=keyword>class</span> <span class="title class_">JdkDynamicAutoProxyConfiguration</span> {</span><br><span class=line></span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=meta>@Configuration(proxyBeanMethods = false)</span></span><br><span class=line> <span class=meta>@EnableAspectJAutoProxy(proxyTargetClass = true)</span></span><br><span class=line> <span class=meta>@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",</span></span><br><span class=line><span class=meta> matchIfMissing = true)</span></span><br><span class=line> <span class=keyword>static</span> <span class=keyword>class</span> <span class="title class_">CglibAutoProxyConfiguration</span> {</span><br><span class=line></span><br><span class=line> }</span><br><span class=line></span><br><span class=line> }</span><br></pre></table></figure><p>为何会加载 AopAutoConfiguration 在前面的文章<a href=https://nicksxs.me/2021/07/11/%E8%81%8A%E8%81%8ASpringBoot-%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D/>聊聊 SpringBoot 自动装配</a>里已经介绍过,有兴趣的可以看下,可以发现 springboot 在 2.x 版本开始使用 cglib 作为默认的动态代理实现。<p>然后就是出现的问题了,代码是这样的,一个简单的基于 springboot 的带有数据库的插入,对插入代码加了事务注解,<figure class="highlight java"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br><span class=line>19</span><br><span class=line>20</span><br><span class=line>21</span><br><span class=line>22</span><br><span class=line>23</span><br><span class=line>24</span><br><span class=line>25</span><br><span class=line>26</span><br><span class=line>27</span><br><span class=line>28</span><br><span class=line>29</span><br><span class=line>30</span><br><span class=line>31</span><br><span class=line>32</span><br><span class=line>33</span><br><span class=line>34</span><br><span class=line>35</span><br><span class=line>36</span><br><span class=line>37</span><br><span class=line>38</span><br><span class=line>39</span><br><span class=line>40</span><br><span class=line>41</span><br><span class=line>42</span><br></pre><td class=code><pre><span class=line><span class=meta>@Mapper</span></span><br><span class=line><span class=keyword>public</span> <span class=keyword>interface</span> <span class="title class_">StudentMapper</span> {</span><br><span class=line> <span class=comment>// 就是插入一条数据</span></span><br><span class=line> <span class=meta>@Insert("insert into student(name, age)" + "values ('nick', '18')")</span></span><br><span class=line> <span class=keyword>public</span> Long <span class="title function_">insert</span><span class=params>()</span>;</span><br><span class=line>}</span><br><span class=line></span><br><span class=line><span class=meta>@Component</span></span><br><span class=line><span class=keyword>public</span> <span class=keyword>class</span> <span class="title class_">StudentManager</span> {</span><br><span class=line></span><br><span class=line> <span class=meta>@Resource</span></span><br><span class=line> <span class=keyword>private</span> StudentMapper studentMapper;</span><br><span class=line> </span><br><span class=line> <span class=keyword>public</span> Long <span class="title function_">createStudent</span><span class=params>()</span> {</span><br><span class=line> <span class=keyword>return</span> studentMapper.insert();</span><br><span class=line> }</span><br><span class=line>}</span><br><span class=line></span><br><span class=line><span class=meta>@Component</span></span><br><span class=line><span class=keyword>public</span> <span class=keyword>class</span> <span class="title class_">StudentServiceImpl</span> <span class=keyword>implements</span> <span class="title class_">StudentService</span> {</span><br><span class=line></span><br><span class=line> <span class=meta>@Resource</span></span><br><span class=line> <span class=keyword>private</span> StudentManager studentManager;</span><br><span class=line></span><br><span class=line> <span class=comment>// 自己引用</span></span><br><span class=line> <span class=meta>@Resource</span></span><br><span class=line> <span class=keyword>private</span> StudentServiceImpl studentService;</span><br><span class=line></span><br><span class=line> <span class=meta>@Override</span></span><br><span class=line> <span class=meta>@Transactional</span></span><br><span class=line> <span class=keyword>public</span> Long <span class="title function_">createStudent</span><span class=params>()</span> {</span><br><span class=line> <span class=type>Long</span> <span class=variable>id</span> <span class=operator>=</span> studentManager.createStudent();</span><br><span class=line> <span class=type>Long</span> <span class=variable>id2</span> <span class=operator>=</span> studentService.createStudent2();</span><br><span class=line> <span class=keyword>return</span> <span class=number>1L</span>;</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=meta>@Transactional</span></span><br><span class=line> <span class=keyword>private</span> Long <span class="title function_">createStudent2</span><span class=params>()</span> {</span><br><span class=line><span class=comment>// Integer t = Integer.valueOf("aaa");</span></span><br><span class=line> <span class=keyword>return</span> studentManager.createStudent();</span><br><span class=line> }</span><br><span class=line>}</span><br></pre></table></figure><p>第一个公有方法 createStudent 首先调用了 manager 层的创建方法,然后再通过引入的 studentService 调用了createStudent2,我们先跑一下看看会出现啥情况,果不其然报错了,正是这个报错让我纠结了很久<p><img alt=EdR7oB loading=lazy src=https://img.nicksxs.me/uPic/EdR7oB.png><p>报了个空指针,而且是在 createStudent2 已经被调用到了,在它的内部,报的 studentManager 是 null,首先 cglib 作为动态代理它是通过继承的方式来实现的,相当于是会在调用目标对象的代理方法时调用 cglib 生成的子类,具体的代理切面逻辑在子类实现,然后在调用目标对象的目标方法,但是继承的方式对于 final 和私有方法其实是没法进行代理的,因为没法继承,所以我最开始的想法是应该通过 studentService 调用 createStudent2 的时候就报错了,也就是不会进入这个方法内部,后面才发现犯了个特别二的错误,继承的方式去调用父类的私有方法,对于 Java 来说是可以调用到的,父类的私有方法并不由子类的InstanceKlass维护,只能通过子类的InstanceKlass找到Java类对应的_super,这样间接地访问。也就是说子类其实是可以访问的,那为啥访问了会报空指针呢,这里报的是studentManager 是空的,可以往依赖注入方面去想,如果忽略依赖注入,我这个studentManager 的确是 null,那是不是就没有被依赖注入呢,但是为啥前面那个可以呢<p>这个问题着实查了很久,不废话来看代码<figure class="highlight java"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br></pre><td class=code><pre><span class=line><span class=meta>@Override</span></span><br><span class=line> <span class=keyword>protected</span> Object <span class="title function_">invokeJoinpoint</span><span class=params>()</span> <span class=keyword>throws</span> Throwable {</span><br><span class=line> <span class=keyword>if</span> (<span class=built_in>this</span>.methodProxy != <span class=literal>null</span>) {</span><br><span class=line> <span class=comment>// 这里的 target 就是被代理的 bean</span></span><br><span class=line> <span class=keyword>return</span> <span class=built_in>this</span>.methodProxy.invoke(<span class=built_in>this</span>.target, <span class=built_in>this</span>.arguments);</span><br><span class=line> }</span><br><span class=line> <span class=keyword>else</span> {</span><br><span class=line> <span class=keyword>return</span> <span class=built_in>super</span>.invokeJoinpoint();</span><br><span class=line> }</span><br><span class=line> }</span><br></pre></table></figure><p>这个是<code>org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation</code>的代码,其实它在这里不是直接调用 super 也就是父类的方法,而是通过 methodProxy 调用 target 目标对象的方法,也就是原始的 studentService bean 的方法,这样子 spring 管理的已经做好依赖注入的 bean 就能正常起作用,否则就会出现上面的问题,因为 cglib 其实是通过继承来实现,通过将调用转移到子类上加入代理逻辑,我们在简单使用的时候会直接 invokeSuper() 调用父类的方法,但是在这里 spring 的场景里需要去支持 spring 的功能逻辑,所以上面的问题就可以开始来解释了,因为 createStudent 是公共方法,cglib 可以对其进行继承代理,但是在执行逻辑的时候其实是通过调用目标对象,也就是 spring 管理的被代理的目标对象的 bean 调用的 createStudent,而对于下面的 createStudent2 方法因为是私有方法,不会走代理逻辑,也就不会有调用回目标对象的逻辑,只是通过继承关系,在子类中没有这个方法,所以会通过子类的InstanceKlass找到这个类对应的_super,然后调用父类的这个私有方法,这里要搞清楚一个点,从这个代理类直接找到其父类然后调用这个私有方法,这个类是由 cglib 生成的,不是被 spring 管理起来经过依赖注入的 bean,所以是没有 studentManager 这个依赖的,也就出现了前面的问题<p>而在前面提到的cglib通过methodProxy调用到目标对象,目标对象是在什么时候设置的呢,其实是在bean的生命周期中,org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization这个接口的在bean的初始化过程中,会调用实现了这个接口的方法,<figure class="highlight java"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br></pre><td class=code><pre><span class=line><span class=meta>@Override</span></span><br><span class=line><span class=keyword>public</span> Object <span class="title function_">postProcessAfterInitialization</span><span class=params>(<span class=meta>@Nullable</span> Object bean, String beanName)</span> {</span><br><span class=line> <span class=keyword>if</span> (bean != <span class=literal>null</span>) {</span><br><span class=line> <span class=type>Object</span> <span class=variable>cacheKey</span> <span class=operator>=</span> getCacheKey(bean.getClass(), beanName);</span><br><span class=line> <span class=keyword>if</span> (<span class=built_in>this</span>.earlyProxyReferences.remove(cacheKey) != bean) {</span><br><span class=line> <span class=keyword>return</span> wrapIfNecessary(bean, beanName, cacheKey);</span><br><span class=line> }</span><br><span class=line> }</span><br><span class=line> <span class=keyword>return</span> bean;</span><br><span class=line>}</span><br></pre></table></figure><p>具体的逻辑在 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary这个方法里<figure class="highlight java"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br><span class=line>19</span><br><span class=line>20</span><br><span class=line>21</span><br><span class=line>22</span><br><span class=line>23</span><br><span class=line>24</span><br><span class=line>25</span><br><span class=line>26</span><br><span class=line>27</span><br><span class=line>28</span><br><span class=line>29</span><br><span class=line>30</span><br><span class=line>31</span><br><span class=line>32</span><br><span class=line>33</span><br><span class=line>34</span><br><span class=line>35</span><br><span class=line>36</span><br><span class=line>37</span><br><span class=line>38</span><br><span class=line>39</span><br><span class=line>40</span><br><span class=line>41</span><br><span class=line>42</span><br></pre><td class=code><pre><span class=line><span class=keyword>protected</span> Object <span class="title function_">getCacheKey</span><span class=params>(Class&LT?> beanClass, <span class=meta>@Nullable</span> String beanName)</span> {</span><br><span class=line> <span class=keyword>if</span> (StringUtils.hasLength(beanName)) {</span><br><span class=line> <span class=keyword>return</span> (FactoryBean.class.isAssignableFrom(beanClass) ?</span><br><span class=line> BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);</span><br><span class=line> }</span><br><span class=line> <span class=keyword>else</span> {</span><br><span class=line> <span class=keyword>return</span> beanClass;</span><br><span class=line> }</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=comment>/**</span></span><br><span class=line><span class=comment> * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.</span></span><br><span class=line><span class=comment> * <span class=doctag>@param</span> bean the raw bean instance</span></span><br><span class=line><span class=comment> * <span class=doctag>@param</span> beanName the name of the bean</span></span><br><span class=line><span class=comment> * <span class=doctag>@param</span> cacheKey the cache key for metadata access</span></span><br><span class=line><span class=comment> * <span class=doctag>@return</span> a proxy wrapping the bean, or the raw bean instance as-is</span></span><br><span class=line><span class=comment> */</span></span><br><span class=line> <span class=keyword>protected</span> Object <span class="title function_">wrapIfNecessary</span><span class=params>(Object bean, String beanName, Object cacheKey)</span> {</span><br><span class=line> <span class=keyword>if</span> (StringUtils.hasLength(beanName) && <span class=built_in>this</span>.targetSourcedBeans.contains(beanName)) {</span><br><span class=line> <span class=keyword>return</span> bean;</span><br><span class=line> }</span><br><span class=line> <span class=keyword>if</span> (Boolean.FALSE.equals(<span class=built_in>this</span>.advisedBeans.get(cacheKey))) {</span><br><span class=line> <span class=keyword>return</span> bean;</span><br><span class=line> }</span><br><span class=line> <span class=keyword>if</span> (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {</span><br><span class=line> <span class=built_in>this</span>.advisedBeans.put(cacheKey, Boolean.FALSE);</span><br><span class=line> <span class=keyword>return</span> bean;</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=comment>// Create proxy if we have advice.</span></span><br><span class=line> Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, <span class=literal>null</span>);</span><br><span class=line> <span class=keyword>if</span> (specificInterceptors != DO_NOT_PROXY) {</span><br><span class=line> <span class=built_in>this</span>.advisedBeans.put(cacheKey, Boolean.TRUE);</span><br><span class=line> <span class=type>Object</span> <span class=variable>proxy</span> <span class=operator>=</span> createProxy(</span><br><span class=line> bean.getClass(), beanName, specificInterceptors, <span class=keyword>new</span> <span class="title class_">SingletonTargetSource</span>(bean));</span><br><span class=line> <span class=built_in>this</span>.proxyTypes.put(cacheKey, proxy.getClass());</span><br><span class=line> <span class=keyword>return</span> proxy;</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=built_in>this</span>.advisedBeans.put(cacheKey, Boolean.FALSE);</span><br><span class=line> <span class=keyword>return</span> bean;</span><br><span class=line> }</span><br></pre></table></figure><p>然后在 <code>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy</code> 中创建了代理类</div><footer class=post-footer><div class="affiliate-creative affiliate-creative--post-end" data-affiliate-id=tencent-cloud-general><a rel="sponsored noopener" aria-label=腾讯云产品优惠 href=https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=2e33a1eedb380997d03618b4a5ba6ca7&from=console target=_blank><img alt=腾讯云服务器、数据库和云产品优惠 decoding=async height=419 loading=lazy src=/uploads/affiliate/tencent-cloud-general.webp width=690> </a><span class=affiliate-disclosure>推广</span></div><div class=reward-container><div>请我一杯咖啡吧!</div><button>赞赏</button><div class=post-reward><div><img alt="Nicksxs 微信" src=https://i.loli.net/2020/01/12/NUlWanT31E8LQGx.png><span>微信</span></div><div><img alt="Nicksxs 支付宝" src=https://ooo.0o0.ooo/2016/08/17/57b421e773057.jpg><span>支付宝</span></div></div></div><div class=post-copyright><ul><li class=post-copyright-author><strong>本文作者: </strong>Nicksxs<li class=post-copyright-link><strong>本文链接:</strong> <a title="聊一下 SpringBoot 中使用的 cglib 作为动态代理中的一个注意点" href=https://nicksxs.me/2021/09/19/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84-cglib-%E4%BD%9C%E4%B8%BA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B3%A8%E6%84%8F%E7%82%B9/>https://nicksxs.me/2021/09/19/聊一下-SpringBoot-中使用的-cglib-作为动态代理中的一个注意点/</a><li class=post-copyright-license><strong>版权声明: </strong>本博客所有文章除特别声明外,均采用 <a href=https://creativecommons.org/licenses/by-nc-sa/4.0/ rel=noopener target=_blank><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处!</ul></div><div class=post-tags><a href=/tags/Java/ rel=tag># Java</a><a href=/tags/Spring/ rel=tag># Spring</a><a href=/tags/SpringBoot/ rel=tag># SpringBoot</a><a href=/tags/cglib/ rel=tag># cglib</a><a href=/tags/%E4%BA%8B%E5%8A%A1/ rel=tag># 事务</a></div><div class=post-nav><div class=post-nav-item><a title="聊一下 RocketMQ 的消息存储二" href=/2021/09/12/%E8%81%8A%E4%B8%80%E4%B8%8B-RocketMQ-%E7%9A%84%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E4%BA%8C/ rel=prev><i class="fa fa-angle-left"></i> 聊一下 RocketMQ 的消息存储二</a></div><div class=post-nav-item><a title="聊一下 SpringBoot 中动态切换数据源的方法" href=/2021/09/26/%E8%81%8A%E4%B8%80%E4%B8%8B-SpringBoot-%E4%B8%AD%E5%8A%A8%E6%80%81%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E6%96%B9%E6%B3%95/ rel=next>聊一下 SpringBoot 中动态切换数据源的方法 <i class="fa fa-angle-right"></i></a></div></div></footer></article></div><div class=comments id=disqus_thread><noscript>Please enable JavaScript to view the comments powered by Disqus.</noscript></div></div></main><footer class=footer><div class=footer-inner><div class=beian><a href=https://beian.miit.gov.cn/ rel=noopener target=_blank>浙ICP备16002580号-2 </a><img alt src=/uploads/beian.png><a href=https://beian.mps.gov.cn/#/query/webSearch?code=33010602011094 rel=noopener target=_blank>浙公网安备 33010602011094号</a></div><div class=copyright>© <span itemprop=copyrightYear>2026</span><span class=with-love><i class="fa fa-heart"></i> </span><span class=author itemprop=copyrightHolder>Nicksxs</span></div></div></footer><div class="toggle sidebar-toggle" role=button><span class=toggle-line></span><span class=toggle-line></span><span class=toggle-line></span></div><div class=sidebar-dimmer></div><div aria-label=返回顶部 class=back-to-top role=button><i class="fa fa-arrow-up fa-lg"></i><span>0%</span></div><a aria-label="在 GitHub 上关注我" title="在 GitHub 上关注我" class=github-corner href=https://github.com/nicksxs rel=noopener target=_blank><svg viewbox="0 0 250 250" aria-hidden=true height=80 width=80><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" style="transform-origin:130px 106px" class=octo-arm fill=currentColor></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" class=octo-body fill=currentColor></path></svg></a><noscript><div class=noscript-warning>Theme NexT works best with JavaScript enabled</div></noscript><script data-cloudflare-page-counter-config type=application/json>{"enable":true,"endpoint":"https://counter.nicksxs.me","site":"nicksxs","local_cache":true,"timeout":5000,"icon":"far fa-eye","item_text":true}</script><script src=/js/cloudflare-page-counter.js></script><script class=next-config data-name=disqus type=application/json>{"enable":true,"shortname":"nicksxs","count":false,"i18n":{"disqus":"disqus"}}</script><script defer src=/js/third-party/comments/disqus.js></script>