[{"data":1,"prerenderedAt":4227},["ShallowReactive",2],{"\u002Fposts\u002F370adf0":3,"surround-\u002Fposts\u002F370adf0":4216},{"id":4,"title":5,"body":6,"categories":4191,"date":4193,"description":4194,"draft":4195,"extension":4196,"image":4197,"meta":4198,"navigation":134,"path":4200,"permalink":4200,"published":4201,"readingTime":4202,"recommend":157,"references":4201,"seo":4207,"sitemap":4208,"stem":4209,"tags":4210,"type":4213,"updated":4214,"__hash__":4215},"content\u002Fposts\u002F2026\u002FSpring AOP 动态代理机制：从静态代理到 JDK 与 CGLIB 的实现.md","Spring AOP 动态代理机制：从静态代理到 JDK 与 CGLIB 的实现",{"type":7,"value":8,"toc":4171},"minimark",[9,13,16,20,23,26,30,37,40,46,49,55,58,61,64,67,70,73,76,232,235,634,637,901,904,973,976,979,982,985,1473,1476,1711,1714,1956,1959,1962,1965,2040,2044,2047,2050,2644,2648,2651,2656,2687,2691,2723,2738,2746,2749,2754,2773,2815,2818,3140,3143,3151,3154,3157,3212,3221,3226,3229,3258,3268,3275,3285,3328,3332,3346,3369,3373,3376,3461,3464,3992,3999,4035,4038,4099,4102,4167],[10,11,12],"p",{},"Spring提供了对面向切面编程(AOP)的丰富支持，允许通过分离应用的业务逻辑与系统级服务（例如审计（auditing）和事务（transaction）管理）进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责（甚至是意识）其它的系统级关注点，例如日志或事务支持。",[10,14,15],{},"Spring 的 AOP 是通过动态代理来实现的。代理是一种设计模式，但是这里说到的静态代理和动态代理不是GoF23种设计模式分类中的一种，而是 Java 领域中按代理类生成时机来划分的实现方式，属于代理模式的具体技术实践，而非 GoF 定义的分类。",[17,18,19],"h2",{"id":19},"代理模式",[10,21,22],{},"A (调用方) -> C(代理) -> B(目标)",[10,24,25],{},"调用方不直接调用使用 B，而是通过代理 C 来间接使用 B，这就是代理。",[27,28,29],"h3",{"id":29},"代理模式的作用",[31,32,33],"ol",{},[34,35,36],"li",{},"解决程序中 A 对象和 B 对象无法直接交互的问题",[10,38,39],{},"举例：类似婚介所，男方和女方互不相识，通过中介（代理）相互认识",[31,41,43],{"start":42},2,[34,44,45],{},"给程序中某块代码做功能增强或解耦",[10,47,48],{},"举例：还是婚介所，男方自己找的对象自己不满意，分手后，通过婚介(代理对象)寻找，找到原对象的增强版，各方面更为满意",[31,50,52],{"start":51},3,[34,53,54],{},"给程序中某块代码提供保护",[10,56,57],{},"举例：依然是婚介所，男方本来是登报征婚，结果手机被骚扰电话打爆，出于保护的目的，选择了婚介所（代理），让婚介所把关，有合适的再联系。",[10,59,60],{},"上面的男方就是目标对象，婚介所就是代理对象，代理对象代替目标征婚，这就是代理。",[17,62,63],{"id":63},"静态代理",[27,65,66],{"id":66},"耦合日志的代码",[10,68,69],{},"假设我们要实现一个非常简单的登陆功能，用户名是 admin，密码是 123456",[10,71,72],{},"代码如下",[10,74,75],{},"1.首先定义 LoginService 接口",[77,78,84],"pre",{"className":79,"code":80,"filename":81,"language":82,"meta":83,"style":83},"language-java shiki shiki-themes catppuccin-latte one-dark-pro","package top.dhbxs.demo.springaop.staticproxy.service;\n\n\u002F**\n * @author dhbxs\n * @since 2026\u002F4\u002F19\n *\u002F\npublic interface LoginService {\n\n    boolean login(String username, String password);\n}\n","LoginService.java","java","",[85,86,87,130,136,142,155,166,172,188,193,226],"code",{"__ignoreMap":83},[88,89,92,96,99,103,106,108,111,113,116,118,121,123,126],"span",{"class":90,"line":91},"line",1,[88,93,95],{"class":94},"sSWcl","package",[88,97,98],{"class":94}," top",[88,100,102],{"class":101},"sHUla",".",[88,104,105],{"class":94},"dhbxs",[88,107,102],{"class":101},[88,109,110],{"class":94},"demo",[88,112,102],{"class":101},[88,114,115],{"class":94},"springaop",[88,117,102],{"class":101},[88,119,120],{"class":94},"staticproxy",[88,122,102],{"class":101},[88,124,125],{"class":94},"service",[88,127,129],{"class":128},"sgT6j",";\n",[88,131,132],{"class":90,"line":42},[88,133,135],{"emptyLinePlaceholder":134},true,"\n",[88,137,138],{"class":90,"line":51},[88,139,141],{"class":140},"skYY2","\u002F**\n",[88,143,145,148,152],{"class":90,"line":144},4,[88,146,147],{"class":140}," * ",[88,149,151],{"class":150},"szsGz","@author",[88,153,154],{"class":140}," dhbxs\n",[88,156,158,160,163],{"class":90,"line":157},5,[88,159,147],{"class":140},[88,161,162],{"class":150},"@since",[88,164,165],{"class":140}," 2026\u002F4\u002F19\n",[88,167,169],{"class":90,"line":168},6,[88,170,171],{"class":140}," *\u002F\n",[88,173,175,178,181,185],{"class":90,"line":174},7,[88,176,177],{"class":94},"public",[88,179,180],{"class":94}," interface",[88,182,184],{"class":183},"sIkkJ"," LoginService",[88,186,187],{"class":128}," {\n",[88,189,191],{"class":90,"line":190},8,[88,192,135],{"emptyLinePlaceholder":134},[88,194,196,199,203,206,210,214,217,220,223],{"class":90,"line":195},9,[88,197,198],{"class":94},"    boolean",[88,200,202],{"class":201},"seVD2"," login",[88,204,205],{"class":128},"(",[88,207,209],{"class":208},"sPahJ","String",[88,211,213],{"class":212},"sddMY"," username",[88,215,216],{"class":128},",",[88,218,219],{"class":208}," String",[88,221,222],{"class":212}," password",[88,224,225],{"class":128},");\n",[88,227,229],{"class":90,"line":228},10,[88,230,231],{"class":128},"}\n",[10,233,234],{},"2.实现接口",[77,236,239],{"className":79,"code":237,"filename":238,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.staticproxy.service.impl;\n\nimport lombok.extern.slf4j.Slf4j;\nimport top.dhbxs.demo.springaop.staticproxy.service.LoginService;\n\n\u002F**\n * @author dhbxs\n * @since 2026\u002F4\u002F19\n *\u002F\n@Slf4j\npublic class LoginServiceImpl implements LoginService {\n\n    @Override\n    public boolean login(String username, String password) {\n        log.info(\"开始登陆\"); \u002F\u002F 日志：非核心业务代码\n        log.info(\"{} 正在登陆系统\", username); \u002F\u002F 日志：非核心业务代码\n        boolean flag = \"admin\".equals(username) && \"123456\".equals(password); \u002F\u002F 核心业务代码\n        if (!flag) {\n            log.error(\"{} 登陆失败\", username); \u002F\u002F 日志：非核心业务代码\n        } else {\n            log.info(\"{} 登陆成功\", username); \u002F\u002F 日志：非核心业务代码\n        }\n        return flag;\n    }\n}\n","LoginServiceImpl.java",[85,240,241,274,278,305,338,342,346,354,362,366,376,394,399,408,436,459,482,531,550,574,585,607,613,623,629],{"__ignoreMap":83},[88,242,243,245,247,249,251,253,255,257,259,261,263,265,267,269,272],{"class":90,"line":91},[88,244,95],{"class":94},[88,246,98],{"class":94},[88,248,102],{"class":101},[88,250,105],{"class":94},[88,252,102],{"class":101},[88,254,110],{"class":94},[88,256,102],{"class":101},[88,258,115],{"class":94},[88,260,102],{"class":101},[88,262,120],{"class":94},[88,264,102],{"class":101},[88,266,125],{"class":94},[88,268,102],{"class":101},[88,270,271],{"class":94},"impl",[88,273,129],{"class":128},[88,275,276],{"class":90,"line":42},[88,277,135],{"emptyLinePlaceholder":134},[88,279,280,283,287,290,293,295,298,300,303],{"class":90,"line":51},[88,281,282],{"class":94},"import",[88,284,286],{"class":285},"szf8G"," lombok",[88,288,102],{"class":289},"sGc2n",[88,291,292],{"class":285},"extern",[88,294,102],{"class":289},[88,296,297],{"class":285},"slf4j",[88,299,102],{"class":289},[88,301,302],{"class":285},"Slf4j",[88,304,129],{"class":128},[88,306,307,309,311,313,315,317,319,321,323,325,327,329,331,333,336],{"class":90,"line":144},[88,308,282],{"class":94},[88,310,98],{"class":285},[88,312,102],{"class":289},[88,314,105],{"class":285},[88,316,102],{"class":289},[88,318,110],{"class":285},[88,320,102],{"class":289},[88,322,115],{"class":285},[88,324,102],{"class":289},[88,326,120],{"class":285},[88,328,102],{"class":289},[88,330,125],{"class":285},[88,332,102],{"class":289},[88,334,335],{"class":285},"LoginService",[88,337,129],{"class":128},[88,339,340],{"class":90,"line":157},[88,341,135],{"emptyLinePlaceholder":134},[88,343,344],{"class":90,"line":168},[88,345,141],{"class":140},[88,347,348,350,352],{"class":90,"line":174},[88,349,147],{"class":140},[88,351,151],{"class":150},[88,353,154],{"class":140},[88,355,356,358,360],{"class":90,"line":190},[88,357,147],{"class":140},[88,359,162],{"class":150},[88,361,165],{"class":140},[88,363,364],{"class":90,"line":195},[88,365,171],{"class":140},[88,367,368,372],{"class":90,"line":228},[88,369,371],{"class":370},"slb6Y","@",[88,373,375],{"class":374},"saiVi","Slf4j\n",[88,377,379,381,384,387,390,392],{"class":90,"line":378},11,[88,380,177],{"class":94},[88,382,383],{"class":94}," class",[88,385,386],{"class":183}," LoginServiceImpl",[88,388,389],{"class":94}," implements",[88,391,184],{"class":183},[88,393,187],{"class":128},[88,395,397],{"class":90,"line":396},12,[88,398,135],{"emptyLinePlaceholder":134},[88,400,402,405],{"class":90,"line":401},13,[88,403,404],{"class":370},"    @",[88,406,407],{"class":374},"Override\n",[88,409,411,414,417,419,421,423,425,427,429,431,434],{"class":90,"line":410},14,[88,412,413],{"class":94},"    public",[88,415,416],{"class":94}," boolean",[88,418,202],{"class":201},[88,420,205],{"class":128},[88,422,209],{"class":208},[88,424,213],{"class":212},[88,426,216],{"class":128},[88,428,219],{"class":208},[88,430,222],{"class":212},[88,432,433],{"class":128},")",[88,435,187],{"class":128},[88,437,439,442,444,447,449,453,456],{"class":90,"line":438},15,[88,440,441],{"class":285},"        log",[88,443,102],{"class":128},[88,445,446],{"class":201},"info",[88,448,205],{"class":128},[88,450,452],{"class":451},"sw_MA","\"开始登陆\"",[88,454,455],{"class":128},");",[88,457,458],{"class":140}," \u002F\u002F 日志：非核心业务代码\n",[88,460,462,464,466,468,470,473,475,478,480],{"class":90,"line":461},16,[88,463,441],{"class":285},[88,465,102],{"class":128},[88,467,446],{"class":201},[88,469,205],{"class":128},[88,471,472],{"class":451},"\"{} 正在登陆系统\"",[88,474,216],{"class":128},[88,476,213],{"class":477},"sa2x1",[88,479,455],{"class":128},[88,481,458],{"class":140},[88,483,485,488,492,496,499,501,504,506,509,511,514,517,519,521,523,526,528],{"class":90,"line":484},17,[88,486,487],{"class":94},"        boolean",[88,489,491],{"class":490},"sIGPt"," flag",[88,493,495],{"class":494},"sqgB4"," =",[88,497,498],{"class":451}," \"admin\"",[88,500,102],{"class":128},[88,502,503],{"class":201},"equals",[88,505,205],{"class":128},[88,507,508],{"class":477},"username",[88,510,433],{"class":128},[88,512,513],{"class":494}," &&",[88,515,516],{"class":451}," \"123456\"",[88,518,102],{"class":128},[88,520,503],{"class":201},[88,522,205],{"class":128},[88,524,525],{"class":477},"password",[88,527,455],{"class":128},[88,529,530],{"class":140}," \u002F\u002F 核心业务代码\n",[88,532,534,537,540,543,546,548],{"class":90,"line":533},18,[88,535,536],{"class":94},"        if",[88,538,539],{"class":128}," (",[88,541,542],{"class":494},"!",[88,544,545],{"class":477},"flag",[88,547,433],{"class":128},[88,549,187],{"class":128},[88,551,553,556,558,561,563,566,568,570,572],{"class":90,"line":552},19,[88,554,555],{"class":285},"            log",[88,557,102],{"class":128},[88,559,560],{"class":201},"error",[88,562,205],{"class":128},[88,564,565],{"class":451},"\"{} 登陆失败\"",[88,567,216],{"class":128},[88,569,213],{"class":477},[88,571,455],{"class":128},[88,573,458],{"class":140},[88,575,577,580,583],{"class":90,"line":576},20,[88,578,579],{"class":128},"        }",[88,581,582],{"class":94}," else",[88,584,187],{"class":128},[88,586,588,590,592,594,596,599,601,603,605],{"class":90,"line":587},21,[88,589,555],{"class":285},[88,591,102],{"class":128},[88,593,446],{"class":201},[88,595,205],{"class":128},[88,597,598],{"class":451},"\"{} 登陆成功\"",[88,600,216],{"class":128},[88,602,213],{"class":477},[88,604,455],{"class":128},[88,606,458],{"class":140},[88,608,610],{"class":90,"line":609},22,[88,611,612],{"class":128},"        }\n",[88,614,616,619,621],{"class":90,"line":615},23,[88,617,618],{"class":94},"        return",[88,620,491],{"class":477},[88,622,129],{"class":128},[88,624,626],{"class":90,"line":625},24,[88,627,628],{"class":128},"    }\n",[88,630,632],{"class":90,"line":631},25,[88,633,231],{"class":128},[10,635,636],{},"3.编写测试类测试功能",[77,638,641],{"className":79,"code":639,"filename":640,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.staticproxy.service;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport top.dhbxs.demo.springaop.staticproxy.service.impl.LoginServiceImpl;\n\n@SpringBootTest\nclass LoginServiceTest {\n\n    @Test\n    void login() {\n        LoginService loginService = new LoginServiceImpl();\n\n        boolean flag = loginService.login(\"admin\", \"123456\");\n        System.out.println(\"flag = \" + flag);\n    }\n}\n","LoginServiceTest.java",[85,642,643,671,675,704,737,774,778,785,795,799,806,818,836,840,866,893,897],{"__ignoreMap":83},[88,644,645,647,649,651,653,655,657,659,661,663,665,667,669],{"class":90,"line":91},[88,646,95],{"class":94},[88,648,98],{"class":94},[88,650,102],{"class":101},[88,652,105],{"class":94},[88,654,102],{"class":101},[88,656,110],{"class":94},[88,658,102],{"class":101},[88,660,115],{"class":94},[88,662,102],{"class":101},[88,664,120],{"class":94},[88,666,102],{"class":101},[88,668,125],{"class":94},[88,670,129],{"class":128},[88,672,673],{"class":90,"line":42},[88,674,135],{"emptyLinePlaceholder":134},[88,676,677,679,682,684,687,689,692,694,697,699,702],{"class":90,"line":51},[88,678,282],{"class":94},[88,680,681],{"class":285}," org",[88,683,102],{"class":289},[88,685,686],{"class":285},"junit",[88,688,102],{"class":289},[88,690,691],{"class":285},"jupiter",[88,693,102],{"class":289},[88,695,696],{"class":285},"api",[88,698,102],{"class":289},[88,700,701],{"class":285},"Test",[88,703,129],{"class":128},[88,705,706,708,710,712,715,717,720,722,725,727,730,732,735],{"class":90,"line":144},[88,707,282],{"class":94},[88,709,681],{"class":285},[88,711,102],{"class":289},[88,713,714],{"class":285},"springframework",[88,716,102],{"class":289},[88,718,719],{"class":285},"boot",[88,721,102],{"class":289},[88,723,724],{"class":285},"test",[88,726,102],{"class":289},[88,728,729],{"class":285},"context",[88,731,102],{"class":289},[88,733,734],{"class":285},"SpringBootTest",[88,736,129],{"class":128},[88,738,739,741,743,745,747,749,751,753,755,757,759,761,763,765,767,769,772],{"class":90,"line":157},[88,740,282],{"class":94},[88,742,98],{"class":285},[88,744,102],{"class":289},[88,746,105],{"class":285},[88,748,102],{"class":289},[88,750,110],{"class":285},[88,752,102],{"class":289},[88,754,115],{"class":285},[88,756,102],{"class":289},[88,758,120],{"class":285},[88,760,102],{"class":289},[88,762,125],{"class":285},[88,764,102],{"class":289},[88,766,271],{"class":285},[88,768,102],{"class":289},[88,770,771],{"class":285},"LoginServiceImpl",[88,773,129],{"class":128},[88,775,776],{"class":90,"line":168},[88,777,135],{"emptyLinePlaceholder":134},[88,779,780,782],{"class":90,"line":174},[88,781,371],{"class":370},[88,783,784],{"class":374},"SpringBootTest\n",[88,786,787,790,793],{"class":90,"line":190},[88,788,789],{"class":94},"class",[88,791,792],{"class":183}," LoginServiceTest",[88,794,187],{"class":128},[88,796,797],{"class":90,"line":195},[88,798,135],{"emptyLinePlaceholder":134},[88,800,801,803],{"class":90,"line":228},[88,802,404],{"class":370},[88,804,805],{"class":374},"Test\n",[88,807,808,811,813,816],{"class":90,"line":378},[88,809,810],{"class":94},"    void",[88,812,202],{"class":201},[88,814,815],{"class":128},"()",[88,817,187],{"class":128},[88,819,820,823,826,828,831,833],{"class":90,"line":396},[88,821,822],{"class":208},"        LoginService",[88,824,825],{"class":490}," loginService",[88,827,495],{"class":494},[88,829,830],{"class":94}," new",[88,832,386],{"class":201},[88,834,835],{"class":128},"();\n",[88,837,838],{"class":90,"line":401},[88,839,135],{"emptyLinePlaceholder":134},[88,841,842,844,846,848,850,852,855,857,860,862,864],{"class":90,"line":410},[88,843,487],{"class":94},[88,845,491],{"class":490},[88,847,495],{"class":494},[88,849,825],{"class":285},[88,851,102],{"class":128},[88,853,854],{"class":201},"login",[88,856,205],{"class":128},[88,858,859],{"class":451},"\"admin\"",[88,861,216],{"class":128},[88,863,516],{"class":451},[88,865,225],{"class":128},[88,867,868,871,873,876,878,881,883,886,889,891],{"class":90,"line":438},[88,869,870],{"class":285},"        System",[88,872,102],{"class":128},[88,874,875],{"class":285},"out",[88,877,102],{"class":128},[88,879,880],{"class":201},"println",[88,882,205],{"class":128},[88,884,885],{"class":451},"\"flag = \"",[88,887,888],{"class":494}," +",[88,890,491],{"class":477},[88,892,225],{"class":128},[88,894,895],{"class":90,"line":461},[88,896,628],{"class":128},[88,898,899],{"class":90,"line":484},[88,900,231],{"class":128},[10,902,903],{},"4.输出如下",[77,905,910],{"className":906,"code":907,"filename":908,"language":909,"meta":83,"style":83},"language-log shiki shiki-themes catppuccin-latte one-dark-pro","2026-04-19T22:17:05.145+08:00  INFO 28308 --- [SpringAOP] [           main] t.d.d.s.s.service.impl.LoginServiceImpl  : 开始登陆\n2026-04-19T22:17:05.145+08:00  INFO 28308 --- [SpringAOP] [           main] t.d.d.s.s.service.impl.LoginServiceImpl  : admin 正在登陆系统\n2026-04-19T22:17:05.146+08:00  INFO 28308 --- [SpringAOP] [           main] t.d.d.s.s.service.impl.LoginServiceImpl  : admin 登陆成功\nflag = true\n","console.log","log",[85,911,912,934,949,965],{"__ignoreMap":83},[88,913,914,917,921,925,928,931],{"class":90,"line":91},[88,915,916],{"class":140},"2026-04-19T22:17:05.145+08:00",[88,918,920],{"class":919},"sFUGW","  INFO",[88,922,924],{"class":923},"sFiMs"," 28308",[88,926,927],{"class":477}," --- [SpringAOP] [           main] ",[88,929,930],{"class":923},"t.d.d.s.s.service.impl.LoginServiceImpl",[88,932,933],{"class":477},"  : 开始登陆\n",[88,935,936,938,940,942,944,946],{"class":90,"line":42},[88,937,916],{"class":140},[88,939,920],{"class":919},[88,941,924],{"class":923},[88,943,927],{"class":477},[88,945,930],{"class":923},[88,947,948],{"class":477},"  : admin 正在登陆系统\n",[88,950,951,954,956,958,960,962],{"class":90,"line":51},[88,952,953],{"class":140},"2026-04-19T22:17:05.146+08:00",[88,955,920],{"class":919},[88,957,924],{"class":923},[88,959,927],{"class":477},[88,961,930],{"class":923},[88,963,964],{"class":477},"  : admin 登陆成功\n",[88,966,967,970],{"class":90,"line":144},[88,968,969],{"class":477},"flag = ",[88,971,972],{"class":923},"true\n",[10,974,975],{},"以上就是非常简单直接的一个登陆逻辑，可以在 LoginServiceImpl 代码中看到有很多非业务相关的日志记录的代码，和业务逻辑是深度耦合的。",[10,977,978],{},"接下来使用代理模式中的静态代理来优化解耦。",[27,980,981],{"id":981},"静态代理解耦",[10,983,984],{},"1.创建一个代理类，实现相同的 LoginService 接口",[77,986,989],{"className":79,"code":987,"filename":988,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.staticproxy.service.proxy;\n\nimport lombok.extern.slf4j.Slf4j;\nimport top.dhbxs.demo.springaop.staticproxy.service.LoginService;\nimport top.dhbxs.demo.springaop.staticproxy.service.impl.LoginServiceImpl;\n\n\u002F**\n * 静态代理：解决代码耦合\n * 代理类和目标类都实现了同一个接口\n *\n * @author dhbxs\n * @since 2026\u002F4\u002F19\n *\u002F\n@Slf4j\npublic class LoginServiceProxy implements LoginService {\n\n\n    \u002F**\n     * 代理方法，帮你调用目标\n     *\n     * @param username 用户名\n     * @param password 密码\n     * @return 登陆结果\n     *\u002F\n    @Override\n    public boolean login(String username, String password) {\n\n\n        log.info(\"开始登陆\"); \u002F\u002F 日志：非核心业务代码\n        log.info(\"{} 正在登陆系统\", username); \u002F\u002F 日志：非核心业务代码\n\n        LoginService loginService = new LoginServiceImpl(); \u002F\u002F 创建目标对象\n        boolean flag = loginService.login(username, password); \u002F\u002F 调用目标方法\n\n        if (!flag) {\n            log.error(\"{} 登陆失败\", username); \u002F\u002F 日志：非核心业务代码\n        } else {\n            log.info(\"{} 登陆成功\", username); \u002F\u002F 日志：非核心业务代码\n        }\n\n        return flag;\n    }\n}\n","LoginServiceProxy.java",[85,990,991,1024,1028,1048,1080,1116,1120,1124,1129,1134,1139,1147,1155,1159,1165,1180,1184,1188,1193,1198,1203,1216,1227,1237,1242,1248,1273,1278,1283,1300,1321,1326,1345,1373,1378,1393,1414,1423,1444,1449,1454,1463,1468],{"__ignoreMap":83},[88,992,993,995,997,999,1001,1003,1005,1007,1009,1011,1013,1015,1017,1019,1022],{"class":90,"line":91},[88,994,95],{"class":94},[88,996,98],{"class":94},[88,998,102],{"class":101},[88,1000,105],{"class":94},[88,1002,102],{"class":101},[88,1004,110],{"class":94},[88,1006,102],{"class":101},[88,1008,115],{"class":94},[88,1010,102],{"class":101},[88,1012,120],{"class":94},[88,1014,102],{"class":101},[88,1016,125],{"class":94},[88,1018,102],{"class":101},[88,1020,1021],{"class":94},"proxy",[88,1023,129],{"class":128},[88,1025,1026],{"class":90,"line":42},[88,1027,135],{"emptyLinePlaceholder":134},[88,1029,1030,1032,1034,1036,1038,1040,1042,1044,1046],{"class":90,"line":51},[88,1031,282],{"class":94},[88,1033,286],{"class":285},[88,1035,102],{"class":289},[88,1037,292],{"class":285},[88,1039,102],{"class":289},[88,1041,297],{"class":285},[88,1043,102],{"class":289},[88,1045,302],{"class":285},[88,1047,129],{"class":128},[88,1049,1050,1052,1054,1056,1058,1060,1062,1064,1066,1068,1070,1072,1074,1076,1078],{"class":90,"line":144},[88,1051,282],{"class":94},[88,1053,98],{"class":285},[88,1055,102],{"class":289},[88,1057,105],{"class":285},[88,1059,102],{"class":289},[88,1061,110],{"class":285},[88,1063,102],{"class":289},[88,1065,115],{"class":285},[88,1067,102],{"class":289},[88,1069,120],{"class":285},[88,1071,102],{"class":289},[88,1073,125],{"class":285},[88,1075,102],{"class":289},[88,1077,335],{"class":285},[88,1079,129],{"class":128},[88,1081,1082,1084,1086,1088,1090,1092,1094,1096,1098,1100,1102,1104,1106,1108,1110,1112,1114],{"class":90,"line":157},[88,1083,282],{"class":94},[88,1085,98],{"class":285},[88,1087,102],{"class":289},[88,1089,105],{"class":285},[88,1091,102],{"class":289},[88,1093,110],{"class":285},[88,1095,102],{"class":289},[88,1097,115],{"class":285},[88,1099,102],{"class":289},[88,1101,120],{"class":285},[88,1103,102],{"class":289},[88,1105,125],{"class":285},[88,1107,102],{"class":289},[88,1109,271],{"class":285},[88,1111,102],{"class":289},[88,1113,771],{"class":285},[88,1115,129],{"class":128},[88,1117,1118],{"class":90,"line":168},[88,1119,135],{"emptyLinePlaceholder":134},[88,1121,1122],{"class":90,"line":174},[88,1123,141],{"class":140},[88,1125,1126],{"class":90,"line":190},[88,1127,1128],{"class":140}," * 静态代理：解决代码耦合\n",[88,1130,1131],{"class":90,"line":195},[88,1132,1133],{"class":140}," * 代理类和目标类都实现了同一个接口\n",[88,1135,1136],{"class":90,"line":228},[88,1137,1138],{"class":140}," *\n",[88,1140,1141,1143,1145],{"class":90,"line":378},[88,1142,147],{"class":140},[88,1144,151],{"class":150},[88,1146,154],{"class":140},[88,1148,1149,1151,1153],{"class":90,"line":396},[88,1150,147],{"class":140},[88,1152,162],{"class":150},[88,1154,165],{"class":140},[88,1156,1157],{"class":90,"line":401},[88,1158,171],{"class":140},[88,1160,1161,1163],{"class":90,"line":410},[88,1162,371],{"class":370},[88,1164,375],{"class":374},[88,1166,1167,1169,1171,1174,1176,1178],{"class":90,"line":438},[88,1168,177],{"class":94},[88,1170,383],{"class":94},[88,1172,1173],{"class":183}," LoginServiceProxy",[88,1175,389],{"class":94},[88,1177,184],{"class":183},[88,1179,187],{"class":128},[88,1181,1182],{"class":90,"line":461},[88,1183,135],{"emptyLinePlaceholder":134},[88,1185,1186],{"class":90,"line":484},[88,1187,135],{"emptyLinePlaceholder":134},[88,1189,1190],{"class":90,"line":533},[88,1191,1192],{"class":140},"    \u002F**\n",[88,1194,1195],{"class":90,"line":552},[88,1196,1197],{"class":140},"     * 代理方法，帮你调用目标\n",[88,1199,1200],{"class":90,"line":576},[88,1201,1202],{"class":140},"     *\n",[88,1204,1205,1208,1211,1213],{"class":90,"line":587},[88,1206,1207],{"class":140},"     * ",[88,1209,1210],{"class":150},"@param",[88,1212,213],{"class":212},[88,1214,1215],{"class":140}," 用户名\n",[88,1217,1218,1220,1222,1224],{"class":90,"line":609},[88,1219,1207],{"class":140},[88,1221,1210],{"class":150},[88,1223,222],{"class":212},[88,1225,1226],{"class":140}," 密码\n",[88,1228,1229,1231,1234],{"class":90,"line":615},[88,1230,1207],{"class":140},[88,1232,1233],{"class":150},"@return",[88,1235,1236],{"class":140}," 登陆结果\n",[88,1238,1239],{"class":90,"line":625},[88,1240,1241],{"class":140},"     *\u002F\n",[88,1243,1244,1246],{"class":90,"line":631},[88,1245,404],{"class":370},[88,1247,407],{"class":374},[88,1249,1251,1253,1255,1257,1259,1261,1263,1265,1267,1269,1271],{"class":90,"line":1250},26,[88,1252,413],{"class":94},[88,1254,416],{"class":94},[88,1256,202],{"class":201},[88,1258,205],{"class":128},[88,1260,209],{"class":208},[88,1262,213],{"class":212},[88,1264,216],{"class":128},[88,1266,219],{"class":208},[88,1268,222],{"class":212},[88,1270,433],{"class":128},[88,1272,187],{"class":128},[88,1274,1276],{"class":90,"line":1275},27,[88,1277,135],{"emptyLinePlaceholder":134},[88,1279,1281],{"class":90,"line":1280},28,[88,1282,135],{"emptyLinePlaceholder":134},[88,1284,1286,1288,1290,1292,1294,1296,1298],{"class":90,"line":1285},29,[88,1287,441],{"class":285},[88,1289,102],{"class":128},[88,1291,446],{"class":201},[88,1293,205],{"class":128},[88,1295,452],{"class":451},[88,1297,455],{"class":128},[88,1299,458],{"class":140},[88,1301,1303,1305,1307,1309,1311,1313,1315,1317,1319],{"class":90,"line":1302},30,[88,1304,441],{"class":285},[88,1306,102],{"class":128},[88,1308,446],{"class":201},[88,1310,205],{"class":128},[88,1312,472],{"class":451},[88,1314,216],{"class":128},[88,1316,213],{"class":477},[88,1318,455],{"class":128},[88,1320,458],{"class":140},[88,1322,1324],{"class":90,"line":1323},31,[88,1325,135],{"emptyLinePlaceholder":134},[88,1327,1329,1331,1333,1335,1337,1339,1342],{"class":90,"line":1328},32,[88,1330,822],{"class":208},[88,1332,825],{"class":490},[88,1334,495],{"class":494},[88,1336,830],{"class":94},[88,1338,386],{"class":201},[88,1340,1341],{"class":128},"();",[88,1343,1344],{"class":140}," \u002F\u002F 创建目标对象\n",[88,1346,1348,1350,1352,1354,1356,1358,1360,1362,1364,1366,1368,1370],{"class":90,"line":1347},33,[88,1349,487],{"class":94},[88,1351,491],{"class":490},[88,1353,495],{"class":494},[88,1355,825],{"class":285},[88,1357,102],{"class":128},[88,1359,854],{"class":201},[88,1361,205],{"class":128},[88,1363,508],{"class":477},[88,1365,216],{"class":128},[88,1367,222],{"class":477},[88,1369,455],{"class":128},[88,1371,1372],{"class":140}," \u002F\u002F 调用目标方法\n",[88,1374,1376],{"class":90,"line":1375},34,[88,1377,135],{"emptyLinePlaceholder":134},[88,1379,1381,1383,1385,1387,1389,1391],{"class":90,"line":1380},35,[88,1382,536],{"class":94},[88,1384,539],{"class":128},[88,1386,542],{"class":494},[88,1388,545],{"class":477},[88,1390,433],{"class":128},[88,1392,187],{"class":128},[88,1394,1396,1398,1400,1402,1404,1406,1408,1410,1412],{"class":90,"line":1395},36,[88,1397,555],{"class":285},[88,1399,102],{"class":128},[88,1401,560],{"class":201},[88,1403,205],{"class":128},[88,1405,565],{"class":451},[88,1407,216],{"class":128},[88,1409,213],{"class":477},[88,1411,455],{"class":128},[88,1413,458],{"class":140},[88,1415,1417,1419,1421],{"class":90,"line":1416},37,[88,1418,579],{"class":128},[88,1420,582],{"class":94},[88,1422,187],{"class":128},[88,1424,1426,1428,1430,1432,1434,1436,1438,1440,1442],{"class":90,"line":1425},38,[88,1427,555],{"class":285},[88,1429,102],{"class":128},[88,1431,446],{"class":201},[88,1433,205],{"class":128},[88,1435,598],{"class":451},[88,1437,216],{"class":128},[88,1439,213],{"class":477},[88,1441,455],{"class":128},[88,1443,458],{"class":140},[88,1445,1447],{"class":90,"line":1446},39,[88,1448,612],{"class":128},[88,1450,1452],{"class":90,"line":1451},40,[88,1453,135],{"emptyLinePlaceholder":134},[88,1455,1457,1459,1461],{"class":90,"line":1456},41,[88,1458,618],{"class":94},[88,1460,491],{"class":477},[88,1462,129],{"class":128},[88,1464,1466],{"class":90,"line":1465},42,[88,1467,628],{"class":128},[88,1469,1471],{"class":90,"line":1470},43,[88,1472,231],{"class":128},[10,1474,1475],{},"2.修改原来的 LoginServiceImpl 接口",[77,1477,1479],{"className":79,"code":1478,"filename":238,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.staticproxy.service.impl;\n\nimport lombok.extern.slf4j.Slf4j;\nimport top.dhbxs.demo.springaop.staticproxy.service.LoginService;\n\n\u002F**\n * @author dhbxs\n * @since 2026\u002F4\u002F19\n *\u002F\n@Slf4j\npublic class LoginServiceImpl implements LoginService {\n\n    @Override\n    public boolean login(String username, String password) {\n\n        boolean flag = \"admin\".equals(username) && \"123456\".equals(password); \u002F\u002F 核心业务代码\n\n        return flag;\n    }\n}\n",[85,1480,1481,1513,1517,1537,1569,1573,1577,1585,1593,1597,1603,1617,1621,1627,1651,1655,1691,1695,1703,1707],{"__ignoreMap":83},[88,1482,1483,1485,1487,1489,1491,1493,1495,1497,1499,1501,1503,1505,1507,1509,1511],{"class":90,"line":91},[88,1484,95],{"class":94},[88,1486,98],{"class":94},[88,1488,102],{"class":101},[88,1490,105],{"class":94},[88,1492,102],{"class":101},[88,1494,110],{"class":94},[88,1496,102],{"class":101},[88,1498,115],{"class":94},[88,1500,102],{"class":101},[88,1502,120],{"class":94},[88,1504,102],{"class":101},[88,1506,125],{"class":94},[88,1508,102],{"class":101},[88,1510,271],{"class":94},[88,1512,129],{"class":128},[88,1514,1515],{"class":90,"line":42},[88,1516,135],{"emptyLinePlaceholder":134},[88,1518,1519,1521,1523,1525,1527,1529,1531,1533,1535],{"class":90,"line":51},[88,1520,282],{"class":94},[88,1522,286],{"class":285},[88,1524,102],{"class":289},[88,1526,292],{"class":285},[88,1528,102],{"class":289},[88,1530,297],{"class":285},[88,1532,102],{"class":289},[88,1534,302],{"class":285},[88,1536,129],{"class":128},[88,1538,1539,1541,1543,1545,1547,1549,1551,1553,1555,1557,1559,1561,1563,1565,1567],{"class":90,"line":144},[88,1540,282],{"class":94},[88,1542,98],{"class":285},[88,1544,102],{"class":289},[88,1546,105],{"class":285},[88,1548,102],{"class":289},[88,1550,110],{"class":285},[88,1552,102],{"class":289},[88,1554,115],{"class":285},[88,1556,102],{"class":289},[88,1558,120],{"class":285},[88,1560,102],{"class":289},[88,1562,125],{"class":285},[88,1564,102],{"class":289},[88,1566,335],{"class":285},[88,1568,129],{"class":128},[88,1570,1571],{"class":90,"line":157},[88,1572,135],{"emptyLinePlaceholder":134},[88,1574,1575],{"class":90,"line":168},[88,1576,141],{"class":140},[88,1578,1579,1581,1583],{"class":90,"line":174},[88,1580,147],{"class":140},[88,1582,151],{"class":150},[88,1584,154],{"class":140},[88,1586,1587,1589,1591],{"class":90,"line":190},[88,1588,147],{"class":140},[88,1590,162],{"class":150},[88,1592,165],{"class":140},[88,1594,1595],{"class":90,"line":195},[88,1596,171],{"class":140},[88,1598,1599,1601],{"class":90,"line":228},[88,1600,371],{"class":370},[88,1602,375],{"class":374},[88,1604,1605,1607,1609,1611,1613,1615],{"class":90,"line":378},[88,1606,177],{"class":94},[88,1608,383],{"class":94},[88,1610,386],{"class":183},[88,1612,389],{"class":94},[88,1614,184],{"class":183},[88,1616,187],{"class":128},[88,1618,1619],{"class":90,"line":396},[88,1620,135],{"emptyLinePlaceholder":134},[88,1622,1623,1625],{"class":90,"line":401},[88,1624,404],{"class":370},[88,1626,407],{"class":374},[88,1628,1629,1631,1633,1635,1637,1639,1641,1643,1645,1647,1649],{"class":90,"line":410},[88,1630,413],{"class":94},[88,1632,416],{"class":94},[88,1634,202],{"class":201},[88,1636,205],{"class":128},[88,1638,209],{"class":208},[88,1640,213],{"class":212},[88,1642,216],{"class":128},[88,1644,219],{"class":208},[88,1646,222],{"class":212},[88,1648,433],{"class":128},[88,1650,187],{"class":128},[88,1652,1653],{"class":90,"line":438},[88,1654,135],{"emptyLinePlaceholder":134},[88,1656,1657,1659,1661,1663,1665,1667,1669,1671,1673,1675,1677,1679,1681,1683,1685,1687,1689],{"class":90,"line":461},[88,1658,487],{"class":94},[88,1660,491],{"class":490},[88,1662,495],{"class":494},[88,1664,498],{"class":451},[88,1666,102],{"class":128},[88,1668,503],{"class":201},[88,1670,205],{"class":128},[88,1672,508],{"class":477},[88,1674,433],{"class":128},[88,1676,513],{"class":494},[88,1678,516],{"class":451},[88,1680,102],{"class":128},[88,1682,503],{"class":201},[88,1684,205],{"class":128},[88,1686,525],{"class":477},[88,1688,455],{"class":128},[88,1690,530],{"class":140},[88,1692,1693],{"class":90,"line":484},[88,1694,135],{"emptyLinePlaceholder":134},[88,1696,1697,1699,1701],{"class":90,"line":533},[88,1698,618],{"class":94},[88,1700,491],{"class":477},[88,1702,129],{"class":128},[88,1704,1705],{"class":90,"line":552},[88,1706,628],{"class":128},[88,1708,1709],{"class":90,"line":576},[88,1710,231],{"class":128},[10,1712,1713],{},"3.修改测试类，调用代理类实现业务",[77,1715,1717],{"className":79,"code":1716,"filename":640,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.staticproxy.service;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport top.dhbxs.demo.springaop.staticproxy.service.proxy.LoginServiceProxy;\n\n@SpringBootTest\nclass LoginServiceTest {\n\n    @Test\n    void login() {\n        LoginService loginService = new LoginServiceProxy(); \u002F\u002F 创建代理对象\n\n        boolean flag = loginService.login(\"admin\", \"123456\"); \u002F\u002F 调用代理对象方法\n        System.out.println(\"flag = \" + flag);\n    }\n}\n",[85,1718,1719,1747,1751,1775,1803,1840,1844,1850,1858,1862,1868,1878,1895,1899,1926,1948,1952],{"__ignoreMap":83},[88,1720,1721,1723,1725,1727,1729,1731,1733,1735,1737,1739,1741,1743,1745],{"class":90,"line":91},[88,1722,95],{"class":94},[88,1724,98],{"class":94},[88,1726,102],{"class":101},[88,1728,105],{"class":94},[88,1730,102],{"class":101},[88,1732,110],{"class":94},[88,1734,102],{"class":101},[88,1736,115],{"class":94},[88,1738,102],{"class":101},[88,1740,120],{"class":94},[88,1742,102],{"class":101},[88,1744,125],{"class":94},[88,1746,129],{"class":128},[88,1748,1749],{"class":90,"line":42},[88,1750,135],{"emptyLinePlaceholder":134},[88,1752,1753,1755,1757,1759,1761,1763,1765,1767,1769,1771,1773],{"class":90,"line":51},[88,1754,282],{"class":94},[88,1756,681],{"class":285},[88,1758,102],{"class":289},[88,1760,686],{"class":285},[88,1762,102],{"class":289},[88,1764,691],{"class":285},[88,1766,102],{"class":289},[88,1768,696],{"class":285},[88,1770,102],{"class":289},[88,1772,701],{"class":285},[88,1774,129],{"class":128},[88,1776,1777,1779,1781,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801],{"class":90,"line":144},[88,1778,282],{"class":94},[88,1780,681],{"class":285},[88,1782,102],{"class":289},[88,1784,714],{"class":285},[88,1786,102],{"class":289},[88,1788,719],{"class":285},[88,1790,102],{"class":289},[88,1792,724],{"class":285},[88,1794,102],{"class":289},[88,1796,729],{"class":285},[88,1798,102],{"class":289},[88,1800,734],{"class":285},[88,1802,129],{"class":128},[88,1804,1805,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825,1827,1829,1831,1833,1835,1838],{"class":90,"line":157},[88,1806,282],{"class":94},[88,1808,98],{"class":285},[88,1810,102],{"class":289},[88,1812,105],{"class":285},[88,1814,102],{"class":289},[88,1816,110],{"class":285},[88,1818,102],{"class":289},[88,1820,115],{"class":285},[88,1822,102],{"class":289},[88,1824,120],{"class":285},[88,1826,102],{"class":289},[88,1828,125],{"class":285},[88,1830,102],{"class":289},[88,1832,1021],{"class":285},[88,1834,102],{"class":289},[88,1836,1837],{"class":285},"LoginServiceProxy",[88,1839,129],{"class":128},[88,1841,1842],{"class":90,"line":168},[88,1843,135],{"emptyLinePlaceholder":134},[88,1845,1846,1848],{"class":90,"line":174},[88,1847,371],{"class":370},[88,1849,784],{"class":374},[88,1851,1852,1854,1856],{"class":90,"line":190},[88,1853,789],{"class":94},[88,1855,792],{"class":183},[88,1857,187],{"class":128},[88,1859,1860],{"class":90,"line":195},[88,1861,135],{"emptyLinePlaceholder":134},[88,1863,1864,1866],{"class":90,"line":228},[88,1865,404],{"class":370},[88,1867,805],{"class":374},[88,1869,1870,1872,1874,1876],{"class":90,"line":378},[88,1871,810],{"class":94},[88,1873,202],{"class":201},[88,1875,815],{"class":128},[88,1877,187],{"class":128},[88,1879,1880,1882,1884,1886,1888,1890,1892],{"class":90,"line":396},[88,1881,822],{"class":208},[88,1883,825],{"class":490},[88,1885,495],{"class":494},[88,1887,830],{"class":94},[88,1889,1173],{"class":201},[88,1891,1341],{"class":128},[88,1893,1894],{"class":140}," \u002F\u002F 创建代理对象\n",[88,1896,1897],{"class":90,"line":401},[88,1898,135],{"emptyLinePlaceholder":134},[88,1900,1901,1903,1905,1907,1909,1911,1913,1915,1917,1919,1921,1923],{"class":90,"line":410},[88,1902,487],{"class":94},[88,1904,491],{"class":490},[88,1906,495],{"class":494},[88,1908,825],{"class":285},[88,1910,102],{"class":128},[88,1912,854],{"class":201},[88,1914,205],{"class":128},[88,1916,859],{"class":451},[88,1918,216],{"class":128},[88,1920,516],{"class":451},[88,1922,455],{"class":128},[88,1924,1925],{"class":140}," \u002F\u002F 调用代理对象方法\n",[88,1927,1928,1930,1932,1934,1936,1938,1940,1942,1944,1946],{"class":90,"line":438},[88,1929,870],{"class":285},[88,1931,102],{"class":128},[88,1933,875],{"class":285},[88,1935,102],{"class":128},[88,1937,880],{"class":201},[88,1939,205],{"class":128},[88,1941,885],{"class":451},[88,1943,888],{"class":494},[88,1945,491],{"class":477},[88,1947,225],{"class":128},[88,1949,1950],{"class":90,"line":461},[88,1951,628],{"class":128},[88,1953,1954],{"class":90,"line":484},[88,1955,231],{"class":128},[10,1957,1958],{},"修改后，我们通过 LoginServiceProxy 实现相同的 LoginService 接口，然后调用方直接调用我们的 Proxy 代理对象，由代理对象通义打印日志，并由代理对象调用最终目标方法，实现日志功能和业务逻辑解耦合。",[10,1960,1961],{},"但是这种静态代理需要我们一个个手动创建代理类，调用代理对象，还是太麻烦。所以就有了动态代理。",[17,1963,1964],{"id":1964},"动态代理",[1966,1967,1968,2016],"ul",{},[34,1969,1970,1971],{},"JDK 动态代理\n",[1966,1972,1973,1976,2013],{},[34,1974,1975],{},"基于接口实现，代理类和目标类都实现同一个接口。代理类是基于反射机制生成。类名一般是 $Proxy 前缀开头 + 数字",[34,1977,1978,1979,1997,1998,2006,2007,2012],{},"核心 API：",[85,1980,1982,1984,1987,1989,1992,1994],{"className":79,"code":1981,"language":82,"style":83},"package java.lang.reflect",[88,1983,95],{"class":94},[88,1985,1986],{"class":94}," java",[88,1988,102],{"class":101},[88,1990,1991],{"class":94},"lang",[88,1993,102],{"class":101},[88,1995,1996],{"class":94},"reflect"," 下的 ",[85,1999,2001,2003],{"className":79,"code":2000,"language":82,"style":83},"class Proxy",[88,2002,789],{"class":94},[88,2004,2005],{"class":183}," Proxy","（生成代理对象）、",[85,2008,2010],{"className":79,"code":2009,"language":82,"style":83},"InvocationHandler",[88,2011,2009],{"class":208},"（定义增强逻辑）",[34,2014,2015],{},"调用逻辑：A -> C(代理对象 -> h( InvocationHandler.invoke() )) -> B(目标)",[34,2017,2018,2019],{},"CGLIB 动态代理\n",[1966,2020,2021,2024,2027],{},[34,2022,2023],{},"基于继承实现，代理类是目标类的子类。代理类是通过第三方插件，字节码生成工具动态生成的内部类。",[34,2025,2026],{},"无需接口：直接继承目标类生成代理，目标类可以无任何接口",[34,2028,1978,2029,2006,2034,2039],{},[85,2030,2032],{"className":79,"code":2031,"language":82,"style":83},"Enhancer",[88,2033,2031],{"class":208},[85,2035,2037],{"className":79,"code":2036,"language":82,"style":83},"MethodInterceptor",[88,2038,2036],{"class":208},"（ 定义增强逻辑）",[27,2041,2043],{"id":2042},"jdk-动态代理","JDK 动态代理",[10,2045,2046],{},"新建一个 jdkproxy.service 包，把之前的 LoginService 接口和 LoginServiceImpl 实现类复制到新包下",[10,2048,2049],{},"然后新建测试类，源码如下",[77,2051,2053],{"className":79,"code":2052,"filename":640,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.jdkproxy.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport top.dhbxs.demo.springaop.jdkproxy.service.impl.LoginServiceImpl;\n\nimport java.lang.reflect.Proxy;\n\n@Slf4j\n@SpringBootTest\nclass LoginServiceTest {\n\n    @Test\n    void login() {\n        \u002F\u002F 创建目标对象\n        LoginService loginService = new LoginServiceImpl();\n\n        \u002F\u002F 创建代理对象\n        \u002F\u002F 代理对象和目标对象都实现了同一个接口，所以这个方法默认返回的 Object 对象可以强制向下转型为LoginService\n        LoginService loginServiceProxy = (LoginService) Proxy.newProxyInstance(\n                loginService.getClass().getClassLoader(), \u002F\u002F 类加载器，需要提供一个类加载器，让动态生成的字节码能加载到内存中\n                loginService.getClass().getInterfaces(), \u002F\u002F 代理类要实现哪个接口，或者哪些接口\n                (proxy, method, args) -> { \u002F\u002F InvocationHandler 对象 隐式函数式接口\n                    log.info(\"开始登陆\"); \u002F\u002F 日志：非核心业务代码\n                    log.info(\"{} 正在登陆系统\", args[0]); \u002F\u002F 日志：非核心业务代码\n\n                    boolean flag = (boolean) method.invoke(loginService, args); \u002F\u002F 调用目标方法\n\n                    if (!flag) {\n                        log.error(\"{} 登陆失败\", args[0]); \u002F\u002F 日志：非核心业务代码\n                    } else {\n                        log.info(\"{} 登陆成功\", args[0]); \u002F\u002F 日志：非核心业务代码\n                    }\n\n                    return flag;\n                });\n\n\n        \u002F\u002F 调用代理对象\n        boolean flag = loginServiceProxy.login(\"admin\", \"123456\");\n        System.out.println(\"flag = \" + flag);\n    }\n}\n",[85,2054,2055,2084,2088,2108,2132,2160,2196,2200,2221,2225,2231,2237,2245,2249,2255,2265,2270,2284,2288,2293,2298,2323,2345,2363,2391,2408,2436,2440,2476,2480,2495,2520,2529,2553,2558,2562,2571,2576,2580,2584,2589,2613,2635,2639],{"__ignoreMap":83},[88,2056,2057,2059,2061,2063,2065,2067,2069,2071,2073,2075,2078,2080,2082],{"class":90,"line":91},[88,2058,95],{"class":94},[88,2060,98],{"class":94},[88,2062,102],{"class":101},[88,2064,105],{"class":94},[88,2066,102],{"class":101},[88,2068,110],{"class":94},[88,2070,102],{"class":101},[88,2072,115],{"class":94},[88,2074,102],{"class":101},[88,2076,2077],{"class":94},"jdkproxy",[88,2079,102],{"class":101},[88,2081,125],{"class":94},[88,2083,129],{"class":128},[88,2085,2086],{"class":90,"line":42},[88,2087,135],{"emptyLinePlaceholder":134},[88,2089,2090,2092,2094,2096,2098,2100,2102,2104,2106],{"class":90,"line":51},[88,2091,282],{"class":94},[88,2093,286],{"class":285},[88,2095,102],{"class":289},[88,2097,292],{"class":285},[88,2099,102],{"class":289},[88,2101,297],{"class":285},[88,2103,102],{"class":289},[88,2105,302],{"class":285},[88,2107,129],{"class":128},[88,2109,2110,2112,2114,2116,2118,2120,2122,2124,2126,2128,2130],{"class":90,"line":144},[88,2111,282],{"class":94},[88,2113,681],{"class":285},[88,2115,102],{"class":289},[88,2117,686],{"class":285},[88,2119,102],{"class":289},[88,2121,691],{"class":285},[88,2123,102],{"class":289},[88,2125,696],{"class":285},[88,2127,102],{"class":289},[88,2129,701],{"class":285},[88,2131,129],{"class":128},[88,2133,2134,2136,2138,2140,2142,2144,2146,2148,2150,2152,2154,2156,2158],{"class":90,"line":157},[88,2135,282],{"class":94},[88,2137,681],{"class":285},[88,2139,102],{"class":289},[88,2141,714],{"class":285},[88,2143,102],{"class":289},[88,2145,719],{"class":285},[88,2147,102],{"class":289},[88,2149,724],{"class":285},[88,2151,102],{"class":289},[88,2153,729],{"class":285},[88,2155,102],{"class":289},[88,2157,734],{"class":285},[88,2159,129],{"class":128},[88,2161,2162,2164,2166,2168,2170,2172,2174,2176,2178,2180,2182,2184,2186,2188,2190,2192,2194],{"class":90,"line":168},[88,2163,282],{"class":94},[88,2165,98],{"class":285},[88,2167,102],{"class":289},[88,2169,105],{"class":285},[88,2171,102],{"class":289},[88,2173,110],{"class":285},[88,2175,102],{"class":289},[88,2177,115],{"class":285},[88,2179,102],{"class":289},[88,2181,2077],{"class":285},[88,2183,102],{"class":289},[88,2185,125],{"class":285},[88,2187,102],{"class":289},[88,2189,271],{"class":285},[88,2191,102],{"class":289},[88,2193,771],{"class":285},[88,2195,129],{"class":128},[88,2197,2198],{"class":90,"line":174},[88,2199,135],{"emptyLinePlaceholder":134},[88,2201,2202,2204,2206,2208,2210,2212,2214,2216,2219],{"class":90,"line":190},[88,2203,282],{"class":94},[88,2205,1986],{"class":285},[88,2207,102],{"class":289},[88,2209,1991],{"class":285},[88,2211,102],{"class":289},[88,2213,1996],{"class":285},[88,2215,102],{"class":289},[88,2217,2218],{"class":285},"Proxy",[88,2220,129],{"class":128},[88,2222,2223],{"class":90,"line":195},[88,2224,135],{"emptyLinePlaceholder":134},[88,2226,2227,2229],{"class":90,"line":228},[88,2228,371],{"class":370},[88,2230,375],{"class":374},[88,2232,2233,2235],{"class":90,"line":378},[88,2234,371],{"class":370},[88,2236,784],{"class":374},[88,2238,2239,2241,2243],{"class":90,"line":396},[88,2240,789],{"class":94},[88,2242,792],{"class":183},[88,2244,187],{"class":128},[88,2246,2247],{"class":90,"line":401},[88,2248,135],{"emptyLinePlaceholder":134},[88,2250,2251,2253],{"class":90,"line":410},[88,2252,404],{"class":370},[88,2254,805],{"class":374},[88,2256,2257,2259,2261,2263],{"class":90,"line":438},[88,2258,810],{"class":94},[88,2260,202],{"class":201},[88,2262,815],{"class":128},[88,2264,187],{"class":128},[88,2266,2267],{"class":90,"line":461},[88,2268,2269],{"class":140},"        \u002F\u002F 创建目标对象\n",[88,2271,2272,2274,2276,2278,2280,2282],{"class":90,"line":484},[88,2273,822],{"class":208},[88,2275,825],{"class":490},[88,2277,495],{"class":494},[88,2279,830],{"class":94},[88,2281,386],{"class":201},[88,2283,835],{"class":128},[88,2285,2286],{"class":90,"line":533},[88,2287,135],{"emptyLinePlaceholder":134},[88,2289,2290],{"class":90,"line":552},[88,2291,2292],{"class":140},"        \u002F\u002F 创建代理对象\n",[88,2294,2295],{"class":90,"line":576},[88,2296,2297],{"class":140},"        \u002F\u002F 代理对象和目标对象都实现了同一个接口，所以这个方法默认返回的 Object 对象可以强制向下转型为LoginService\n",[88,2299,2300,2302,2305,2307,2309,2311,2313,2315,2317,2320],{"class":90,"line":587},[88,2301,822],{"class":208},[88,2303,2304],{"class":490}," loginServiceProxy",[88,2306,495],{"class":494},[88,2308,539],{"class":128},[88,2310,335],{"class":477},[88,2312,433],{"class":128},[88,2314,2005],{"class":285},[88,2316,102],{"class":128},[88,2318,2319],{"class":201},"newProxyInstance",[88,2321,2322],{"class":128},"(\n",[88,2324,2325,2328,2330,2333,2336,2339,2342],{"class":90,"line":609},[88,2326,2327],{"class":285},"                loginService",[88,2329,102],{"class":128},[88,2331,2332],{"class":201},"getClass",[88,2334,2335],{"class":128},"().",[88,2337,2338],{"class":201},"getClassLoader",[88,2340,2341],{"class":128},"(),",[88,2343,2344],{"class":140}," \u002F\u002F 类加载器，需要提供一个类加载器，让动态生成的字节码能加载到内存中\n",[88,2346,2347,2349,2351,2353,2355,2358,2360],{"class":90,"line":615},[88,2348,2327],{"class":285},[88,2350,102],{"class":128},[88,2352,2332],{"class":201},[88,2354,2335],{"class":128},[88,2356,2357],{"class":201},"getInterfaces",[88,2359,2341],{"class":128},[88,2361,2362],{"class":140}," \u002F\u002F 代理类要实现哪个接口，或者哪些接口\n",[88,2364,2365,2368,2370,2372,2375,2377,2380,2382,2385,2388],{"class":90,"line":625},[88,2366,2367],{"class":128},"                (",[88,2369,1021],{"class":477},[88,2371,216],{"class":128},[88,2373,2374],{"class":477}," method",[88,2376,216],{"class":128},[88,2378,2379],{"class":477}," args",[88,2381,433],{"class":128},[88,2383,2384],{"class":94}," ->",[88,2386,2387],{"class":128}," {",[88,2389,2390],{"class":140}," \u002F\u002F InvocationHandler 对象 隐式函数式接口\n",[88,2392,2393,2396,2398,2400,2402,2404,2406],{"class":90,"line":631},[88,2394,2395],{"class":285},"                    log",[88,2397,102],{"class":128},[88,2399,446],{"class":201},[88,2401,205],{"class":128},[88,2403,452],{"class":451},[88,2405,455],{"class":128},[88,2407,458],{"class":140},[88,2409,2410,2412,2414,2416,2418,2420,2422,2424,2427,2431,2434],{"class":90,"line":1250},[88,2411,2395],{"class":285},[88,2413,102],{"class":128},[88,2415,446],{"class":201},[88,2417,205],{"class":128},[88,2419,472],{"class":451},[88,2421,216],{"class":128},[88,2423,2379],{"class":477},[88,2425,2426],{"class":128},"[",[88,2428,2430],{"class":2429},"sYQis","0",[88,2432,2433],{"class":128},"]);",[88,2435,458],{"class":140},[88,2437,2438],{"class":90,"line":1275},[88,2439,135],{"emptyLinePlaceholder":134},[88,2441,2442,2445,2447,2449,2451,2454,2456,2458,2460,2463,2465,2468,2470,2472,2474],{"class":90,"line":1280},[88,2443,2444],{"class":94},"                    boolean",[88,2446,491],{"class":490},[88,2448,495],{"class":494},[88,2450,539],{"class":128},[88,2452,2453],{"class":94},"boolean",[88,2455,433],{"class":128},[88,2457,2374],{"class":285},[88,2459,102],{"class":128},[88,2461,2462],{"class":201},"invoke",[88,2464,205],{"class":128},[88,2466,2467],{"class":477},"loginService",[88,2469,216],{"class":128},[88,2471,2379],{"class":477},[88,2473,455],{"class":128},[88,2475,1372],{"class":140},[88,2477,2478],{"class":90,"line":1285},[88,2479,135],{"emptyLinePlaceholder":134},[88,2481,2482,2485,2487,2489,2491,2493],{"class":90,"line":1302},[88,2483,2484],{"class":94},"                    if",[88,2486,539],{"class":128},[88,2488,542],{"class":494},[88,2490,545],{"class":477},[88,2492,433],{"class":128},[88,2494,187],{"class":128},[88,2496,2497,2500,2502,2504,2506,2508,2510,2512,2514,2516,2518],{"class":90,"line":1323},[88,2498,2499],{"class":285},"                        log",[88,2501,102],{"class":128},[88,2503,560],{"class":201},[88,2505,205],{"class":128},[88,2507,565],{"class":451},[88,2509,216],{"class":128},[88,2511,2379],{"class":477},[88,2513,2426],{"class":128},[88,2515,2430],{"class":2429},[88,2517,2433],{"class":128},[88,2519,458],{"class":140},[88,2521,2522,2525,2527],{"class":90,"line":1328},[88,2523,2524],{"class":128},"                    }",[88,2526,582],{"class":94},[88,2528,187],{"class":128},[88,2530,2531,2533,2535,2537,2539,2541,2543,2545,2547,2549,2551],{"class":90,"line":1347},[88,2532,2499],{"class":285},[88,2534,102],{"class":128},[88,2536,446],{"class":201},[88,2538,205],{"class":128},[88,2540,598],{"class":451},[88,2542,216],{"class":128},[88,2544,2379],{"class":477},[88,2546,2426],{"class":128},[88,2548,2430],{"class":2429},[88,2550,2433],{"class":128},[88,2552,458],{"class":140},[88,2554,2555],{"class":90,"line":1375},[88,2556,2557],{"class":128},"                    }\n",[88,2559,2560],{"class":90,"line":1380},[88,2561,135],{"emptyLinePlaceholder":134},[88,2563,2564,2567,2569],{"class":90,"line":1395},[88,2565,2566],{"class":94},"                    return",[88,2568,491],{"class":477},[88,2570,129],{"class":128},[88,2572,2573],{"class":90,"line":1416},[88,2574,2575],{"class":128},"                });\n",[88,2577,2578],{"class":90,"line":1425},[88,2579,135],{"emptyLinePlaceholder":134},[88,2581,2582],{"class":90,"line":1446},[88,2583,135],{"emptyLinePlaceholder":134},[88,2585,2586],{"class":90,"line":1451},[88,2587,2588],{"class":140},"        \u002F\u002F 调用代理对象\n",[88,2590,2591,2593,2595,2597,2599,2601,2603,2605,2607,2609,2611],{"class":90,"line":1456},[88,2592,487],{"class":94},[88,2594,491],{"class":490},[88,2596,495],{"class":494},[88,2598,2304],{"class":285},[88,2600,102],{"class":128},[88,2602,854],{"class":201},[88,2604,205],{"class":128},[88,2606,859],{"class":451},[88,2608,216],{"class":128},[88,2610,516],{"class":451},[88,2612,225],{"class":128},[88,2614,2615,2617,2619,2621,2623,2625,2627,2629,2631,2633],{"class":90,"line":1465},[88,2616,870],{"class":285},[88,2618,102],{"class":128},[88,2620,875],{"class":285},[88,2622,102],{"class":128},[88,2624,880],{"class":201},[88,2626,205],{"class":128},[88,2628,885],{"class":451},[88,2630,888],{"class":494},[88,2632,491],{"class":477},[88,2634,225],{"class":128},[88,2636,2637],{"class":90,"line":1470},[88,2638,628],{"class":128},[88,2640,2642],{"class":90,"line":2641},44,[88,2643,231],{"class":128},[2645,2646,2647],"h4",{"id":2647},"创建步骤",[10,2649,2650],{},"使用 JDK 给一个目标对象动态创建代理对象，分为三步",[2652,2653,2655],"h5",{"id":2654},"_1-先创建目标对象","1. 先创建目标对象",[10,2657,2658,2679,2680,2683,2684,2686],{},[85,2659,2661,2663,2666,2669,2671,2673,2676],{"className":79,"code":2660,"language":82,"style":83},"LoginService loginService = new LoginServiceImpl();",[88,2662,335],{"class":208},[88,2664,2665],{"class":490}," loginService ",[88,2667,2668],{"class":494},"=",[88,2670,830],{"class":94},[88,2672,386],{"class":201},[88,2674,815],{"class":2675},"syBBb",[88,2677,2678],{"class":128},";"," 我们要给 ",[85,2681,2682],{"code":2682},"loginServiceImpl"," 这个类（目标类）做功能增强，先 new 这个类的实体对象。然后将实体类类型改为 ",[85,2685,335],{"code":335}," 这个接口，这里就是面向对象里的多态了。因为 JDK 动态代理是基于接口实现的，所以目标类需要实现一个接口，也就是 LoginService 接口，后续的代理类也会实现这个接口。",[2652,2688,2690],{"id":2689},"_2-创建代理对象","2. 创建代理对象",[10,2692,2693,2694,1997,2708,2714,2715,2722],{},"JDK 动态代理主要使用 ",[85,2695,2696,2698,2700,2702,2704,2706],{"className":79,"code":1981,"language":82,"style":83},[88,2697,95],{"class":94},[88,2699,1986],{"class":94},[88,2701,102],{"class":101},[88,2703,1991],{"class":94},[88,2705,102],{"class":101},[88,2707,1996],{"class":94},[85,2709,2710,2712],{"className":79,"code":2000,"language":82,"style":83},[88,2711,789],{"class":94},[88,2713,2005],{"class":183}," 中的 ",[85,2716,2718,2720],{"className":79,"code":2717,"language":82,"style":83},"newProxyInstance()",[88,2719,2319],{"class":201},[88,2721,815],{"class":2675},"（翻译为 新建代理实例，也就是新建代理对象） 方法来生成代理对象。",[10,2724,2725,2726,2737],{},"本质上，",[85,2727,2729,2731,2733,2735],{"className":79,"code":2728,"language":82,"style":83},"Proxy.newProxyInstance()",[88,2730,2218],{"class":285},[88,2732,102],{"class":128},[88,2734,2319],{"class":201},[88,2736,815],{"class":128}," 这个方法做了两件事：",[1966,2739,2740,2743],{},[34,2741,2742],{},"在内存中动态的生成了一个类的字节码 class",[34,2744,2745],{},"new 了一个对象。通过内存中生成的代理类的字节码，实例化了代理对象",[10,2747,2748],{},"这个 newProxyInstance(类加载器，代理类实现哪些接口，调用处理器) 需要传入三个参数",[31,2750,2751],{},[34,2752,2753],{},"第一个参数：ClassLoader loader",[10,2755,2756,2757,2772],{},"告诉 JDK，要用哪个类加载器加载动态生成的代理类的字节码，一般我们就用目标对象所属类的类加载器，这里就是 ",[85,2758,2760,2762,2764,2766,2768,2770],{"className":79,"code":2759,"language":82,"style":83},"loginService.getClass().getClassLoader()",[88,2761,2467],{"class":285},[88,2763,102],{"class":128},[88,2765,2332],{"class":201},[88,2767,2335],{"class":128},[88,2769,2338],{"class":201},[88,2771,815],{"class":128},"。",[10,2774,2775,2776,2792,2793,2806,2807],{},"在 Spring 中，使用哪个类的类加载器由一个静态方法来确定，在 Spring-Core 中的 ",[85,2777,2779,2781,2783,2785,2787,2789],{"className":79,"code":2778,"language":82,"style":83},"package org.springframework.util",[88,2780,95],{"class":94},[88,2782,681],{"class":94},[88,2784,102],{"class":101},[88,2786,714],{"class":94},[88,2788,102],{"class":101},[88,2790,2791],{"class":94},"util","包下的 ",[85,2794,2796,2798,2801,2803],{"className":79,"code":2795,"language":82,"style":83},"public abstract class ClassUtils",[88,2797,177],{"class":94},[88,2799,2800],{"class":94}," abstract",[88,2802,383],{"class":94},[88,2804,2805],{"class":183}," ClassUtils"," 这个抽象类里，有一个静态方法 ",[85,2808,2810,2813],{"className":79,"code":2809,"language":82,"style":83},"getDefaultClassLoader()",[88,2811,2812],{"class":201},"getDefaultClassLoader",[88,2814,815],{"class":2675},[10,2816,2817],{},"源码如下：",[77,2819,2822],{"className":79,"code":2820,"filename":2821,"language":82,"meta":83,"style":83},"\u002F**\n * Return the default ClassLoader to use: typically the thread context\n * ClassLoader, if available; the ClassLoader that loaded the ClassUtils\n * class will be used as fallback.\n * \u003Cp>Call this method if you intend to use the thread context ClassLoader\n * in a scenario where you clearly prefer a non-null ClassLoader reference:\n * for example, for class path resource loading (but not necessarily for\n * {@code Class.forName}, which accepts a {@code null} ClassLoader\n * reference as well).\n * @return the default ClassLoader (only {@code null} if even the system\n * ClassLoader isn't accessible)\n * @see Thread#getContextClassLoader()\n * @see ClassLoader#getSystemClassLoader()\n *\u002F\n@Nullable\npublic static ClassLoader getDefaultClassLoader() {\n    ClassLoader cl = null;\n    try {\n        cl = Thread.currentThread().getContextClassLoader();\n    }\n    catch (Throwable ex) {\n        \u002F\u002F Cannot access thread context ClassLoader - falling back...\n    }\n    if (cl == null) {\n        \u002F\u002F No thread context class loader -> use class loader of this class.\n        cl = ClassUtils.class.getClassLoader();\n        if (cl == null) {\n            \u002F\u002F getClassLoader() returning null indicates the bootstrap ClassLoader\n            try {\n                cl = ClassLoader.getSystemClassLoader();\n            }\n            catch (Throwable ex) {\n                \u002F\u002F Cannot access system ClassLoader - oh well, maybe the caller can live with null...\n            }\n        }\n    }\n    return cl;\n}\n","org.springframework.util.ClassUtils.java",[85,2823,2824,2828,2833,2838,2843,2848,2853,2858,2863,2868,2877,2882,2892,2901,2905,2912,2929,2944,2951,2973,2977,2994,2999,3003,3022,3027,3045,3061,3066,3073,3089,3094,3109,3114,3118,3122,3126,3136],{"__ignoreMap":83},[88,2825,2826],{"class":90,"line":91},[88,2827,141],{"class":140},[88,2829,2830],{"class":90,"line":42},[88,2831,2832],{"class":140}," * Return the default ClassLoader to use: typically the thread context\n",[88,2834,2835],{"class":90,"line":51},[88,2836,2837],{"class":140}," * ClassLoader, if available; the ClassLoader that loaded the ClassUtils\n",[88,2839,2840],{"class":90,"line":144},[88,2841,2842],{"class":140}," * class will be used as fallback.\n",[88,2844,2845],{"class":90,"line":157},[88,2846,2847],{"class":140}," * \u003Cp>Call this method if you intend to use the thread context ClassLoader\n",[88,2849,2850],{"class":90,"line":168},[88,2851,2852],{"class":140}," * in a scenario where you clearly prefer a non-null ClassLoader reference:\n",[88,2854,2855],{"class":90,"line":174},[88,2856,2857],{"class":140}," * for example, for class path resource loading (but not necessarily for\n",[88,2859,2860],{"class":90,"line":190},[88,2861,2862],{"class":140}," * {@code Class.forName}, which accepts a {@code null} ClassLoader\n",[88,2864,2865],{"class":90,"line":195},[88,2866,2867],{"class":140}," * reference as well).\n",[88,2869,2870,2872,2874],{"class":90,"line":228},[88,2871,147],{"class":140},[88,2873,1233],{"class":150},[88,2875,2876],{"class":140}," the default ClassLoader (only {@code null} if even the system\n",[88,2878,2879],{"class":90,"line":378},[88,2880,2881],{"class":140}," * ClassLoader isn't accessible)\n",[88,2883,2884,2886,2889],{"class":90,"line":396},[88,2885,147],{"class":140},[88,2887,2888],{"class":150},"@see",[88,2890,2891],{"class":140}," Thread#getContextClassLoader()\n",[88,2893,2894,2896,2898],{"class":90,"line":401},[88,2895,147],{"class":140},[88,2897,2888],{"class":150},[88,2899,2900],{"class":140}," ClassLoader#getSystemClassLoader()\n",[88,2902,2903],{"class":90,"line":410},[88,2904,171],{"class":140},[88,2906,2907,2909],{"class":90,"line":438},[88,2908,371],{"class":370},[88,2910,2911],{"class":374},"Nullable\n",[88,2913,2914,2916,2919,2922,2925,2927],{"class":90,"line":461},[88,2915,177],{"class":94},[88,2917,2918],{"class":94}," static",[88,2920,2921],{"class":208}," ClassLoader",[88,2923,2924],{"class":201}," getDefaultClassLoader",[88,2926,815],{"class":2675},[88,2928,187],{"class":2675},[88,2930,2931,2934,2937,2939,2942],{"class":90,"line":484},[88,2932,2933],{"class":208},"    ClassLoader",[88,2935,2936],{"class":490}," cl ",[88,2938,2668],{"class":494},[88,2940,2941],{"class":923}," null",[88,2943,129],{"class":128},[88,2945,2946,2949],{"class":90,"line":533},[88,2947,2948],{"class":94},"    try",[88,2950,187],{"class":2675},[88,2952,2953,2956,2958,2961,2963,2966,2968,2971],{"class":90,"line":552},[88,2954,2955],{"class":490},"        cl ",[88,2957,2668],{"class":494},[88,2959,2960],{"class":285}," Thread",[88,2962,102],{"class":128},[88,2964,2965],{"class":201},"currentThread",[88,2967,2335],{"class":128},[88,2969,2970],{"class":201},"getContextClassLoader",[88,2972,835],{"class":128},[88,2974,2975],{"class":90,"line":576},[88,2976,628],{"class":2675},[88,2978,2979,2982,2984,2987,2990,2992],{"class":90,"line":587},[88,2980,2981],{"class":94},"    catch",[88,2983,539],{"class":2675},[88,2985,2986],{"class":208},"Throwable",[88,2988,2989],{"class":212}," ex",[88,2991,433],{"class":2675},[88,2993,187],{"class":2675},[88,2995,2996],{"class":90,"line":609},[88,2997,2998],{"class":140},"        \u002F\u002F Cannot access thread context ClassLoader - falling back...\n",[88,3000,3001],{"class":90,"line":615},[88,3002,628],{"class":2675},[88,3004,3005,3008,3010,3013,3016,3018,3020],{"class":90,"line":625},[88,3006,3007],{"class":94},"    if",[88,3009,539],{"class":2675},[88,3011,3012],{"class":490},"cl ",[88,3014,3015],{"class":494},"==",[88,3017,2941],{"class":923},[88,3019,433],{"class":2675},[88,3021,187],{"class":2675},[88,3023,3024],{"class":90,"line":631},[88,3025,3026],{"class":140},"        \u002F\u002F No thread context class loader -> use class loader of this class.\n",[88,3028,3029,3031,3033,3035,3037,3039,3041,3043],{"class":90,"line":1250},[88,3030,2955],{"class":490},[88,3032,2668],{"class":494},[88,3034,2805],{"class":285},[88,3036,102],{"class":128},[88,3038,789],{"class":285},[88,3040,102],{"class":128},[88,3042,2338],{"class":201},[88,3044,835],{"class":128},[88,3046,3047,3049,3051,3053,3055,3057,3059],{"class":90,"line":1275},[88,3048,536],{"class":94},[88,3050,539],{"class":2675},[88,3052,3012],{"class":490},[88,3054,3015],{"class":494},[88,3056,2941],{"class":923},[88,3058,433],{"class":2675},[88,3060,187],{"class":2675},[88,3062,3063],{"class":90,"line":1280},[88,3064,3065],{"class":140},"            \u002F\u002F getClassLoader() returning null indicates the bootstrap ClassLoader\n",[88,3067,3068,3071],{"class":90,"line":1285},[88,3069,3070],{"class":94},"            try",[88,3072,187],{"class":2675},[88,3074,3075,3078,3080,3082,3084,3087],{"class":90,"line":1302},[88,3076,3077],{"class":490},"                cl ",[88,3079,2668],{"class":494},[88,3081,2921],{"class":285},[88,3083,102],{"class":128},[88,3085,3086],{"class":201},"getSystemClassLoader",[88,3088,835],{"class":128},[88,3090,3091],{"class":90,"line":1323},[88,3092,3093],{"class":2675},"            }\n",[88,3095,3096,3099,3101,3103,3105,3107],{"class":90,"line":1328},[88,3097,3098],{"class":94},"            catch",[88,3100,539],{"class":2675},[88,3102,2986],{"class":208},[88,3104,2989],{"class":212},[88,3106,433],{"class":2675},[88,3108,187],{"class":2675},[88,3110,3111],{"class":90,"line":1347},[88,3112,3113],{"class":140},"                \u002F\u002F Cannot access system ClassLoader - oh well, maybe the caller can live with null...\n",[88,3115,3116],{"class":90,"line":1375},[88,3117,3093],{"class":2675},[88,3119,3120],{"class":90,"line":1380},[88,3121,612],{"class":2675},[88,3123,3124],{"class":90,"line":1395},[88,3125,628],{"class":2675},[88,3127,3128,3131,3134],{"class":90,"line":1416},[88,3129,3130],{"class":94},"    return",[88,3132,3133],{"class":490}," cl",[88,3135,129],{"class":128},[88,3137,3138],{"class":90,"line":1425},[88,3139,231],{"class":2675},[10,3141,3142],{},"Spring 采用的是三级降级策略，优先使用当前线程上下文类加载器 ThreadContextClassLoader（TCCL），如果失败，降级使用 Spring 自己的类加载器，如果还是白，继续降级，使用兜底方案，使用系统类加载器，如果依然失败，则返回 null交给调用者自己解决（oh well, maybe the caller can live with null...）。",[31,3144,3145],{"start":42},[34,3146,3147,3148,3150],{},"第二个参数：Class\u003C?>",[88,3149],{}," interfaces",[10,3152,3153],{},"代理类需要实现的一些接口。在 JDK 动态生成代理对象的时候，需要我们告诉他这个代理类要实现哪些接口。",[10,3155,3156],{},"类似前文中静态代理的的实现，代理类需要和目标类实现相同的接口，才能让调用者在调用的时候不需要关注具体调用的是哪个，从而做到无感，低耦合。如果代理类没有实现目标类的接口，那不就意味着代理类的行为和目标类完全不同，那就不是代理了，完全是个新类了。",[10,3158,3159,3160,3175,3176,3183,3184,3193,3194,3201,3202,3211],{},"上文代码中，使用 ",[85,3161,3163,3165,3167,3169,3171,3173],{"className":79,"code":3162,"language":82,"style":83},"loginService.getClass().getInterfaces()",[88,3164,2467],{"class":285},[88,3166,102],{"class":128},[88,3168,2332],{"class":201},[88,3170,2335],{"class":128},[88,3172,2357],{"class":201},[88,3174,815],{"class":128},"，loginService 是目标对象，调用 ",[85,3177,3179,3181],{"className":79,"code":3178,"language":82,"style":83},"getClass()",[88,3180,2332],{"class":201},[88,3182,815],{"class":2675}," 获取到的是目标对象的类，运行时是 ",[85,3185,3187,3189,3191],{"className":79,"code":3186,"language":82,"style":83},"LoginServiceImpl.class",[88,3188,771],{"class":285},[88,3190,102],{"class":128},[88,3192,789],{"class":285}," 这个实现类，然后继续调用他的 ",[85,3195,3197,3199],{"className":79,"code":3196,"language":82,"style":83},"getInterfaces()",[88,3198,2357],{"class":201},[88,3200,815],{"class":2675},"获取到的是这个类实现的接口，就是 ",[85,3203,3205,3207,3209],{"className":79,"code":3204,"language":82,"style":83},"LoginService.class",[88,3206,335],{"class":285},[88,3208,102],{"class":128},[88,3210,789],{"class":285}," 接口。",[10,3213,3214,3220],{},[85,3215,3216,3218],{"className":79,"code":3196,"language":82,"style":83},[88,3217,2357],{"class":201},[88,3219,815],{"class":2675}," 返回的是数组，一个类可以多实现（implement），但是只能单继承（extend）。所以这个类实现的接口可能有多个，就需要一个数组，放到数组里传给 JDK。",[31,3222,3223],{"start":51},[34,3224,3225],{},"第三个参数：InvocationHandler h",[10,3227,3228],{},"调用处理器，JDK 帮我们动态生成了代理类，并且这个代理类实现了我们指定的接口，此时 JDK 还不知道生成的这个代理类要做什么事，也就是接口中的方法需要我们来实现，就在这个参数里实现。",[10,3230,3231,3232,3240,3241,3248,3249,3257],{},"这个参数是个接口，这个接口上并没有加 ",[85,3233,3235,3237],{"className":79,"code":3234,"language":82,"style":83},"@FunctionalInterface",[88,3236,371],{"class":370},[88,3238,3239],{"class":374},"FunctionalInterface"," 注解，但是该接口中只有一个抽象方法 ",[85,3242,3244,3246],{"className":79,"code":3243,"language":82,"style":83},"invoke()",[88,3245,2462],{"class":201},[88,3247,815],{"class":2675},"，另外一个是静态方法 ",[85,3250,3252,3255],{"className":79,"code":3251,"language":82,"style":83},"invokeDefault()",[88,3253,3254],{"class":201},"invokeDefault",[88,3256,815],{"class":2675}," 所以是个隐式的函数式接口，可以使用 Lambda 表达式。",[10,3259,3260,3261,3267],{},"我们需要实现这个 ",[85,3262,3263,3265],{"className":79,"code":3243,"language":82,"style":83},[88,3264,2462],{"class":201},[88,3266,815],{"class":2675}," 方法，在这个方法里，写我们需要增强目标对象的目标方法的逻辑。这个方法在代理对象调用代理方法的时候，会被 JDK 调用执行。",[10,3269,3270,3271,3274],{},"这个方法有三个参数 ",[85,3272,3273],{"code":3273},"(Object proxy, Method method, Object[] args)"," ，proxy 就是 JDK 动态代理生成的代理对象的引用，method 是目标对象中的目标方法（要执行的目标方法就是它），args 是目标方法上的实参。",[10,3276,3277,3278,3284],{},"要调用目标对象的目标方法，就需要使用反射机制，传入的参数有 method（目标方法），所以可以使用方法的 ",[85,3279,3280,3282],{"className":79,"code":3243,"language":82,"style":83},[88,3281,2462],{"class":201},[88,3283,815],{"class":2675}," 函数来调用目标方法。",[10,3286,3287,3288,3320,3321,3327],{},"上面代码中 ",[85,3289,3291,3293,3296,3298,3300,3302,3304,3306,3308,3310,3312,3314,3316,3318],{"className":79,"code":3290,"language":82,"style":83},"boolean flag = (boolean) method.invoke(loginService, args)",[88,3292,2453],{"class":94},[88,3294,3295],{"class":490}," flag ",[88,3297,2668],{"class":494},[88,3299,539],{"class":2675},[88,3301,2453],{"class":94},[88,3303,433],{"class":2675},[88,3305,2374],{"class":285},[88,3307,102],{"class":128},[88,3309,2462],{"class":201},[88,3311,205],{"class":128},[88,3313,2467],{"class":477},[88,3315,216],{"class":128},[88,3317,2379],{"class":477},[88,3319,433],{"class":128}," 就是在调用目标对象的目标方法。这个 ",[85,3322,3323,3325],{"className":79,"code":3243,"language":82,"style":83},[88,3324,2462],{"class":201},[88,3326,815],{"class":2675}," 需要传入两个参数，第一个是目标对象，第二个是调用这个目标对象的目标方法时传入什么参数。",[2652,3329,3331],{"id":3330},"_3-调用代理对象的代理方法","3. 调用代理对象的代理方法",[10,3333,3334,3335,3345],{},"通过 ",[85,3336,3337,3339,3341,3343],{"className":79,"code":2728,"language":82,"style":83},[88,3338,2218],{"class":285},[88,3340,102],{"class":128},[88,3342,2319],{"class":201},[88,3344,815],{"class":128}," 构建好代理对象后，就可以直接调用代理对象的代理方法，和调用目标对象的目标方法一样，只不过把实例对象换成了代理对象，仅此而已。",[10,3347,3348,3349],{},"在上面示例代码中就是",[85,3350,3352,3355,3357,3359,3361,3363,3365,3367],{"className":79,"code":3351,"language":82,"style":83},"loginServiceProxy.login(\"admin\", \"123456\")",[88,3353,3354],{"class":285},"loginServiceProxy",[88,3356,102],{"class":128},[88,3358,854],{"class":201},[88,3360,205],{"class":128},[88,3362,859],{"class":451},[88,3364,216],{"class":128},[88,3366,516],{"class":451},[88,3368,433],{"class":128},[27,3370,3372],{"id":3371},"cglib-动态代理","CGLIB 动态代理",[10,3374,3375],{},"1.引入 CGLIB 依赖",[77,3377,3382],{"className":3378,"code":3379,"filename":3380,"language":3381,"meta":83,"style":83},"language-xml shiki shiki-themes catppuccin-latte one-dark-pro","\u003Cdependency>\n    \u003CgroupId>cglib\u003C\u002FgroupId>\n    \u003CartifactId>cglib\u003C\u002FartifactId>\n    \u003Cversion>3.3.0\u003C\u002Fversion>\n\u003C\u002Fdependency>\n","pom.xml","xml",[85,3383,3384,3397,3418,3435,3453],{"__ignoreMap":83},[88,3385,3386,3390,3394],{"class":90,"line":91},[88,3387,3389],{"class":3388},"sxizN","\u003C",[88,3391,3393],{"class":3392},"sGF2L","dependency",[88,3395,3396],{"class":3388},">\n",[88,3398,3399,3402,3405,3408,3411,3414,3416],{"class":90,"line":42},[88,3400,3401],{"class":3388},"    \u003C",[88,3403,3404],{"class":3392},"groupId",[88,3406,3407],{"class":3388},">",[88,3409,3410],{"class":477},"cglib",[88,3412,3413],{"class":3388},"\u003C\u002F",[88,3415,3404],{"class":3392},[88,3417,3396],{"class":3388},[88,3419,3420,3422,3425,3427,3429,3431,3433],{"class":90,"line":51},[88,3421,3401],{"class":3388},[88,3423,3424],{"class":3392},"artifactId",[88,3426,3407],{"class":3388},[88,3428,3410],{"class":477},[88,3430,3413],{"class":3388},[88,3432,3424],{"class":3392},[88,3434,3396],{"class":3388},[88,3436,3437,3439,3442,3444,3447,3449,3451],{"class":90,"line":144},[88,3438,3401],{"class":3388},[88,3440,3441],{"class":3392},"version",[88,3443,3407],{"class":3388},[88,3445,3446],{"class":477},"3.3.0",[88,3448,3413],{"class":3388},[88,3450,3441],{"class":3392},[88,3452,3396],{"class":3388},[88,3454,3455,3457,3459],{"class":90,"line":157},[88,3456,3413],{"class":3388},[88,3458,3393],{"class":3392},[88,3460,3396],{"class":3388},[10,3462,3463],{},"2.新建测试类",[77,3465,3467],{"className":79,"code":3466,"filename":640,"language":82,"meta":83,"style":83},"package top.dhbxs.demo.springaop.cglibproxy.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport net.sf.cglib.proxy.Enhancer;\nimport net.sf.cglib.proxy.MethodInterceptor;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@Slf4j\n@SpringBootTest\nclass LoginServiceTest {\n\n    @Test\n    void login() {\n        \u002F\u002F 创建目标对象\n        LoginService loginService = new LoginService();\n\n        \u002F\u002F 创建代理对象\n        LoginService loginServiceProxy = (LoginService) Enhancer.create(\n            LoginService.class,\n            (MethodInterceptor) (proxyObj, method, argsArr, methodProxy) -> {\n                log.info(\"开始登陆\"); \u002F\u002F 日志：非核心业务代码\n                log.info(\"{} 正在登陆系统\", argsArr[0]); \u002F\u002F 日志：非核心业务代码\n                boolean flag = (boolean) method.invoke(loginService, argsArr); \u002F\u002F 调用目标对象方法\n                if (!flag) {\n                    log.error(\"{} 登陆失败\", argsArr[0]); \u002F\u002F 日志：非核心业务代码\n                } else {\n                    log.info(\"{} 登陆成功\", argsArr[0]); \u002F\u002F 日志：非核心业务代码\n                }\n                return flag;\n            });\n\n        \u002F\u002F 调用代理对象\n        boolean flag = loginServiceProxy.login(\"admin\", \"123456\");\n        System.out.println(\"flag = \" + flag);\n    }\n}\n",[85,3468,3469,3498,3502,3522,3548,3572,3596,3624,3628,3634,3640,3648,3652,3658,3668,3672,3686,3690,3694,3718,3730,3764,3781,3805,3839,3854,3878,3887,3911,3916,3925,3930,3934,3938,3962,3984,3988],{"__ignoreMap":83},[88,3470,3471,3473,3475,3477,3479,3481,3483,3485,3487,3489,3492,3494,3496],{"class":90,"line":91},[88,3472,95],{"class":94},[88,3474,98],{"class":94},[88,3476,102],{"class":101},[88,3478,105],{"class":94},[88,3480,102],{"class":101},[88,3482,110],{"class":94},[88,3484,102],{"class":101},[88,3486,115],{"class":94},[88,3488,102],{"class":101},[88,3490,3491],{"class":94},"cglibproxy",[88,3493,102],{"class":101},[88,3495,125],{"class":94},[88,3497,129],{"class":128},[88,3499,3500],{"class":90,"line":42},[88,3501,135],{"emptyLinePlaceholder":134},[88,3503,3504,3506,3508,3510,3512,3514,3516,3518,3520],{"class":90,"line":51},[88,3505,282],{"class":94},[88,3507,286],{"class":285},[88,3509,102],{"class":289},[88,3511,292],{"class":285},[88,3513,102],{"class":289},[88,3515,297],{"class":285},[88,3517,102],{"class":289},[88,3519,302],{"class":285},[88,3521,129],{"class":128},[88,3523,3524,3526,3529,3531,3534,3536,3538,3540,3542,3544,3546],{"class":90,"line":144},[88,3525,282],{"class":94},[88,3527,3528],{"class":285}," net",[88,3530,102],{"class":289},[88,3532,3533],{"class":285},"sf",[88,3535,102],{"class":289},[88,3537,3410],{"class":285},[88,3539,102],{"class":289},[88,3541,1021],{"class":285},[88,3543,102],{"class":289},[88,3545,2031],{"class":285},[88,3547,129],{"class":128},[88,3549,3550,3552,3554,3556,3558,3560,3562,3564,3566,3568,3570],{"class":90,"line":157},[88,3551,282],{"class":94},[88,3553,3528],{"class":285},[88,3555,102],{"class":289},[88,3557,3533],{"class":285},[88,3559,102],{"class":289},[88,3561,3410],{"class":285},[88,3563,102],{"class":289},[88,3565,1021],{"class":285},[88,3567,102],{"class":289},[88,3569,2036],{"class":285},[88,3571,129],{"class":128},[88,3573,3574,3576,3578,3580,3582,3584,3586,3588,3590,3592,3594],{"class":90,"line":168},[88,3575,282],{"class":94},[88,3577,681],{"class":285},[88,3579,102],{"class":289},[88,3581,686],{"class":285},[88,3583,102],{"class":289},[88,3585,691],{"class":285},[88,3587,102],{"class":289},[88,3589,696],{"class":285},[88,3591,102],{"class":289},[88,3593,701],{"class":285},[88,3595,129],{"class":128},[88,3597,3598,3600,3602,3604,3606,3608,3610,3612,3614,3616,3618,3620,3622],{"class":90,"line":174},[88,3599,282],{"class":94},[88,3601,681],{"class":285},[88,3603,102],{"class":289},[88,3605,714],{"class":285},[88,3607,102],{"class":289},[88,3609,719],{"class":285},[88,3611,102],{"class":289},[88,3613,724],{"class":285},[88,3615,102],{"class":289},[88,3617,729],{"class":285},[88,3619,102],{"class":289},[88,3621,734],{"class":285},[88,3623,129],{"class":128},[88,3625,3626],{"class":90,"line":190},[88,3627,135],{"emptyLinePlaceholder":134},[88,3629,3630,3632],{"class":90,"line":195},[88,3631,371],{"class":370},[88,3633,375],{"class":374},[88,3635,3636,3638],{"class":90,"line":228},[88,3637,371],{"class":370},[88,3639,784],{"class":374},[88,3641,3642,3644,3646],{"class":90,"line":378},[88,3643,789],{"class":94},[88,3645,792],{"class":183},[88,3647,187],{"class":128},[88,3649,3650],{"class":90,"line":396},[88,3651,135],{"emptyLinePlaceholder":134},[88,3653,3654,3656],{"class":90,"line":401},[88,3655,404],{"class":370},[88,3657,805],{"class":374},[88,3659,3660,3662,3664,3666],{"class":90,"line":410},[88,3661,810],{"class":94},[88,3663,202],{"class":201},[88,3665,815],{"class":128},[88,3667,187],{"class":128},[88,3669,3670],{"class":90,"line":438},[88,3671,2269],{"class":140},[88,3673,3674,3676,3678,3680,3682,3684],{"class":90,"line":461},[88,3675,822],{"class":208},[88,3677,825],{"class":490},[88,3679,495],{"class":494},[88,3681,830],{"class":94},[88,3683,184],{"class":201},[88,3685,835],{"class":128},[88,3687,3688],{"class":90,"line":484},[88,3689,135],{"emptyLinePlaceholder":134},[88,3691,3692],{"class":90,"line":533},[88,3693,2292],{"class":140},[88,3695,3696,3698,3700,3702,3704,3706,3708,3711,3713,3716],{"class":90,"line":552},[88,3697,822],{"class":208},[88,3699,2304],{"class":490},[88,3701,495],{"class":494},[88,3703,539],{"class":128},[88,3705,335],{"class":477},[88,3707,433],{"class":128},[88,3709,3710],{"class":285}," Enhancer",[88,3712,102],{"class":128},[88,3714,3715],{"class":201},"create",[88,3717,2322],{"class":128},[88,3719,3720,3723,3725,3727],{"class":90,"line":576},[88,3721,3722],{"class":285},"            LoginService",[88,3724,102],{"class":128},[88,3726,789],{"class":285},[88,3728,3729],{"class":128},",\n",[88,3731,3732,3735,3737,3739,3741,3744,3746,3748,3750,3753,3755,3758,3760,3762],{"class":90,"line":587},[88,3733,3734],{"class":128},"            (",[88,3736,2036],{"class":477},[88,3738,433],{"class":128},[88,3740,539],{"class":128},[88,3742,3743],{"class":477},"proxyObj",[88,3745,216],{"class":128},[88,3747,2374],{"class":477},[88,3749,216],{"class":128},[88,3751,3752],{"class":477}," argsArr",[88,3754,216],{"class":128},[88,3756,3757],{"class":477}," methodProxy",[88,3759,433],{"class":128},[88,3761,2384],{"class":94},[88,3763,187],{"class":128},[88,3765,3766,3769,3771,3773,3775,3777,3779],{"class":90,"line":609},[88,3767,3768],{"class":285},"                log",[88,3770,102],{"class":128},[88,3772,446],{"class":201},[88,3774,205],{"class":128},[88,3776,452],{"class":451},[88,3778,455],{"class":128},[88,3780,458],{"class":140},[88,3782,3783,3785,3787,3789,3791,3793,3795,3797,3799,3801,3803],{"class":90,"line":615},[88,3784,3768],{"class":285},[88,3786,102],{"class":128},[88,3788,446],{"class":201},[88,3790,205],{"class":128},[88,3792,472],{"class":451},[88,3794,216],{"class":128},[88,3796,3752],{"class":477},[88,3798,2426],{"class":128},[88,3800,2430],{"class":2429},[88,3802,2433],{"class":128},[88,3804,458],{"class":140},[88,3806,3807,3810,3812,3814,3816,3818,3820,3822,3824,3826,3828,3830,3832,3834,3836],{"class":90,"line":625},[88,3808,3809],{"class":94},"                boolean",[88,3811,491],{"class":490},[88,3813,495],{"class":494},[88,3815,539],{"class":128},[88,3817,2453],{"class":94},[88,3819,433],{"class":128},[88,3821,2374],{"class":285},[88,3823,102],{"class":128},[88,3825,2462],{"class":201},[88,3827,205],{"class":128},[88,3829,2467],{"class":477},[88,3831,216],{"class":128},[88,3833,3752],{"class":477},[88,3835,455],{"class":128},[88,3837,3838],{"class":140}," \u002F\u002F 调用目标对象方法\n",[88,3840,3841,3844,3846,3848,3850,3852],{"class":90,"line":631},[88,3842,3843],{"class":94},"                if",[88,3845,539],{"class":128},[88,3847,542],{"class":494},[88,3849,545],{"class":477},[88,3851,433],{"class":128},[88,3853,187],{"class":128},[88,3855,3856,3858,3860,3862,3864,3866,3868,3870,3872,3874,3876],{"class":90,"line":1250},[88,3857,2395],{"class":285},[88,3859,102],{"class":128},[88,3861,560],{"class":201},[88,3863,205],{"class":128},[88,3865,565],{"class":451},[88,3867,216],{"class":128},[88,3869,3752],{"class":477},[88,3871,2426],{"class":128},[88,3873,2430],{"class":2429},[88,3875,2433],{"class":128},[88,3877,458],{"class":140},[88,3879,3880,3883,3885],{"class":90,"line":1275},[88,3881,3882],{"class":128},"                }",[88,3884,582],{"class":94},[88,3886,187],{"class":128},[88,3888,3889,3891,3893,3895,3897,3899,3901,3903,3905,3907,3909],{"class":90,"line":1280},[88,3890,2395],{"class":285},[88,3892,102],{"class":128},[88,3894,446],{"class":201},[88,3896,205],{"class":128},[88,3898,598],{"class":451},[88,3900,216],{"class":128},[88,3902,3752],{"class":477},[88,3904,2426],{"class":128},[88,3906,2430],{"class":2429},[88,3908,2433],{"class":128},[88,3910,458],{"class":140},[88,3912,3913],{"class":90,"line":1285},[88,3914,3915],{"class":128},"                }\n",[88,3917,3918,3921,3923],{"class":90,"line":1302},[88,3919,3920],{"class":94},"                return",[88,3922,491],{"class":477},[88,3924,129],{"class":128},[88,3926,3927],{"class":90,"line":1323},[88,3928,3929],{"class":128},"            });\n",[88,3931,3932],{"class":90,"line":1328},[88,3933,135],{"emptyLinePlaceholder":134},[88,3935,3936],{"class":90,"line":1347},[88,3937,2588],{"class":140},[88,3939,3940,3942,3944,3946,3948,3950,3952,3954,3956,3958,3960],{"class":90,"line":1375},[88,3941,487],{"class":94},[88,3943,491],{"class":490},[88,3945,495],{"class":494},[88,3947,2304],{"class":285},[88,3949,102],{"class":128},[88,3951,854],{"class":201},[88,3953,205],{"class":128},[88,3955,859],{"class":451},[88,3957,216],{"class":128},[88,3959,516],{"class":451},[88,3961,225],{"class":128},[88,3963,3964,3966,3968,3970,3972,3974,3976,3978,3980,3982],{"class":90,"line":1380},[88,3965,870],{"class":285},[88,3967,102],{"class":128},[88,3969,875],{"class":285},[88,3971,102],{"class":128},[88,3973,880],{"class":201},[88,3975,205],{"class":128},[88,3977,885],{"class":451},[88,3979,888],{"class":494},[88,3981,491],{"class":477},[88,3983,225],{"class":128},[88,3985,3986],{"class":90,"line":1395},[88,3987,628],{"class":128},[88,3989,3990],{"class":90,"line":1416},[88,3991,231],{"class":128},[10,3993,3994,3995,3998],{},"3.添加 jvm 参数 ",[85,3996,3997],{"code":3997},"--add-opens java.base\u002Fjava.lang=ALL-UNNAMED","，因为 JDK9 开始为了增强安全性，引入了模块系统（JPMS）对反射做了严格限制。CGLIB 尝试通过反射调用 ClassLoader.defineClass() 方法来动态生成类，但该方法属于 java.lang 包且未被暴露给“未命名模块”（即你的普通 Java 项目）。所以在不加上面的 jvm 参数时会报如下错误：",[77,4000,4002],{"className":906,"code":4001,"filename":908,"language":909,"meta":83,"style":83},"Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(...) accessible:\nmodule java.base does not \"opens java.lang\" to unnamed module\n",[85,4003,4004,4018],{"__ignoreMap":83},[88,4005,4006,4009,4012,4015],{"class":90,"line":91},[88,4007,4008],{"class":477},"Unable to make protected final ",[88,4010,4011],{"class":923},"java.lang.Class",[88,4013,4014],{"class":923}," java.lang.ClassLoader.defineClass",[88,4016,4017],{"class":477},"(...) accessible:\n",[88,4019,4020,4023,4026,4029,4032],{"class":90,"line":42},[88,4021,4022],{"class":477},"module ",[88,4024,4025],{"class":923},"java.base",[88,4027,4028],{"class":477}," does not ",[88,4030,4031],{"class":451},"\"opens java.lang\"",[88,4033,4034],{"class":477}," to unnamed module\n",[10,4036,4037],{},"4.执行结果",[77,4039,4041],{"className":906,"code":4040,"filename":908,"language":909,"meta":83,"style":83},"2026-04-19T23:36:10.364+08:00  INFO 15380 --- [SpringAOP] [           main] t.d.d.s.c.service.LoginServiceTest       : 开始登陆\n2026-04-19T23:36:10.365+08:00  INFO 15380 --- [SpringAOP] [           main] t.d.d.s.c.service.LoginServiceTest       : admin 正在登陆系统\n2026-04-19T23:36:10.367+08:00  INFO 15380 --- [SpringAOP] [           main] t.d.d.s.c.service.LoginServiceTest       : admin 登陆成功\nflag = true\n",[85,4042,4043,4061,4077,4093],{"__ignoreMap":83},[88,4044,4045,4048,4050,4053,4055,4058],{"class":90,"line":91},[88,4046,4047],{"class":140},"2026-04-19T23:36:10.364+08:00",[88,4049,920],{"class":919},[88,4051,4052],{"class":923}," 15380",[88,4054,927],{"class":477},[88,4056,4057],{"class":923},"t.d.d.s.c.service.LoginServiceTest",[88,4059,4060],{"class":477},"       : 开始登陆\n",[88,4062,4063,4066,4068,4070,4072,4074],{"class":90,"line":42},[88,4064,4065],{"class":140},"2026-04-19T23:36:10.365+08:00",[88,4067,920],{"class":919},[88,4069,4052],{"class":923},[88,4071,927],{"class":477},[88,4073,4057],{"class":923},[88,4075,4076],{"class":477},"       : admin 正在登陆系统\n",[88,4078,4079,4082,4084,4086,4088,4090],{"class":90,"line":51},[88,4080,4081],{"class":140},"2026-04-19T23:36:10.367+08:00",[88,4083,920],{"class":919},[88,4085,4052],{"class":923},[88,4087,927],{"class":477},[88,4089,4057],{"class":923},[88,4091,4092],{"class":477},"       : admin 登陆成功\n",[88,4094,4095,4097],{"class":90,"line":144},[88,4096,969],{"class":477},[88,4098,972],{"class":923},[17,4100,4101],{"id":4101},"总结",[4103,4104,4105,4119],"table",{},[4106,4107,4108],"thead",{},[4109,4110,4111,4115,4117],"tr",{},[4112,4113,4114],"th",{},"特性",[4112,4116,2043],{},[4112,4118,3372],{},[4120,4121,4122,4134,4145,4156],"tbody",{},[4109,4123,4124,4128,4131],{},[4125,4126,4127],"td",{},"依赖条件",[4125,4129,4130],{},"目标类必须实现接口",[4125,4132,4133],{},"目标类无需实现接口",[4109,4135,4136,4139,4142],{},[4125,4137,4138],{},"实现方式",[4125,4140,4141],{},"实现与目标类相同的接口",[4125,4143,4144],{},"继承目标类",[4109,4146,4147,4150,4153],{},[4125,4148,4149],{},"核心 API",[4125,4151,4152],{},"Proxy + InvocationHandler",[4125,4154,4155],{},"Enhancer + MethodInterceptor",[4109,4157,4158,4161,4164],{},[4125,4159,4160],{},"Spring AOP 适配",[4125,4162,4163],{},"目标类有接口时默认使用",[4125,4165,4166],{},"目标类无接口时自动切换使用",[4168,4169,4170],"style",{},"html pre.shiki code .sSWcl, html code.shiki .sSWcl{--shiki-default:#8839EF;--shiki-dark:#C678DD}html pre.shiki code .sHUla, html code.shiki .sHUla{--shiki-default:#7C7F93;--shiki-dark:#C678DD}html pre.shiki code .sgT6j, html code.shiki .sgT6j{--shiki-default:#7C7F93;--shiki-dark:#ABB2BF}html pre.shiki code .skYY2, html code.shiki .skYY2{--shiki-default:#7C7F93;--shiki-default-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic}html pre.shiki code .szsGz, html code.shiki .szsGz{--shiki-default:#8839EF;--shiki-default-font-style:inherit;--shiki-dark:#C678DD;--shiki-dark-font-style:italic}html pre.shiki code .sIkkJ, html code.shiki .sIkkJ{--shiki-default:#DF8E1D;--shiki-default-font-style:italic;--shiki-dark:#E5C07B;--shiki-dark-font-style:inherit}html pre.shiki code .seVD2, html code.shiki .seVD2{--shiki-default:#1E66F5;--shiki-default-font-style:italic;--shiki-dark:#61AFEF;--shiki-dark-font-style:inherit}html pre.shiki code .sPahJ, html code.shiki .sPahJ{--shiki-default:#8839EF;--shiki-dark:#E5C07B}html pre.shiki code .sddMY, html code.shiki .sddMY{--shiki-default:#E64553;--shiki-default-font-style:italic;--shiki-dark:#E06C75;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szf8G, html code.shiki .szf8G{--shiki-default:#4C4F69;--shiki-dark:#E5C07B}html pre.shiki code .sGc2n, html code.shiki .sGc2n{--shiki-default:#7C7F93;--shiki-dark:#E5C07B}html pre.shiki code .slb6Y, html code.shiki .slb6Y{--shiki-default:#FE640B;--shiki-dark:#ABB2BF}html pre.shiki code .saiVi, html code.shiki .saiVi{--shiki-default:#FE640B;--shiki-dark:#E5C07B}html pre.shiki code .sw_MA, html code.shiki .sw_MA{--shiki-default:#40A02B;--shiki-dark:#98C379}html pre.shiki code .sa2x1, html code.shiki .sa2x1{--shiki-default:#4C4F69;--shiki-dark:#ABB2BF}html pre.shiki code .sIGPt, html code.shiki .sIGPt{--shiki-default:#4C4F69;--shiki-dark:#E06C75}html pre.shiki code .sqgB4, html code.shiki .sqgB4{--shiki-default:#179299;--shiki-dark:#56B6C2}html pre.shiki code .sFUGW, html code.shiki .sFUGW{--shiki-default:#4C4F69;--shiki-dark:#98C379}html pre.shiki code .sFiMs, html code.shiki .sFiMs{--shiki-default:#D20F39;--shiki-dark:#D19A66}html pre.shiki code .sYQis, html code.shiki .sYQis{--shiki-default:#FE640B;--shiki-dark:#D19A66}html pre.shiki code .syBBb, html code.shiki .syBBb{--shiki-default:#7C7F93;--shiki-dark:#E06C75}html pre.shiki code .sxizN, html code.shiki .sxizN{--shiki-default:#179299;--shiki-dark:#ABB2BF}html pre.shiki code .sGF2L, html code.shiki .sGF2L{--shiki-default:#1E66F5;--shiki-dark:#E06C75}",{"title":83,"searchDepth":144,"depth":144,"links":4172},[4173,4176,4180,4190],{"id":19,"depth":42,"text":19,"children":4174},[4175],{"id":29,"depth":51,"text":29},{"id":63,"depth":42,"text":63,"children":4177},[4178,4179],{"id":66,"depth":51,"text":66},{"id":981,"depth":51,"text":981},{"id":1964,"depth":42,"text":1964,"children":4181},[4182,4189],{"id":2042,"depth":51,"text":2043,"children":4183},[4184],{"id":2647,"depth":144,"text":2647,"children":4185},[4186,4187,4188],{"id":2654,"depth":157,"text":2655},{"id":2689,"depth":157,"text":2690},{"id":3330,"depth":157,"text":3331},{"id":3371,"depth":51,"text":3372},{"id":4101,"depth":42,"text":4101},[4192],"技术","2026-04-20 11:18:07","用日志和业务逻辑解耦的案例，从静态代理的手动编码痛点出发，逐步演进至JDK动态代理与CGLIB字节码增强，对比两种机制的底层实现差异与适用场景，深入理解Spring AOP底层的实现方式。",false,"md","https:\u002F\u002Ffile.dhbxs.top\u002Fblog_img\u002F1776615019347_dtdl.webp",{"slots":4199},{},"\u002Fposts\u002F370adf0",null,{"text":4203,"minutes":4204,"time":4205,"words":4206},"18 min read",17.8,1068000,3560,{"title":5,"description":4194},{"loc":4200},"posts\u002F2026\u002FSpring AOP 动态代理机制：从静态代理到 JDK 与 CGLIB 的实现",[4211,4212],"Spring","Java","tech","2026-04-23 22:43:00","VXuTcoj7ZINON9HOVyWENhlSfiaXbRyoKJhcOzngWzI",[4217,4222],{"title":4218,"path":4219,"stem":4220,"date":4221,"type":4213,"children":-1},"从零手写一个 Spring Boot Starter：深入理解自动装配原理","\u002Fposts\u002F7dc99e0","posts\u002F2026\u002F从零手写一个 Spring Boot Starter：深入理解自动装配原理","2026-04-09 07:13:41",{"title":4223,"path":4224,"stem":4225,"date":4226,"type":4213,"children":-1},"重复造轮子之简易RPC框架","\u002Fposts\u002F39924a5","posts\u002F2026\u002F重复造轮子之简易RPC框架","2026-05-02 15:00:00",1778500161540]