javaå±äºä»ä¹è¯è¨ï¼
javaå±äºä»ä¹è¯è¨ï¼
JAVAè¯è¨ï¼å°±æ¯å±äºæ··ååè¯è¨ï¼è¿æ¯å±äºè§£éåè¯è¨åç¼è¯åè¯è¨ä¹é´çä¸ç§è¯è¨ãå¦ä¹ ä¸é¨é«çº§ç¨åºè¯è¨ï¼å¾å¤äººé½æ¨èJAVAãJAVAè½è®©ä½ å¦ä¹ å°ä¸é¨é«çº§ç¨åºè¯è¨çæ¹æ¹é¢é¢ï¼ä½åä¸ä¼é æå¦ä¹ æ²çº¿è¿äºé¡å³\x0d\\x0d\Javaè¯è¨æ¯ä¸ä¸ªæ¯æç½ç»è®¡ç®çé¢å对象ç¨åºè®¾è®¡è¯è¨ãJavaè¯è¨å¸æ¶äºSmalltalkè¯è¨åC++è¯åè¢è¨çä¼ç¹ï¼å¹¶å¢å äºå ¶å®ç¹æ§ï¼å¦æ¯æ并åç¨åºè®¾è®¡ãç½ç»éä¿¡ãåå¤åªä½æ°æ®æ§å¶çã主è¦ç¹æ§å¦ä¸ï¼\x0d\1)Javaè¯è¨æ¯ç®åçãJavaè¯è¨çè¯æ³ä¸Cè¯è¨åC++è¯è¨å¾æ¥è¿ï¼ä½¿å¾å¤§å¤æ°ç¨åºåå¾å®¹æå¦ä¹ å使ç¨Javaãå¦ä¸æ¹é¢ï¼Java丢å¼äºC++ä¸å¾å°ä½¿ç¨çãå¾é¾ç解çã令人迷æçé£äºç¹æ§ï¼å¦æä½ç¬¦éè½½ãå¤ç»§æ¿ãèªå¨ç强å¶ç±»å转æ¢ãç¹å«å°ï¼Javaè¯è¨ä¸ä½¿ç¨æéï¼å¹¶æä¾äºèªå¨çåºææ¶éï¼ä½¿å¾ç¨åºåä¸å¿ 为å å管çèæ 忧ã\x0d\2)Javaè¯è¨æ¯ä¸ä¸ªé¢å对象çãJavaè¯è¨æä¾ç±»ãæ¥å£å继æ¿çåè¯ï¼ä¸ºäºç®åèµ·è§ï¼åªæ¯æç±»ä¹é´çå继æ¿ï¼ä½æ¯ææ¥å£ä¹é´çå¤ç»§æ¿ï¼å¹¶æ¯æç±»ä¸æ¥å£ä¹é´çå®ç°æºå¶ï¼å ³é®å为implementsï¼ãJavaè¯è¨å ¨é¢æ¯æå¨æç»å®ï¼èC++è¯è¨åªå¯¹èå½æ°ä½¿ç¨å¨æç»å®ãæ»ä¹ï¼Javaè¯è¨æ¯ä¸ä¸ªçº¯çé¢å对象ç¨åºè®¾è®¡è¯è¨ã\x0d\3)Javaè¯è¨æ¯åå¸å¼çãJavaè¯è¨æ¯æInternetåºç¨çå¼åï¼å¨åºæ¬çJavaåºç¨ç¼ç¨æ¥å£ä¸æä¸ä¸ªç½ç»åºç¨ç¼ç¨æ¥å£ï¼java.netï¼ï¼å®æä¾äºç¨äºç½ç»åºç¨ç¼ç¨çç±»åºï¼å æ¬URLãURLConnectionãSocketãServerSocketçãJavaçRMI(è¿ç¨æ¹æ³æ¿æ´»)æºå¶ä¹æ¯å¼ååå¸å¼åºç¨çéè¦æ段ã\x0d\4)Javaè¯è¨æ¯å¥å£®çãJavaç强类åæºå¶ãå¼å¸¸å¤çãåºæçèªå¨æ¶éçæ¯Javaç¨åºå¥å£®æ§çéè¦ä¿è¯ã对æéç丢å¼æ¯Javaçææºéæ©ãJavaçå®å ¨æ£æ¥æºå¶ä½¿å¾Javaæ´å ·å¥å£®æ§ã\x0d\5)Javaè¯è¨æ¯å®å ¨çãJavaé常被ç¨å¨ç½ç»ç¯å¢ä¸ï¼ä¸ºæ¤ï¼Javaæä¾äºä¸ä¸ªå®å ¨æºå¶ä»¥é²æ¶è å¯æºæ代ç çæ»å»ãé¤äºJavaè¯è¨å ·æç许å¤å®å ¨ç¹æ§ä»¥å¤ï¼Java对éè¿ç½ç»ä¸è½½çç±»å ·æä¸ä¸ªå®å ¨é²èæºå¶ï¼ç±»ClassLoaderï¼ï¼å¦åé ä¸åçåå空é´ä»¥é²æ¿ä»£æ¬å°çååç±»ãåè代ç æ£æ¥ï¼å¹¶æä¾å®å ¨ç®¡çæºå¶ï¼ç±»SecurityManagerï¼è®©Javaåºç¨è®¾ç½®å®å ¨å¨å µã\x0d\6)Javaè¯è¨æ¯ä½ç³»ç»æä¸ç«çãJavaç¨åºï¼åç¼ä¸ºjavaçæ件ï¼å¨Javaå¹³å°ä¸è¢«ç¼è¯ä¸ºä½ç³»ç»æä¸ç«çåèç æ ¼å¼ï¼åç¼ä¸ºclassçæ件ï¼é¦æ,源码源码设计书籍ç¶åå¯ä»¥å¨å®ç°è¿ä¸ªJavaå¹³å°çä»»ä½ç³»ç»ä¸è¿è¡ãè¿ç§éå¾éåäºå¼æçç½ç»ç¯å¢å软件çååã\x0d\7)Javaè¯è¨æ¯å¯ç§»æ¤çãè¿ç§å¯ç§»æ¤æ§æ¥æºäºä½ç³»ç»æä¸ç«æ§ï¼å¦å¤ï¼Javaè¿ä¸¥æ ¼è§å®äºå个åºæ¬æ°æ®ç±»åçé¿åº¦ãJavaç³»ç»æ¬èº«ä¹å ·æå¾å¼ºçå¯ç§»æ¤æ§ï¼Javaç¼è¯å¨æ¯ç¨Javaå®ç°çï¼Javaçè¿è¡ç¯å¢æ¯ç¨ANSICå®ç°çã\x0d\8)Javaè¯è¨æ¯è§£éåçãå¦åæè¿°ï¼Javaç¨åºå¨Javaå¹³å°ä¸è¢«ç¼è¯ä¸ºåèç æ ¼å¼ï¼ç¶åå¯ä»¥å¨å®ç°è¿ä¸ªJavaå¹³å°çä»»ä½ç³»ç»ä¸è¿è¡ãå¨è¿è¡æ¶ï¼Javaå¹³å°ä¸çJava解éå¨å¯¹è¿äºåèç è¿è¡è§£éæ§è¡ï¼æ§è¡è¿ç¨ä¸éè¦çç±»å¨èæ¥é¶æ®µè¢«è½½å ¥å°è¿è¡ç¯å¢ä¸ã\x0d\9)Javaæ¯é«æ§è½çãä¸é£äºè§£éåçé«çº§èæ¬è¯è¨ç¸æ¯ï¼Javaçç¡®æ¯é«æ§è½çãäºå®ä¸ï¼Javaçè¿è¡é度éçJIT(Just-In-Time)ç¼è¯å¨ææ¯çåå±è¶æ¥è¶æ¥è¿äºC++ã\x0d\)Javaè¯è¨æ¯å¤çº¿ç¨çãå¨Javaè¯è¨ä¸ï¼çº¿ç¨æ¯ä¸ç§ç¹æ®ç对象ï¼å®å¿ é¡»ç±Threadç±»æå ¶åï¼åï¼ç±»æ¥å建ãé常æ两ç§æ¹æ³æ¥å建线ç¨ï¼å ¶ä¸ï¼ä½¿ç¨åæ为Thread(Runnable)çæé åå°ä¸ä¸ªå®ç°äºRunnableæ¥å£ç对象å è£ æä¸ä¸ªçº¿ç¨ï¼å ¶äºï¼ä»Thread类派çåºå类并éårunæ¹æ³ï¼ä½¿ç¨è¯¥åç±»å建ç对象å³ä¸ºçº¿ç¨ãå¼å¾æ³¨æçæ¯Thread类已ç»å®ç°äºRunnableæ¥å£ï¼å æ¤ï¼ä»»ä½ä¸ä¸ªçº¿ç¨åæå®çrunæ¹æ³ï¼èrunæ¹æ³ä¸å å«äºçº¿ç¨æè¦è¿è¡ç代ç ã线ç¨çæ´»å¨ç±ä¸ç»æ¹æ³æ¥æ§å¶ãJavaè¯è¨æ¯æå¤ä¸ªçº¿ç¨çåæ¶æ§è¡ï¼å¹¶æä¾å¤çº¿ç¨ä¹é´çåæ¥æºå¶ï¼å ³é®å为synchronizedï¼ã\x0d\)Javaè¯è¨æ¯å¨æçãJavaè¯è¨ç设计ç®æ ä¹ä¸æ¯éåºäºå¨æååçç¯å¢ãJavaç¨åºéè¦çç±»è½å¨æå°è¢«è½½å ¥å°è¿è¡ç¯å¢ï¼ä¹å¯ä»¥éè¿ç½ç»æ¥è½½å ¥æéè¦çç±»ãè¿ä¹æå©äºè½¯ä»¶çå级ãå¦å¤ï¼Javaä¸çç±»æä¸ä¸ªè¿è¡æ¶å»ç表示ï¼è½è¿è¡è¿è¡æ¶å»çç±»åæ£æ¥ã\x0d\Javaè¯è¨çä¼è¯ç¹æ§ä½¿å¾Javaåºç¨å ·ææ æ¯çå¥å£®æ§åå¯é æ§ï¼è¿ä¹åå°äºåºç¨ç³»ç»çç»´æ¤è´¹ç¨ãJava对对象ææ¯çå ¨é¢æ¯æåJavaå¹³å°å åµçAPIè½ç¼©çåºç¨ç³»ç»çå¼åæ¶é´å¹¶éä½ææ¬ãJavaçç¼è¯ä¸æ¬¡ï¼å°å¤å¯è¿è¡çç¹æ§ä½¿å¾å®è½å¤æä¾ä¸ä¸ªéå¤å¯ç¨çå¼æ¾ç»æåå¨å¤å¹³å°ä¹é´ä¼ éä¿¡æ¯çä½ææ¬æ¹å¼ãç¹å«æ¯Javaä¼ä¸åºç¨ç¼ç¨æ¥å£ï¼JavaEnterpriseAPIsï¼ä¸ºä¼ä¸è®¡ç®åçµååå¡åºç¨ç³»ç»æä¾äºæå ³ææ¯å丰å¯çç±»åºã\x0d\1)JDBCï¼JavaDatabaseConnectivityï¼æä¾è¿æ¥åç§å ³ç³»æ°æ®åºçç»ä¸æ¥å£ã\x0d\2)EJB(EnterpriseJavaBeans)使å¾å¼åè æ¹ä¾¿å°å建ãé¨ç½²å管ç跨平å°çåºäºç»ä»¶çä¼ä¸åºç¨ã\x0d\3)JavaRMI(JavaRemoteMethodInvocation)ç¨æ¥å¼ååå¸å¼Javaåºç¨ç¨åºãä¸ä¸ªJava对象çæ¹æ³è½è¢«è¿ç¨Javaèææºè°ç¨ãè¿æ ·ï¼è¿ç¨æ¹æ³æ¿æ´»å¯ä»¥åçå¨å¯¹çç两端ï¼ä¹å¯ä»¥åçå¨å®¢æ·ç«¯åæå¡å¨ä¹é´ï¼åªè¦åæ¹çåºç¨ç¨åºé½æ¯ç¨Javaåçã\x0d\4)JavaIDL(JavaInterfaceDefinitionLanguage)æä¾ä¸CORBA(CommonObjectRequestBrokerArchitecture)çæ é¢çäºæä½æ§ãè¿ä½¿å¾Javaè½éæå¼æçåå¡ä¿¡æ¯èµæºã\x0d\5)JNDI(JavaNamingandDirectoryInterface)æä¾ä»Javaå¹³å°å°çç»ä¸çæ é¢çè¿æ¥ãè¿ä¸ªæ¥å£å±è½äºä¼ä¸ç½ç»æ使ç¨çåç§å½ååç®å½æå¡ã\x0d\6)JMAPIï¼JavaManagementAPIï¼ä¸ºå¼æç½ç»ä¸ç³»ç»ãç½ç»åæå¡ç®¡ççå¼åæä¾ä¸æ´å¥ä¸°å¯ç对象åæ¹æ³ã\x0d\7)JMS(JavaMessageService)æä¾ä¼ä¸æ¶æ¯æå¡ï¼å¦å¯é çæ¶æ¯éåãåå¸å订é éä¿¡ã以åæå ³æ¨æï¼Push/Pullï¼ææ¯çå个æ¹é¢ã\x0d\8)JTS(JavatransactionService)æä¾ååäºå¡å¤çèµæºçå¼æ¾æ åï¼è¿äºäºå¡å¤çèµæºå æ¬äºå¡å¤çåºç¨ç¨åºãäºå¡å¤ç管çåçæ§ã\x0d\å¨Javaææ¯ä¸ï¼å¼å¾å ³æ³¨çè¿æJavaBeansï¼å®æ¯ä¸ä¸ªå¼æ¾çæ åçç»ä»¶ä½ç³»ç»æï¼å®ç¬ç«äºå¹³å°ï¼ä½ä½¿ç¨Javaè¯è¨ãä¸ä¸ªJavaBeanæ¯ä¸ä¸ªæ»¡è¶³JavaBeansè§èçJavaç±»ï¼é常å®ä¹äºä¸ä¸ªç°å®ä¸ççäºç©ææ¦å¿µãä¸ä¸ªJavaBeanç主è¦ç¹å¾å æ¬å±æ§ãæ¹æ³åäºä»¶ãé常ï¼å¨ä¸ä¸ªæ¯æJavaBeansè§èçå¼åç¯å¢ï¼å¦SunJavaStudioåIBMVisualAgeforJavaï¼ä¸ï¼å¯ä»¥å¯è§å°æä½JavaBeanï¼ä¹å¯ä»¥ä½¿ç¨JavaBeanæé åºæ°çJavaBeanãJavaBeançä¼å¿è¿å¨äºJava带æ¥çå¯ç§»æ¤æ§ãç°å¨ï¼EJB(EnterpriseJavaBeans)å°JavaBeanæ¦å¿µæ©å±å°Javaæå¡ç«¯ç»ä»¶ä½ç³»ç»æï¼è¿ä¸ªæ¨¡åæ¯æå¤å±çåå¸å¼å¯¹è±¡åºç¨ãé¤äºJavaBeansï¼å ¸åçç»ä»¶ä½ç³»ç»æè¿æDCOMåCORBAï¼å ³äºè¿äºç»ä»¶ä½ç³»ç»æçæ·±å ¥è®¨è®ºè¶ åºäºæ¬ä¹¦çèå´ã
javaæ¯ä»ä¹ç±»åè¯è¨javaè¯è¨å±äºæ··ååè¯è¨ï¼æ¯è§£éåè¯è¨åç¼èæºè¯åè¯è¨ä¹é´çä¸ç§è¯è¨ï¼æ¯ä¸ä¸ªæ¯æç½ç»è®¡ç®çé¢å对象ç¨åºè®¾è®¡è¯è¨ï¼å¸æ¶äºSmalltalkè¯è¨åC++è¯è¨çä¼ç¹ï¼å¹¶å¢å äºå ¶ç¬æç¹æ§ï¼å¦æ¯æ并åç¨åºè®¾è®¡ãç½ç»éä¿¡ãåå¤åªä½æ°æ®æ§å¶çã
Javaæç®åæ§ãé¢å对象ãåå¸æ§ãç¼è¯å解éæ§ã稳å¥æ§ãå®å ¨æ§ãå¯ç§»æ¤æ§ãé«æ§è½çç¹ç¹ï¼å¯ä»¥ç¼ååºç¨ç¨åºãWebåºç¨ç¨åºãåå¸å¼ç³»ç»ååµå ¥å¼ç³»ç»åºç¨ç¨åºçã
计ç®æºè¯è¨å¾å¤ï¼ä¸åçè¯è¨æ侧éçé¢åä¸ç¸åï¼Javaå è¯æ³ç®åãä¸ææ¯è¾å¿«ï¼å¨Androidåºç¨ãéèä¸æè¦ä¼ãç½ç«ã大æ°æ®ææ¯ãé«é¢äº¤æç空é´çæ¹é¢é½æåºç¨ã
æ»ç»ï¼
javaè¯è¨å±äºæ··ååè¯è¨ï¼æ¯è§£éåè¯è¨åç¼è¯åè¯è¨ä¹é´çä¸ç§è¯è¨ï¼æ¯ä¸ä¸ªæ¯æç½ç»è®¡ç®çé¢å对象ç¨åºè®¾è®¡è¯è¨ï¼å¸æ¶äºSmalltalkè¯è¨åC++è¯è¨çä¼ç¹ï¼å¹¶å¢å äºå ¶ç¬æç¹æ§ï¼å¦æ¯æ并åç¨åºè®¾è®¡ãç½ç»éä¿¡ãååçå¤åªä½æ°æ®æ§å¶çã
声æï¼æ¬ç½é¡µå 容æ¨å¨ä¼ æç¥è¯ï¼è¥æä¾µæçé®é¢è¯·åæ¶ä¸æ¬ç½èç³»ï¼æ们å°å¨ç¬¬ä¸æ¶é´å é¤å¤çãTEL:-E-MAIL:@qq.com
javaæ¯ä»ä¹ç±»åçç¼ç¨è¯è¨
åç±»éè¦ç¡®å®ä»ä»ä¹è§åº¦å»åã
1.ä»è¯è¨ç级ä¸æ¥åï¼javaå±äºé«çº§è¯è¨ï¼éè¦ç¼è¯æåèç ä¹åæè½è¿è¡ã
2.ä»è¯è¨è®¾è®¡ææ³æ¥çï¼javaå±äºé¢å对象çè¯è¨ï¼å°ææçäºç©çææ¯å¯¹è±¡ï¼æå°è£ ã继æ¿ãå¤æçç¹æ§ã
3.ä»æ§è¡è¿ç¨æ¥çï¼javaæ¯ä¸ç§æ··ååè¯è¨ï¼javaå ç¼è¯æåèç ç¶åå¨JVMä¸è§£éæ§è¡ï¼ç¼è¯åè¯è¨éè¦å¸åç»è¿ç¼è¯å¨å°æºä»£ç ç¼è¯ææºå¨ç ä¹åæè½æ§è¡çè¯è¨ï¼å¦Cï¼C++ï¼è§£éåè¯è¨ï¼ä¸éè¦ç¼è¯ï¼å¨è¿è¡ç¨æ¿æ£åºçæ¶åéè¡ç¿»è¯ï¼å¦JavaScriptï¼pythonï¼ã
4.ä»è¿è¡æ¶æ°æ®ç±»åæ¥åï¼javaæ¯ä¸ç§éæç±»åè¯è¨ï¼æè 说æ¯å¼ºç±»åè¯è¨ï¼å®çæ°æ®ç±»åå¨ç¼è¯ææè 说è¿è¡åç¡®å®çï¼å¨å®ä¹åéæ¶éè¦æç¡®æå®å®æ¶è½¿æçæ°æ®ç±»åï¼å¦æä¸ç»è¿å¼ºå¶ç±»å转æ¢ï¼å®çç±»åå°±ä¸ä¼åã
综åæ¥è¯´ï¼javaæ¯ä¸é¨å¼ºç±»åçãé¢å对象çæ··ååé«çº§ç¼ç¨è¯è¨ã
从源码层面带你实现一个自动注入注解
首先,需要了解到的源码是。SpringBean的源码生命周期在生命周期中。注入bean属性的源码位置是在以下代码:populateBean位置中
那么我们在项目中使用注解产生一个bean的时候必定会经过以下代码进行一个bean的创建流程
/**省略代码**///开始初始化bean实例对象ObjectexposedObject=bean;try{ //<5>对bean进行填充,将各个属性值注入,源码其中,源码可能存在依赖于其他bean的源码属性populateBean(beanName,mbd,instanceWrapper);//<6>调用初始化方法exposedObject=initializeBean(beanName,exposedObject,mbd);}catch(Throwableex){ if(exinstanceofBeanCreationException&&beanName.equals(((BeanCreationException)ex).getBeanName())){ throw(BeanCreationException)ex;}else{ thrownewBeanCreationException(mbd.getResourceDescription(),beanName,"Initializationofbeanfailed",ex);}}/**省略代码**/在生命周期中populateBean进行填充bean数据。把其他依赖引入进来
BeanPostProcessor是源码一个bean创建时候的一个钩子。
以下代码是源码循环调用实现了BeanPostProcessor子类InstantiationAwareBeanPostProcessor#postProcessProperties方法
Spring在以下代码中有自动注入的拓展点。关键就是源码实现InstantiationAwareBeanPostProcessor#postProcessProperties
/**省略代码**/for(BeanPostProcessorbp:getBeanPostProcessors()){ if(bpinstanceofInstantiationAwareBeanPostProcessor){ InstantiationAwareBeanPostProcessoribp=(InstantiationAwareBeanPostProcessor)bp;//对所有需要依赖检查的属性进行后处理PropertyValuespvsToUse=ibp.postProcessProperties(pvs,bw.getWrappedInstance(),beanName);if(pvsToUse==null){ //从bw对象中提取PropertyDescriptor结果集//PropertyDescriptor:可以通过一对存取方法提取一个属性if(filteredPds==null){ filteredPds=filterPropertyDescriptorsForDependencyCheck(bw,mbd.allowCaching);}pvsToUse=ibp.postProcessPropertyValues(pvs,filteredPds,bw.getWrappedInstance(),beanName);if(pvsToUse==null){ return;}}pvs=pvsToUse;}}/**省略代码**/我们展开来讲一下@Autowired的实现是怎么样的吧:
实现类为AutowiredAnnotationBeanPostProcessor.java
从上面可以得知,填充bean的时候。时调用了方法ibp.postProcessPropertyValues()
那么AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues()则会被调用
调用findAutowiringMetadata获取class以及父类带有@Autowired或者@Value的属性或者方法:
/**省略代码**/publicPropertyValuespostProcessProperties(PropertyValuespvs,Objectbean,StringbeanName){ //获取所有可以注入的元数据InjectionMetadatametadata=findAutowiringMetadata(beanName,bean.getClass(),pvs);try{ //注入数据metadata.inject(bean,beanName,pvs);}catch(BeanCreationExceptionex){ throwex;}catch(Throwableex){ thrownewBeanCreationException(beanName,"Injectionofautowireddependenciesfailed",ex);}returnpvs;}privateInjectionMetadatafindAutowiringMetadata(StringbeanName,Class<?>clazz,@NullablePropertyValuespvs){ //缓存名字获取StringcacheKey=(StringUtils.hasLength(beanName)?beanName:clazz.getName());InjectionMetadatametadata=this.injectionMetadataCache.get(cacheKey);//获取是否已经读取过这个class类的InjectionMetadata有的话直接从缓存中获取出去if(InjectionMetadata.needsRefresh(metadata,clazz)){ synchronized(this.injectionMetadataCache){ //双重检查metadata=this.injectionMetadataCache.get(cacheKey);if(InjectionMetadata.needsRefresh(metadata,clazz)){ if(metadata!=null){ metadata.clear(pvs);}//构建自动注入的元数据metadata=buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey,metadata);}}}returnmetadata;}privateInjectionMetadatabuildAutowiringMetadata(finalClass<?>clazz){ if(!AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)){ returnInjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement>elements=newArrayList<>();Class<?>targetClass=clazz;do{ finalList<InjectionMetadata.InjectedElement>currElements=newArrayList<>();//循环targetClass的所有field并执FieldCallback逻辑(函数式编程接口,传入的是一个执行函数)ReflectionUtils.doWithLocalFields(targetClass,field->{ //获得字段上面的Annotation注解MergedAnnotation<?>ann=findAutowiredAnnotation(field);if(ann!=null){ //判断是否为静态属性如果是,则不进行注入if(Modifier.isStatic(field.getModifiers())){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationisnotsupportedonstaticfields:"+field);}return;}//注解是否为必须依赖项booleanrequired=determineRequiredStatus(ann);currElements.add(newAutowiredFieldElement(field,required));}});//循环targetClass的所有Method并执MethodCallback逻辑(函数式编程接口,传入的是一个执行函数)ReflectionUtils.doWithLocalMethods(targetClass,method->{ MethodbridgedMethod=BridgeMethodResolver.findBridgedMethod(method);if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method,bridgedMethod)){ return;}MergedAnnotation<?>ann=findAutowiredAnnotation(bridgedMethod);if(ann!=null&&method.equals(ClassUtils.getMostSpecificMethod(method,clazz))){ //判断是否为静态方法如果是,则不进行注入if(Modifier.isStatic(method.getModifiers())){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationisnotsupportedonstaticmethods:"+method);}return;}//判断静态方法参数是否为0if(method.getParameterCount()==0){ if(logger.isInfoEnabled()){ logger.info("Autowiredannotationshouldonlybeusedonmethodswithparameters:"+method);}}booleanrequired=determineRequiredStatus(ann);PropertyDescriptorpd=BeanUtils.findPropertyForMethod(bridgedMethod,clazz);currElements.add(newAutowiredMethodElement(method,required,pd));}});//数据加到数组最前方父类的的注解都放在靠前的位置elements.addAll(0,currElements);//如果有父类则设置targetClass为父类。如此循环targetClass=targetClass.getSuperclass();}while(targetClass!=null&&targetClass!=Object.class);returnInjectionMetadata.forElements(elements,clazz);}/**省略代码**/真正注入数据的是metadata.inject(bean,beanName,pvs);
调用的是InjectionMetadata#inject方法
publicvoidinject(Objecttarget,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ Collection<InjectedElement>checkedElements=this.checkedElements;//带有注解的方法或者属性列表Collection<InjectedElement>elementsToIterate=(checkedElements!=null?checkedElements:this.injectedElements);if(!elementsToIterate.isEmpty()){ for(InjectedElementelement:elementsToIterate){ element.inject(target,beanName,pvs);}}}循环调用之前加入的带有注解的方法或者属性构建的对象AutowiredFieldElement#inject,AutowiredMethodElement#inject
/***属性上有注解构建的处理对象*/privateclassAutowiredFieldElementextendsInjectionMetadata.InjectedElement{ privatefinalbooleanrequired;privatevolatilebooleancached;@NullableprivatevolatileObjectcachedFieldValue;publicAutowiredFieldElement(Fieldfield,booleanrequired){ super(field,null);this.required=required;}@Overrideprotectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ //获取属性名Fieldfield=(Field)this.member;Objectvalue;//Bean不是单例的话,会重复进入注入的这个操作,if(this.cached){ try{ value=resolvedCachedArgument(beanName,this.cachedFieldValue);}catch(NoSuchBeanDefinitionExceptionex){ //Unexpectedremovaloftargetbeanforcachedargument->re-resolvevalue=resolveFieldValue(field,bean,beanName);}}else{ //首次创建的时候进入该方法value=resolveFieldValue(field,bean,beanName);}if(value!=null){ //属性如果不为public的话,则设置为可访问ReflectionUtils.makeAccessible(field);field.set(bean,value);}}@NullableprivateObjectresolveFieldValue(Fieldfield,Objectbean,@NullableStringbeanName){ //构建DependencyDescriptor对象DependencyDescriptordesc=newDependencyDescriptor(field,this.required);desc.setContainingClass(bean.getClass());//注入bean的数量。有可能字段上是一个ListSet<String>autowiredBeanNames=newLinkedHashSet<>(1);Assert.state(beanFactory!=null,"NoBeanFactoryavailable");//获得beanFactory类型转换类TypeConvertertypeConverter=beanFactory.getTypeConverter();Objectvalue;try{ //查找依赖关系value=beanFactory.resolveDependency(desc,beanName,autowiredBeanNames,typeConverter);}catch(BeansExceptionex){ thrownewUnsatisfiedDependencyException(null,beanName,newInjectionPoint(field),ex);}synchronized(this){ if(!this.cached){ ObjectcachedFieldValue=null;if(value!=null||this.required){ cachedFieldValue=desc;//填入依赖关系registerDependentBeans(beanName,autowiredBeanNames);//判断如果注入依赖是只有一个if(autowiredBeanNames.size()==1){ StringautowiredBeanName=autowiredBeanNames.iterator().next();if(beanFactory.containsBean(autowiredBeanName)&&beanFactory.isTypeMatch(autowiredBeanName,field.getType())){ cachedFieldValue=newShortcutDependencyDescriptor(desc,autowiredBeanName,field.getType());}}}this.cachedFieldValue=cachedFieldValue;this.cached=true;}}returnvalue;}}/***方法上有注解构建的处理对象*/privateclassAutowiredMethodElementextendsInjectionMetadata.InjectedElement{ privatefinalbooleanrequired;privatevolatilebooleancached;@NullableprivatevolatileObject[]cachedMethodArguments;publicAutowiredMethodElement(Methodmethod,booleanrequired,@NullablePropertyDescriptorpd){ super(method,pd);this.required=required;}@Overrideprotectedvoidinject(Objectbean,@NullableStringbeanName,@NullablePropertyValuespvs)throwsThrowable{ //检查属性是不会在之前就已经注入过了。如果主如果则不进行二次覆盖if(checkPropertySkipping(pvs)){ return;}Methodmethod=(Method)this.member;Object[]arguments;if(this.cached){ try{ arguments=resolveCachedArguments(beanName);}catch(NoSuchBeanDefinitionExceptionex){ //Unexpectedremovaloftargetbeanforcachedargument->re-resolvearguments=resolveMethodArguments(method,bean,beanName);}}else{ //首次创建的时候进入该方法arguments=resolveMethodArguments(method,bean,beanName);}if(arguments!=null){ try{ //属性如果不为public的话,则设置为可访问ReflectionUtils.makeAccessible(method);//调用方法并传入参数method.invoke(bean,arguments);}catch(InvocationTargetExceptionex){ throwex.getTargetException();}}}@NullableprivateObject[]resolveCachedArguments(@NullableStringbeanName){ Object[]cachedMethodArguments=this.cachedMethodArguments;if(cachedMethodArguments==null){ returnnull;}Object[]arguments=newObject[cachedMethodArguments.length];for(inti=0;i<arguments.length;i++){ arguments[i]=resolvedCachedArgument(beanName,cachedMethodArguments[i]);}returnarguments;}@NullableprivateObject[]resolveMethodArguments(Methodmethod,Objectbean,@NullableStringbeanName){ //获取方法上有几个参数intargumentCount=method.getParameterCount();Object[]arguments=newObject[argumentCount];DependencyDescriptor[]descriptors=newDependencyDescriptor[argumentCount];Set<String>autowiredBeans=newLinkedHashSet<>(argumentCount);Assert.state(beanFactory!=null,"NoBeanFactoryavailable");TypeConvertertypeConverter=beanFactory.getTypeConverter();for(inti=0;i<arguments.length;i++){ //方法参数,从方法参数中取出i构造MethodParameter对象MethodParametermethodParam=newMethodParameter(method,i);DependencyDescriptorcurrDesc=newDependencyDescriptor(methodParam,this.required);currDesc.setContainingClass(bean.getClass());descriptors[i]=currDesc;try{ //获取方法中i参数的内容Objectarg=beanFactory.resolveDependency(currDesc,beanName,autowiredBeans,typeConverter);if(arg==null&fastjson 1.2.源码分析以及漏洞复现
反序列化,这个过程将字节序列恢复为Java对象。例如在使用Python做自动化测试时,火箭赌博源码通过字符串名字调用相同名字的方法。Fastjson的功能允许通过字符串引用如`@type":"com.sun.rowset.JdbcRowSetImpl`来执行内部方法。由此,我们能利用Fastjson提供的便利,通过调用对应的函数来验证漏洞。
在渗透测试中,漏洞的验证通常需要满足几个条件:判断指纹和指纹回显,Fastjson的特性使得这一步变得简单。然而,在利用过程中,要考虑到Fastjson本身的限制、JDK的限制以及可能的安全配置限制。因此,POC验证方案需考虑这些限制的版本和配置。
Fastjson通过JSON抽象类实现JSONAware接口,并提供两个常用方法:`toJSONString`用于对象转换为JsonString,`parseObject`用于将JSON字符串转换为对象。这次的漏洞主要与反序列化相关。
反序列化的执行发生在`DefaultJSONParser.java`类中。关键代码中,固定键`@type`对应反序列化类的全路径,其中`typeName`为传入类的全路径。在Fastjson 1.2.版本中,`loadClass`方法未进行任何过滤,允许传入任何JVM加载的类,并执行`setKey`方法,其中Key为可变参数。
要利用这个反序列化漏洞,需要满足以下条件:JVM加载的类、有非静态set方法和传入一个参数。使用RPC远程执行代码的铁岭软件源码思路实现POC,此处使用了`com.sun.rowset.JdbcRowSetImpl`实现。
JNDI全称为Java Naming and Directory Interface,主要提供应用程序资源命名与目录服务。其底层实现之一是RMI(Remote Method Invocation),用于Java环境的远程方法调用。在`com.sun.rowset.JdbcRowSetImpl`类中,关注点在于`getDataSourceName()`和`setAutoCommit()`方法。`getDataSourceName()`用于传值,`setAutoCommit()`用于确认调用set方法。
实现过程包括引用`com.sun.rowset.JdbcRowSetImpl`类、设置`dataSourceName`传值以及通过`autoCommit`属性触发执行方法。完成方法确认后,使用`marshalsec`项目启动RMI服务并加载远程类。
POC的实现步骤如下:首先确认目标是否使用Fastjson且存在漏洞;利用Fastjson的反序列化功能传输引用类和执行方法;使用`com.sun.rowset.JdbcRowSetImpl`执行验证POC的脚本,并观察回显结果;最后,完成漏洞利用。
具体操作包括搭建环境,如使用CentOS虚拟机作为RMI服务器和远程调用服务,KALI机器作为靶机和抓包测试。进行指纹确认、安装maven、构建RMI服务器和客户端、调用测试文件,并观察DNS日志以验证漏洞成功利用。通过DNS日志确认漏洞利用成功后,可以进一步尝试反弹shell,实现远程控制。
综上所述,Fastjson的反序列化漏洞是一个可以被利用的安全问题,通过合理的利用,可以实现远程代码执行。公式源码背景了解和研究这类漏洞有助于增强对Fastjson以及类似技术的防御能力。
shardingsphere源码阅读-兼容jdbc规范
JDBC规范提供一套标准,让不同数据库厂商遵循统一接口操作数据库,从而简化应用程序开发。shardingsphere兼容此规范,通过重写接口实现兼容。
基于JDBC规范,shardingsphere采用适配器模式重写DataSource、Connection、Statement、ResultSet等关键接口,构建了一套完整的实现方案。适配器模式确保了shardingsphere能够以与JDBC规范一致的方式操作数据库,同时支持分库分表功能。
shardingsphere中,JdbcObject接口代表JDBC规范中的核心接口,包括DataSource、Connection、Statement等。通过包装器接口Wrapper以及其子类WrapperAdapter,shardingsphere实现了适配器模式,重写了这些接口的方法,同时保留了与JDBC规范的兼容性。
AbstractUnsupportedOperationJdbcObject和AbstractJdbcObjectAdapter作为抽象类,分别用于实现部分和全部接口方法。ShardingIdbcObject继承自AbstractJdbcObjectAdapter,包括ShardingDataSource、ShardingConnection、ShardingStatement等对象,这些对象都采用适配器模式重写JDBC规范接口,确保与JDBC规范无缝衔接。oahrcrm系统源码
以ShardingDataSource为例,其构造过程通过ShardingDataSourceFactory创建ShardingDataSource对象,将数据源、分库分表规则和属性等信息整合,同时初始化运行时上下文和静态代码块加载路由、SQL重写、结果集引擎等组件。ShardingDataSource内部的WrapperAdapter类维护方法调用信息,通过recordMethodInvocation和replayMethodsInvocation方法记录和回放方法调用。
AbstractDataSourceAdapter作为数据源适配器的抽象类,封装公共属性和方法,减少重复代码。此类中的dataSourceMap和databaseType属性分别保存数据源信息和数据库类型,getRuntimeContext方法用于获取分库分表的运行时上下文。
综上所述,shardingsphere通过适配器模式重写JDBC规范接口,实现了与JDBC规范的兼容性。不论使用sharding-jdbc还是原生JDBC,操作数据库的方式和流程保持一致,只是在实现细节上支持了分库分表功能,为开发者提供了一种灵活且高效的数据库管理方案。
张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!
本文将简要介绍AOP(面向切面编程)的基础知识与使用方法,并深入剖析Spring AOP源码。首先,我们需要理解AOP的基本概念。
1. **基础知识
**1.1 **什么是AOP?
**AOP全称为Aspect Oriented Programming,即面向切面编程。AOP的思想中,周边功能(如性能统计、日志记录、事务管理等)被定义为切面,核心功能与切面功能独立开发,然后将两者“编织”在一起,这就是AOP的核心。
AOP能够将与业务无关、却为业务模块共同调用的逻辑封装,减少系统重复代码,降低模块间的耦合度,有利于系统的可扩展性和可维护性。
1.2 **AOP基础概念
**解释较为官方,以下用“方言”解释:AOP包括五种通知分类。
1.3 **AOP简单示例
**创建`Louzai`类,添加`LouzaiAspect`切面,并在`applicationContext.xml`中配置。程序入口处添加`"睡觉"`方法并添加前置和后置通知。接下来,我们将探讨Spring内部如何实现这一过程。
1.4 **Spring AOP工作流程
**为了便于理解后面的源码,我们将整体介绍源码执行流程。整个Spring AOP源码分为三块,结合示例进行讲解。
第一块是前置处理,创建`Louzai`Bean前,遍历所有切面信息并存储在缓存中。第二块是后置处理,创建`Louzai`Bean时,主要处理两件事。第三块是执行切面,通过“责任链+递归”执行切面。
2. **源码解读
**注意:Spring版本为5.2..RELEASE,否则代码可能不同!这里,我们将从原理部分开始,逐步深入源码。
2.1 **代码入口
**从`getBean()`函数开始,进入创建Bean的逻辑。
2.2 **前置处理
**主要任务是遍历切面信息并存储。
这是重点!请务必注意!获取切面信息流程结束,后续操作都从缓存`advisorsCache`获取。
2.2.1 **判断是否为切面
**执行逻辑为:判断是否包含切面信息。
2.2.2 **获取切面列表
**进入`getAdvice()`,生成切面信息。
2.3 **后置处理
**主要从缓存拿切面,与`Louzai`方法匹配,创建AOP代理对象。
进入`doCreateBean()`,执行后续逻辑。
2.3.1 **获取切面
**首先,查看如何获取`Louzai`的切面列表。
进入`buildAspectJAdvisors()`,方法用于存储切面信息至缓存`advisorsCache`。随后回到`findEligibleAdvisors()`,从缓存获取所有切面信息。
2.3.2 **创建代理对象
**有了`Louzai`的切面列表,开始创建AOP代理对象。
这是重点!请仔细阅读!这里有两种创建AOP代理对象方式,我们选择使用Cglib。
2.4 **切面执行
**通过“责任链+递归”执行切面与方法。
这部分逻辑非常复杂!接下来是“执行切面”最核心的逻辑,简述设计思路。
2.4.1 **第一次递归
**数组第一个对象执行`invoke()`,参数为`CglibMethodInvocation`。
执行完毕后,继续执行`CglibMethodInvocation`的`process()`。
2.4.2 **第二次递归
**数组第二个对象执行`invoke()`。
2.4.3 **第三次递归
**数组第三个对象执行`invoke()`。
执行完毕,退出递归,查看`invokeJoinpoint()`执行逻辑,即执行主方法。回到第三次递归入口,继续执行后续切面。
切面执行逻辑已演示,直接查看执行方法。
流程结束时,依次退出递归。
2.4.4 **设计思路
**这部分代码研究了大半天,因为这里不是纯粹的责任链模式。
纯粹的责任链模式中,对象内部有一个自身的`next`对象,执行当前对象方法后,启动`next`对象执行,直至最后一个`next`对象执行完毕,或中途因条件中断执行,责任链退出。
这里`CglibMethodInvocation`对象内部无`next`对象,通过`interceptorsAndDynamicMethodMatchers`数组控制执行顺序,依次执行数组中的对象,直至最后一个对象执行完毕,责任链退出。
这属于责任链,实现方式不同,后续会详细剖析。下面讨论类之间的关系。
主对象为`CglibMethodInvocation`,继承于`ReflectiveMethodInvocation`,`process()`的核心逻辑在`ReflectiveMethodInvocation`中。
`ReflectiveMethodInvocation`的`process()`控制整个责任链的执行。
`ReflectiveMethodInvocation`的`process()`方法中,包含一个长度为3的数组`interceptorsAndDynamicMethodMatchers`,存储了3个对象,分别为`ExposeInvocationInterceptor`、`MethodBeforeAdviceInterceptor`、`AfterReturningAdviceInterceptor`。
注意!这3个对象都继承了`MethodInterceptor`接口。
每次`invoke()`调用时,都会执行`CglibMethodInvocation`的`process()`。
是否有些困惑?别着急,我将再次帮你梳理。
对象与方法的关系:
可能有同学疑惑,`invoke()`的参数为`MethodInvocation`,没错!但`CglibMethodInvocation`也继承了`MethodInvocation`,可自行查看。
执行逻辑:
设计巧妙之处在于,纯粹的责任链模式中,`next`对象需要保证类型一致。但这里3个对象内部没有`next`成员,不能直接使用责任链模式。怎么办呢?就单独设计了`CglibMethodInvocation.process()`,通过无限递归`process()`实现责任链逻辑。
这就是我们为什么要研究源码,学习优秀的设计思路!
3. **总结
**本文首先介绍了AOP的基本概念与原理,通过示例展示了AOP的应用。之后深入剖析了Spring AOP源码,分为三部分。
本文是Spring源码解析的第三篇,感觉是难度较大的一篇。图解代码花费了6个小时,整个过程都沉浸在代码的解析中。
难度不在于抠图,而是“切面执行”的设计思路,即使流程能走通,将设计思想总结并清晰表达给读者,需要极大的耐心与理解能力。
今天的源码解析到此结束,有关Spring源码的学习,大家还想了解哪些内容,欢迎留言给楼仔。
2024-11-20 02:19
2024-11-20 02:03
2024-11-20 01:01
2024-11-20 00:59
2024-11-20 00:37