Spring 原始碼梳理(七) 註解原始碼
註解原始碼
1.Spring的註解可以分為兩類,一個是類上的註解,如@Component; 一個是類內部的註解,如@Autowired;Spring對兩種形式的註解的處理是不同的,在Spring的初始化週期中註解生效的時間也不同。
2.使用例項來分析一下(至於專案搭建的步驟見系列第一部分,原始碼梳理(一))
App.java
package com.mycompany.app; import org.springframework.stereotype.Component; /** * Hello world! * */ @Component public class App { public String appString = "This is App"; }
God.java
package com.mycompany.app; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; @Component public class God { @Autowired public App app; public void godSay(){ System.out.println("God.godSay():"+app.appString); } @SuppressWarnings("resource") public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml"); God god = (God)applicationContext.getBean("god"); god.godSay(); } }
SpringBean.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <context:component-scan base-package="com.mycompany.app" /> </beans>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>myapp</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>myapp</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.0.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
執行God.java,得到的結果是:
3.首先可以做以下猜想
1)對於上面的兩種註解,Spring讀取相關的位元組碼檔案,然後找到相關的關鍵字;針對關鍵字做處理。
2)對於類註解,直接註冊類資訊,放入DefinitionMap;對於類內部的註解,如何把資訊注入進去的?有兩種猜測
A:之前的原始碼分析中提到了,BeanFactoryPostProcessor,它也被稱作容器的後置處理器,因為它是在Spring容器載入完所有的Bean資訊之後(是載入Bean,不是初始化)呼叫的處理器。 所以猜測註解可能是由BeanFactoryPostProcessor來實現的。
B:之前的原始碼分析中也提到了BeanPostProcessor,它包括了兩個方法:postProcessBeforeInitialization和postProcessAfterInitialization;它們分別被稱為Bean的前置和後置處理器;因為它們分別在Bean的初始化前後呼叫。所以猜測註解也可能是這兩個方法來實現的。
4.除錯,對程式碼進行分析
1)首先通過載入配置檔案然後解析相關類的過程是在BeanFacroty的初始化過程中;所以我們分析的是obtainFreshBeanFactory方法:
一直debug到前面文章講到過的parseBeanDefinitions方法:
我們的context節點屬於一般性的配置節點,進入parseCustomElement方法:
然後進入parse方法:
它有多個實現類,我們的配置檔案中的一個配置是<context: componentScan/>,所以我們進入ComponentScanBeanDefinitionParser方法:
basePackage指的是我們要掃描package,basepackages指的是package下面的java類; doScan方法對其中每一個java類進行掃描(包括類上的和類內部的註解),進入doScan方法:
2)然後順著findCandidateComponents方法
3)通過一點點分析postProcessBeanDefinition方法,發現實際上它是在beanDefinition中設定相關的屬性, 通過設定自動注入的屬性(從而在註冊bean處理器時發現它,使它繼承AutowiredAnnotationBeanPostProcessor介面),然後在初始化時,在Bean的後置處理方法中開始注入。這就說明猜想2中的B是正確的,而且注入實際上是bean後置處理器實現的,既postProcessAfterInitialization。
至於processCommonDefinitionAnnotations方法,就是對類上的bean進行處理, 然後設定beanDefinition中的屬性, 最後在初始化的時候對類進行初始化(沒有註冊BeanPostProcessor的過程),也證實猜想1是正確的。
總結如圖:
類內的註解經過了1,2,3三個方法,而類上的註解經過了1,3兩個方法。 分析到此,註解生效的整個生命週期就很清楚了。
相關推薦
Spring 原始碼梳理(七) 註解原始碼
註解原始碼 1.Spring的註解可以分為兩類,一個是類上的註解,如@Component; 一個是類內部的註解,如@Autowired;Spring對兩種形式的註解的處理是不同的,在Spring的初始化週期中註解生效的時間也不同。 2.使用例項來分析一下(至於專案搭建的步驟
白話Spring原始碼(七):FactoryBean
看清楚是FactoryBean,不是BeanFactory,雖然他們長得很像,但作用確實天差地別,BeanFactory是bean工廠,前面的部落格已經介紹過了,他們工廠類的基礎介面,而FactoryBean是一種bean,那為什麼要有這種bean呢,和一般的bean有什麼區別呢?下面跟大家分享一下
Spring事務原始碼梳理
通過註解@EnableTransactionManagement中的@Import(TransactionManagementConfigurationSelector.class)給容器中匯入了兩個元件,分別是:AutoProxyRegistrar和ProxyTransactionManagement
非同步任務spring @Async註解原始碼解析
1.引子 開啟非同步任務使用方法: 1).方法上加@Async註解 2).啟動類或者配置類上@EnableAsync 2.原始碼解析 雖然spring5已經出來了,但是我們還是使用的spring4,本文就根據spring-context-4.3.14.RELEASE.jar來分析原始碼。 2.1
Spring Core Container 原始碼分析七:註冊 Bean Definitions
前言 原本以為,Spring 通過解析 bean 的配置,生成並註冊 bean defintions 的過程不太複雜,比較簡單,不用單獨開闢一篇博文來講述;但是當在分析前面兩個章節有關 @Autowired、@Component、@Service 註解的注入機制的時候,發現,如果沒有對有關 bea
Spring提取@Transactional事務註解的原始碼解析
宣告:本編文章是自己在檢視Spring提取@Transactional註解的原始碼過程中隨手記下的筆記,只做了大概流程的記錄,未做詳細分析,如有錯誤還請諒解。 1、事務切面匹配處理類 AopUtils#canApply(Pointcut, Class ,
Spring Transaction 5.1.3 原始碼分析 : AnnotationTransactionAttributeSource 解析註解式事務屬性
概述 Spring支援使用註解指定服務方法的事務屬性。這些事務註解可以用在類上,也可以用在方法上,如下例子所示 。 Spring事務註解例子–應用在類級別 將事務註解標記到服務元件類級別,相當於為該服務元件的每個服務方法都應用了這個註解。 import org.sprin
spring註解原始碼分析-解析和注入註解配置的資源
類內部的註解,如@Autowire、@Value、@Required、@Resource以及EJB和WebService相關的註解,是容器對Bean例項化和依賴注入時,通過容器中註冊的Bean後置處理處理這些註解的。 當使用Spring的註解功能時, <cont
Spring原始碼研究之註解掃描
雖然在兩年前已跟隨《Spring原始碼深度解析》一書看過Spring原始碼的核心實現, 但就註解這塊的解析一直沒有時間瞭解. 導致每次碰到此類問題時心理沒有底氣. 這種感覺著實讓人不爽, 加之距離上次閱讀原始碼已過去比較長時間了, 所以也藉機再次領略下Sp
spring 註解原始碼分析-掃描和讀取bean定義
1.概述 從spring2.0以後的版本中,spring也引入了基於註解方式的配置,註解是jdk1.5中引入的一個新特性,用於簡化Bean的配置,某些場合可以取代xml配置檔案。 Spring IoC容器對於類級別的註解和類內部的註解分以下兩種策略: (1)類級別的註解
Spring boot非同步註解原始碼解析
一、例子 我們先來看下面這個Demo。 pom.xml中maven依賴: <parent> <gro
Spring 之 IoC 原始碼分析 (基於註解方式)
一、 IoC 理論 IoC 全稱為 Inversion of Control,翻譯為 “控制反轉”,它還有一個別名為 DI(Dep
Spring 原始碼(七)Spring 事務
註冊後置處理器開啟對事務的支援 @EnableTransactionManagement @EnableTransactionMa
【面試】足夠“忽悠”面試官的『Spring事務管理器』原始碼閱讀梳理(建議珍藏)
PS:文章內容涉及原始碼,請耐心閱讀。 理論實踐,相輔相成 偉大領袖毛主席告訴我們實踐出真知。這是無比正確的。但是也會很辛苦。就像淘金一樣,從大量沙子中淘出金子一定是一個無比艱辛的過程。但如果真能淘出來,也一定是像金子一樣寶貴的東西。他老人家還說過,當真知上升為理論的時候
Spring Boot中@ConfigurationProperties註解實現原理原始碼解析
0. 開源專案推薦 Pepper Metrics是我與同事開發的一個開源工具(https://github.com/zrbcool/pepper-metrics),其通過收集jedis/mybatis/httpservlet/dubbo/motan的執行效能統計,並暴露成prometheus等主流時序資料庫相
Spring Boot @Enable*註解原始碼解析及自定義@Enable*
Spring Boot 一個重要的特點就是自動配置,約定大於配置,幾乎所有元件使用其本身約定好的預設配置就可以使用,大大減輕配置的麻煩。其實現自動配置一個方式就是使用@Enable*註解,見其名知其意也,即“使什麼可用或開啟什麼的支援”。 ### Spring Boot 常用@Enable* 首先來簡
七 Spring的IOC的註解方式
jcu eem rdp pos hiberna app put yam 技術 Spring的IOC的註解方式入門 創建web項目,引入相應的jar包 除了IOC的6個包,還需要AOP的包 引入Spring配置文件 創建applicationContext.xml 引入約
Spring使用註解的方式實現AOP的開發——Spring AOP(七)
上一章我們已經學過使用XML的方式實現AOP: https://blog.csdn.net/qq_34598667/article/details/83502426 本章我們學習一下使用註解的方式實現AOP Spring使用註解的方式實現AOP的開發 本章所需知識點
spring事務管理實現原理-原始碼-傳播屬性-工作小結
本部落格分為兩點,一個是spring事務實現原理原始碼解讀(個人能力,初步解讀),二是spring事務的傳播屬性 簡單案例,儲存訂單,修改商品數量 就是這兩個方法,第一個方法中引用了第二個方法,都用@Transactional註解。debug呼叫shoppi
Zookeeper 原始碼(七)請求處理
Zookeeper 原始碼(七)請求處理 以單機啟動為例講解 Zookeeper 是如何處理請求的。先回顧一下單機時的請求處理鏈。 // 單機包含 3 個請求鏈:PrepRequestProcessor -> SyncRequestProcessor -> FinalRequestProces