逐行閱讀Spring5.X源碼(一) BeanDefinition,起點(diǎn)

本篇博客你講學(xué)到:
1. 如何理解BeanDefinition
2. 準(zhǔn)備環(huán)境
3. BeanDefinition接口講解
4. BeanDefinition的類繼承關(guān)系
5. IOC的引出
6. BeanFactory工廠的引出
7. 后置處理器的引出
8. spring擴(kuò)展性初探

1、為什么從BeanDefinition講起?

? ? ? ?spring源碼太龐大了,精通spring源碼確實(shí)不容易,講懂更難。學(xué)習(xí)spring源碼是件浩大的工程。很多讀者從spring容器啟動(dòng)開始逐行debug源碼進(jìn)行分析,剛開始很容易理解,但是當(dāng)你逐層debug源碼深處時(shí),就會(huì)感慨“身在此山中,不識(shí)真面目”。筆者在剛開始的時(shí)候也經(jīng)歷過這種痛苦,精讀幾遍之后筆者覺著spring源碼不能從頭讀起,我們需要先搞懂spring中的基礎(chǔ)組件及組件之間的關(guān)系,這就好比組裝電腦,你得先了解CPU作用、內(nèi)存的作用、主板的作用、硬盤的作用,然后你才知道如何講他們組裝到一起,從頭閱讀源碼就跟你讓一個(gè)學(xué)金融專業(yè)的學(xué)生組裝電腦一樣,效果可想而知。

image

? ? ? ?如果我問你spring的作用?想必大部分程序員都會(huì)回答“管理對(duì)象,方便開發(fā)”。中國不缺程序員,缺的是有思想有深度的工程師,別人寫的叫程序,你寫的那叫BUG。不錯(cuò),java一切皆對(duì)象,spring封裝管理你所創(chuàng)建的對(duì)象,封裝后的對(duì)象叫bean,bean擴(kuò)展了你的對(duì)象,你所創(chuàng)建的對(duì)象的所有屬性和方法是bean中的一個(gè)子集。spring所有的功能都是圍繞這個(gè)bean展開的。這個(gè)bean在spring中具體的名字就是BeanDefinition。

怎么理解BeanDefinition?

? ? ? ?假如你編寫一個(gè)Person.java文件,編譯成Persion.class文件后,jvm會(huì)將這個(gè)class文件加載到虛擬機(jī)內(nèi)存(方法區(qū)),程序在當(dāng)遇到new關(guān)鍵字的時(shí)候根據(jù)class在堆內(nèi)生成對(duì)象。class文件已經(jīng)生成了,spring無法更改你的class,但還要擴(kuò)展你的class怎么辦?很簡單,spring定義一個(gè)BeanDefinition類進(jìn)一步封裝Person類, 最后注冊到spring容器中。 所以, Person只是BeanDefinition中的一個(gè)屬性,就這么簡單。BeanDefinition中還會(huì)封裝跟Person相關(guān)的其他屬性,比如bean的作用域,bean的注入模型,bean是否是懶加載等等信息。BeaDefiniton結(jié)構(gòu)類似于:

image

對(duì)象和bean的對(duì)比如下圖,編譯對(duì)應(yīng)封裝,加載對(duì)應(yīng)注冊。Person.class是JVM的class,而BeanDefinition就是Spring中的class。專業(yè)一點(diǎn)講,在JDK中使用java.lang.Class來描述類這個(gè)對(duì)象,Spring使用BeanDefinition來描述bean。

image

? ? ? ?如果你不了解對(duì)象這個(gè)概念,那你就寫不了java程序。同理,如果你不了解BeanDefinition你就讀不懂Spring源碼。這就是筆者為什么先講解BeanDefinition。很多讀者都下過決心精讀spring源碼,剛開始熱情高漲,讀著讀著就不耐煩了,什么亂七八糟的不讀了,感覺會(huì)用就行,你跟架構(gòu)師就這么越來越遠(yuǎn)了。我覺著是方法不對(duì)。那就跟隨筆者的腳步,逐行分析spring源碼,畢竟這是你邁向java架構(gòu)師必須逾越的鴻溝!
在開始之前說清楚,beanDefintion的比較枯燥和晦澀難懂,但是非常非常重要。如果你想精讀spring源碼,請你一定細(xì)讀三遍beanDefintion的知識(shí),他是spring framework當(dāng)中的基石,你避不開!

2、準(zhǔn)備環(huán)境

  • 開發(fā)工具
    IDEA + MAVEN + JDK1.8
  • 導(dǎo)入依賴
 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>
    </dependencies>
  • 配置類
//包掃描
@ComponentScan("com")
//@ImportResource("applicationContext.xml")//使用xml文件而非注解的方式進(jìn)行啟動(dòng)
public class Config {
}
  • xml配置文件applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
       >
    <!--注意上面的default-autowire="byType"  根據(jù)type進(jìn)行自動(dòng)注入-->
    <bean id="ab" abstract="true" ></bean>
    <bean id="xxx" class="com.InterService" parent="ab"></bean>
</beans>

xml方式啟動(dòng)屬實(shí)用的不多了已經(jīng),xml最大的作用就是依賴注入(以后再將,可忽略),筆者在后續(xù)講解中基本以注解方式進(jìn)行講解。

  • 業(yè)務(wù)類
@Component
@Description("業(yè)務(wù)類")
@Scope("singleton")
public class InterService {
    private String name;
    private int age;
}
  • 測試類
public class SpringTest {
    public static void main(String[] args) throws InterruptedException {
       //以下三行代碼完成了spring的啟動(dòng)
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        //加載或者刷新當(dāng)前的配置信息
        context.refresh();;
    }
}

以上代碼均放在com包下。

3、BeanDefinition講解

? ? ? ?spring啟動(dòng)會(huì)完成很多工作,不可能在專題第一篇就把整個(gè)啟動(dòng)流程講清楚,為了引出BeanDefinition,筆者講解三個(gè)過程:

  • 掃描
    ? ? ? ?spring首先根據(jù)Config 的注解@ComponentScan("com")掃描com包下符合規(guī)則的類,這里只有InterService類;
  • 解析
    ? ? ? ?解析InterService類,主要是拿到所有的注解@Component、@Description("業(yè)務(wù)類")、@Scope("singleton")
  • 封裝
    ? ? ? ?解析完的信息保存到哪里里去呢?就存在BeanDefinition中。不然存哪里?存InterService類中嗎?此時(shí)回過頭讀讀文章第一節(jié)“為什么從BeanDefinition講起”就知道BeanDefinition的重要性了吧。BeanDefinition就是對(duì)你的InterService進(jìn)行建模。

? ? ? ?其實(shí),BeanDefinition只是一個(gè)接口:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
     //InterService的scope值,單例
    String SCOPE_SINGLETON = "singleton";
    //InterService的scope值,非單例
    String SCOPE_PROTOTYPE = "prototype";
    //Bean角色:
    //用戶
    int ROLE_APPLICATION = 0;
   //某些復(fù)雜的配置
    int ROLE_SUPPORT = 1;
  //完全內(nèi)部使用
    int ROLE_INFRASTRUCTURE = 2;
    //返回此InterService的的父bean定義的名稱,如果有的話 <bean parent="">(xml配置文件中的bean配置)
    String getParentName();    
    void setParentName(String var1);
   
  //設(shè)置或獲取業(yè)務(wù)類全路徑名
    void setBeanClassName(String var1);
    String getBeanClassName();
    //InterService的scope值
    void setScope(String var1);
    String getScope();
   //InterService的懶加載設(shè)置及獲取
    void setLazyInit(boolean var1);
    boolean isLazyInit();
    //InterService的依賴對(duì)象 ,表示InterService實(shí)例創(chuàng)建前應(yīng)該先創(chuàng)建哪個(gè)對(duì)象
    void setDependsOn(String... var1);
    String[] getDependsOn();
    //是否為被自動(dòng)裝配
    void setAutowireCandidate(boolean var1);
    boolean isAutowireCandidate();
   //如果是被自動(dòng)裝配,是否為主候選bean
    void setPrimary(boolean var1);
    boolean isPrimary();
   //定義創(chuàng)建該Bean對(duì)象的工廠類 
    void setFactoryBeanName(String var1);
    String getFactoryBeanName();
  //定義創(chuàng)建該Bean對(duì)象的工廠方法 
    void setFactoryMethodName(String var1);
    String getFactoryMethodName();
  //返回此InterService的構(gòu)造函數(shù)參數(shù)值。
    ConstructorArgumentValues getConstructorArgumentValues();
  //獲取普通屬性集合
    MutablePropertyValues getPropertyValues();
 //是否為單例
    boolean isSingleton();
    //是否為原型
    boolean isPrototype();
    //是否為抽象類
    boolean isAbstract();
  //獲取這個(gè)bean的應(yīng)用
    int getRole();
   //返回對(duì)bean定義的可讀描述。
    String getDescription();
  //返回該bean定義來自的資源的描述(用于在出現(xiàn)錯(cuò)誤時(shí)顯示上下文)
    String getResourceDescription();
    BeanDefinition getOriginatingBeanDefinition();
}

? ? ? ?通過BeanDefinition接口可以對(duì)InterService的附加屬性進(jìn)行設(shè)置和獲取,雖然目前不能完全搞懂所有屬性及方法,但筆者仍然建議讀者把這個(gè)接口代碼都看一遍。在這里建議大家讀源碼一定要“慢下來”,一點(diǎn)一點(diǎn)的啃,切忌浮躁,這個(gè)痛苦的過程過去了你會(huì)有種高屋建瓴的感覺!那感覺,指點(diǎn)江山!
? ? ? ?光讀不行,還得寫代碼調(diào)試從而增加印象,比如上面BeanDefinition接口中的方法我想驗(yàn)證一下,很簡單,上代碼:

public class SpringTest {
    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        //加載或者刷新當(dāng)前的配置信息
        context.refresh();;
       //獲取InterService對(duì)應(yīng)的BeanDefinition ,默認(rèn)名稱為interService,關(guān)于名字的更改以后講。
        BeanDefinition interServiceBeanDefinition = context.getBeanDefinition("interService");

        System.out.println("——————InterService的附加屬性如下:");
        System.out.println("父類"+interServiceBeanDefinition.getParentName());
        System.out.println("描述"+interServiceBeanDefinition.getDescription());
        System.out.println("InterService在spring的名稱"+interServiceBeanDefinition.getBeanClassName());
        System.out.println("實(shí)例范圍"+interServiceBeanDefinition.getScope());
        System.out.println("是否是懶加載"+interServiceBeanDefinition.isLazyInit());
        System.out.println("是否是抽象類"+interServiceBeanDefinition.isAbstract());
        System.out.println("——————等等等等,讀者自行編寫");
    }
}

打印結(jié)果:


image.png

注意,這些屬性在xml配置文件中都能找到對(duì)應(yīng)匹配的標(biāo)簽,讀者可用xml配置文件自行進(jìn)行配置,只需要將Config配置類上的@ImportResource("applicationContext.xml")注解打開即可。

? ? ? ?既然BeanDefinition是個(gè)接口,那spring中肯定有他的實(shí)現(xiàn)類對(duì)不對(duì),好,是時(shí)候看一下BeanDefinition的類繼承圖了。在這里筆者跟大家說一個(gè)問題,筆者發(fā)現(xiàn)很多人讀源碼的時(shí)候拿來一個(gè)類就讀或者debug源碼跟讀,也不管這個(gè)類跟其他類的關(guān)系,讀完后感覺很混亂,甚至吐槽spring源碼寫的毫無章法,拜托,spring源碼是典型的面向接口編程,嚴(yán)格遵循開閉原則、依賴倒置原則和迪米特法則(軟件設(shè)計(jì)7大基本原則,大家自行百度啦),是spring源碼寫的差還是你的水平差?spring每一個(gè)模塊都有一個(gè)完整的類繼承關(guān)系圖,不然spring被業(yè)界稱贊的高擴(kuò)展性談何而來?所以我們必須將每個(gè)模塊的類繼承關(guān)系了然于胸。初學(xué),我們也不可能將繼承體系中的每個(gè)類都搞懂,把這個(gè)繼承圖下載下來存到桌面,在以后的源碼閱讀中這個(gè)繼承關(guān)系會(huì)被你一一攻破,學(xué)完你也就掌握了,而且不會(huì)忘,更能提高你的編程水平,讀完spring你會(huì)發(fā)現(xiàn)的編程風(fēng)格潛移默化的被spring影響了!對(duì)吧。

BeanDefinition的繼承關(guān)系:

image.png

? ? ? ?突然間好想放棄有沒有,像這種繼承圖,spring中太多了,我說了學(xué)習(xí)spring是項(xiàng)浩大的工程,現(xiàn)在放棄還來得及!說實(shí)話筆者文章寫到這里停了好久,不知道從哪下手講!

? ? ? ?以前利用spring開發(fā)大都通過xml方式進(jìn)行bean配置,其實(shí)spring框架開發(fā)之初并不想讓程序員通過xml方式進(jìn)行配置,而是通過代碼讓我們手動(dòng)將InterService封裝成對(duì)應(yīng)的BeanDefinition,看下面的代碼:

//首先,刪掉業(yè)務(wù)類InterService所有的注解,不讓他被掃描到(spring根據(jù)注解判斷是否將類進(jìn)行包裝)
public class InterService {
    private String name;
    private int age;
}
public class SpringTest {
    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName("com.InterService");
        beanDefinition.setScope("singleton");
        beanDefinition.setDescription("手動(dòng)注入");
        beanDefinition.setAbstract(false);
        //將beanDefinition注冊到spring容器中
        context.registerBeanDefinition("interService",beanDefinition);
        //加載或者刷新當(dāng)前的配置信息
        context.refresh();

        BeanDefinition interServiceBeanDefinition = context.getBeanDefinition("interService");
        System.out.println("——————InterService的附加屬性如下:");
        System.out.println("父類"+interServiceBeanDefinition.getParentName());
        System.out.println("描述"+interServiceBeanDefinition.getDescription());
        System.out.println("InterService在spring的名稱"+interServiceBeanDefinition.getBeanClassName());
        System.out.println("實(shí)例范圍"+interServiceBeanDefinition.getScope());
        System.out.println("是否是懶加載"+interServiceBeanDefinition.isLazyInit());
        System.out.println("是否是抽象類"+interServiceBeanDefinition.isAbstract());
        System.out.println("——————等等等等,讀者自行編寫");
        
    }
}

? ? ? ?其實(shí)筆者很喜歡這種代碼方式完成spring配置工作,這樣能讓我們更深入的了解和應(yīng)用spring,不過這種方式的缺點(diǎn)也很明顯-繁瑣易出錯(cuò),spring為了簡化我們的工作提供了xml配置方式,直到spring5.x注解方式的穩(wěn)定成熟,spring全家桶得到了飛速的發(fā)展。但通過這個(gè)例子讀者可以加深對(duì)BeanDefinition的理解。

IOC的引出

看上面這么一行代碼:

        context.registerBeanDefinition("interService",beanDefinition);

? ? ? ?這行代碼的意思是將我們手動(dòng)封裝的beanDefinition注冊到容器中,同時(shí)給這個(gè)beanDefinition起了個(gè)名字“interService”,spring內(nèi)部生成beanDefinitino時(shí)會(huì)默認(rèn)起一個(gè)名字,改名字的規(guī)則就是業(yè)務(wù)類名字首字母小寫。
? ? ? ?那生成的BeanDefinition保存在哪里呢?既然我們是通過上面的方法將BeanDefinition注冊到容器中,肯丟是在這個(gè)方法底層實(shí)現(xiàn)了保存,我們點(diǎn)進(jìn)去看:

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        // 將beanDefinition保存到spring容器中
        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

? ? ? ?繼續(xù)跟進(jìn)registerBeanDefinition方法,找到下面這行代碼:

                        .....以上代碼省略,以后詳解
            this.beanDefinitionMap.put(beanName, beanDefinition);

? ? ? ?顧名思義,beanDefinitionMap就是一個(gè)Map呀!具體是啥map,我們ctrl+鼠標(biāo)左鍵單擊找到beanDefinitionMap定義處:

/** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

? ? ? ?還需要我解釋這行代碼嗎?有人說需要,我不懂ConcurrentHashMap,好吧,這是java并發(fā)包java.util.concurrent下的集合類,它就是一個(gè)Map,但是支持多線程并發(fā)訪問,為啥使用ConcurrentHashMap而不是用HashMap,嗨,建議你好好補(bǔ)下java高并發(fā)知識(shí)(后續(xù)我會(huì)寫一個(gè)java高并發(fā)編程底層原理,讓你吊打面試官,歡迎大家關(guān)注)??傊@就是beanDefinition存儲(chǔ)的容器,這行代碼所在的類名叫DefaultListableBeanFactory,它是bean的工廠,spring中所有的對(duì)象或者說bean都存在這個(gè)bean工廠中,業(yè)界叫它IOC,很多書或者視頻都會(huì)講IOC,相信讀者也知道IOC是容器,但它就是一堆Map集合而已,beanDefinitionMap 知識(shí)眾多Map中的一個(gè)而已,以后我會(huì)將其他的map容器,今天你只需要只到這么一個(gè)存放BeanDefinition的容器即可。
? ? ? ? 這下你搞懂IOC了吧! 全體起立!
? ? ? ?有讀者問,那DefaultListableBeanFactory這個(gè)bean工廠啥時(shí)候創(chuàng)建的,我說以后再講!想必大家都想知道,那就了解一下吧!看代碼:

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

? ? ? ?這是我們創(chuàng)建spring上下文對(duì)象,AnnotationConfigApplicationContext 類有一個(gè)父類,AnnotationConfigApplicationContext的無參 構(gòu)造函數(shù)執(zhí)行時(shí)會(huì)默認(rèn)調(diào)用父類無參構(gòu)造函數(shù)(java基礎(chǔ)知識(shí)),AnnotationConfigApplicationContext 的父類如下:

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

? ? ? ?也就是GenericApplicationContext ,我們看一下他的構(gòu)造函數(shù):

public GenericApplicationContext() {
        //初始化一個(gè)BeanFactory
        this.beanFactory = new DefaultListableBeanFactory();
    }

? ? ? ?我不說話,靜靜的看著屏幕前的你思考的樣子! 也就是說,spring啟動(dòng)的時(shí)候就創(chuàng)建好了這個(gè)bean工廠!
? ? ? ?咦?不是要將BeanDefinitino的繼承關(guān)系碼?怎么跑偏了?這就是spring的特點(diǎn),太龐大了,沒有孤立的知識(shí)點(diǎn)!這也是很多讀者閱讀spring源碼時(shí)讀著讀著就蒙圈的原因。

后置處理器的引出

? ? ? ?上文我們通過手動(dòng)將InterService封裝成了一個(gè)BeanDefinition然后注冊(說好聽了叫注冊,起始就是map.put)到了容器中,我說了現(xiàn)在我們沒有這么用的了,都是spring自動(dòng)幫我們完成掃描注冊,在哪完成的掃描注冊?回到下面這幾行代碼:

 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        //加載或者刷新當(dāng)前的配置信息
        context.refresh();

? ? ? ? context.refresh()方法,完成了spring的啟動(dòng)、掃描、解析、實(shí)例化等一系列過程,這個(gè)方法完成的功能太多了,我們的掃描注冊也是在這里完成的,進(jìn)入到這個(gè)方法,找到這么一行代碼:

                  ...以上省略
      invokeBeanFactoryPostProcessors(beanFactory);
                  ...以下省略

? ? ? ?翻譯一下名字,執(zhí)行bean工廠的后置處理器,這行代碼完成了掃描與注冊,我不帶大家分析里面的代碼,你只需要知道他的作用就行,這行代碼執(zhí)行完成后,我們只是把業(yè)務(wù)類InterService封裝成了BeanDefinition而已,業(yè)務(wù)類InterService并沒有實(shí)例化,在業(yè)務(wù)類InterService實(shí)例化之前我們能不能從beanDefinition中將InterService偷梁換柱呢?或者說,我們能通過BeanDefinition來構(gòu)建bean,那我們能不能修改bean呢?那必須的!
? ? ? ?通過后置處理器完成,什么是后置處理器?可以把它理解成回調(diào),我掃描注冊成功后回調(diào)后置處理器!BeanDefinition講完后緊接著就講后置處理器。我們添加一個(gè)后置處理器:

/**
 * 掃描注冊成功完成后,spring自動(dòng)調(diào)用后置處理器MyBeanFactoryPostProcessor的postProcessBeanFactory方法
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
        //通過bean工廠拿到業(yè)務(wù)類InterService的beanDefinition
        GenericBeanDefinition beanDefinition =
                (GenericBeanDefinition) beanFactory.getBeanDefinition("interService");
        System.out.println("掃描注冊成功完成后,spring自動(dòng)調(diào)用次方法");
        System.out.println(beanDefinition.getDescription());
    }
}

spring掃描注冊完成后,會(huì)自動(dòng)調(diào)用MyBeanFactoryPostProcessor的postProcessBeanFactory方法,這個(gè)方法給你傳遞了一個(gè)ConfigurableListableBeanFactory類型的bean工廠,ConfigurableListableBeanFactory是一個(gè)接口,上文spring啟動(dòng)實(shí)例化的DefaultListableBeanFactory工廠是它的實(shí)現(xiàn)類。天啊,竟然把bean工廠給你了,相當(dāng)于敵人把軍火庫暴露在你面前,你豈不是想干嘛就干嘛!上述代碼我們通過bean工廠拿到了業(yè)務(wù)類InterService的beanDefinition,我都拿到你的beanDefinition了,那么我不但可以get到你的信息,我也可以set你的信息從而改變你的行為來影響你后續(xù)的實(shí)例化。我們來編寫另一個(gè)業(yè)務(wù)類:

public class User {
    private int age =31;
    private String name="myname";
}

spring啟動(dòng)時(shí)也會(huì)把這個(gè)業(yè)務(wù)類掃描,接下來,看好了,我在bean工廠中偷梁換柱,在beanDefinition中將你的InterService業(yè)務(wù)類替換掉:

/**
 * 掃描注冊成功完成后,spring自動(dòng)調(diào)用后置處理器MyBeanFactoryPostProcessor的postProcessBeanFactory方法
 */
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
        GenericBeanDefinition beanDefinition =
                (GenericBeanDefinition) beanFactory.getBeanDefinition("interService");
        System.out.println(beanDefinition.getBeanClassName());
        System.out.println("開始偷梁換柱");
        beanDefinition.setBeanClass(User.class);
    }
}

測試一下:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();
        System.out.println("更改后的業(yè)務(wù)類:"+context.getBeanDefinition("interService").getBeanClassName());
    }
}

打印結(jié)果:


image.png

? ? ? ?what the f...
? ? ? ?你以為,spring插件是怎么來的?你以為,為什么那么多框架都能集成到spring,就是利用spring的開放性這么擴(kuò)展出來的,上文給你展示的只是冰山一角角,你不懂spring源碼,你怎么擴(kuò)展?當(dāng)然,你會(huì)說我又不做框架開發(fā)插件開發(fā),恩,我對(duì)你的CRUD表示尊重。
? ? ? ?既然我們已經(jīng)偷梁換柱把InterService替換掉了,那么spring在后續(xù)實(shí)例化過程中就不會(huì)實(shí)例化InterService,看下面代碼:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();
        System.out.println("更改后的業(yè)務(wù)類:"+context.getBeanDefinition("interService").getBeanClassName());
        //我們嘗試獲取InterService實(shí)例
        context.getBean(InterService.class);
    }
}

打印結(jié)果報(bào)錯(cuò),因?yàn)镮nterService不存在spring當(dāng)中了:


image.png

? ? ? ?繼續(xù),看后置處理器中的這行代碼:

GenericBeanDefinition beanDefinition =
                (GenericBeanDefinition) beanFactory.getBeanDefinition("interService");

? ? ? ?getBeanDefinition方法返回的BeanDefinition類型,為什么強(qiáng)轉(zhuǎn)成GenericBeanDefinition,起始BeanDefinition接口中并沒有setBeanClass這個(gè)方法,GenericBeanDefinition是他的實(shí)現(xiàn),提供更豐富的功能。不同的BeanDefinition實(shí)現(xiàn)具有不同的作用。
? ? ? ?下一篇我們詳細(xì)講一下不同BeanDefinition的作用,BeanDefinition學(xué)精通后你基本邁入了spring源碼大門。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容