<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          五分鐘,手?jǐn)]一個Spring容器!

          共 5373字,需瀏覽 11分鐘

           ·

          2022-05-25 08:14

          Spring是我們最常用的開源框架,經(jīng)過多年發(fā)展,Spring已經(jīng)發(fā)展成枝繁葉茂的大樹,讓我們難以窺其全貌。

          這節(jié),我們回歸Spring的本質(zhì),五分鐘手?jǐn)]一個Spring容器,揭開Spring神秘的面紗!

          從什么是IOC開始?

          Spring——春天,Java編程世界的春天是由一位音樂家——Rod Johnson帶來的。

          Rod Johnson先后編寫了兩本巨著《Expert One-on-One J2EE Design and Development》、《Expert One-on-One J2EE Development without EJB》,拉起了挑戰(zhàn)正統(tǒng)Java EE框架EJB的大旗。

          Rod Johnson兩大著作-來自百度百科

          Rod Johnson不僅是一名旗手,更是開發(fā)了Spring這一輕量級框架,像一名勇敢的龍騎兵一樣,對EJB發(fā)動了沖鋒,并最終戰(zhàn)勝了EJB,讓Spring成為Java EE事實(shí)上的標(biāo)準(zhǔn)。

          Spring Logo

          Spring的兩大內(nèi)核分別是IOC和AOP,其中最最核心的是IOC。

          所謂的IOC(控制反轉(zhuǎn)):就是由容器來負(fù)責(zé)控制對象的生命周期和對象間的關(guān)系。以前是我們想要什么,就自己創(chuàng)建什么,現(xiàn)在是我們需要什么,容器就給我們送來什么。

          引入IOC之前和引入IOC之后

          也就是說,控制對象生命周期的不再是引用它的對象,而是容器。對具體對象,以前是它控制其它對象,現(xiàn)在所有對象都被容器控制,所以這就叫控制反轉(zhuǎn)

          控制反轉(zhuǎn)示意圖

          也許你還聽到另外一個概念DI(依賴注入),它指的是容器在實(shí)例化對象的時候把它依賴的類注入給它,我們也可以認(rèn)為,DI是IOC的補(bǔ)充和實(shí)現(xiàn)。

          工廠和Spring容器

          Spring是一個成熟的框架,為了滿足擴(kuò)展性、實(shí)現(xiàn)各種功能,所以它的實(shí)現(xiàn)如同枝節(jié)交錯的大樹一樣,現(xiàn)在讓我們把視線從Spring本身移開,來看看一個萌芽版的Spring容器怎么實(shí)現(xiàn)。

          Spring的IOC本質(zhì)就是一個大工廠,我們想想一個工廠是怎么運(yùn)行的呢?

          工廠運(yùn)行
          • 生產(chǎn)產(chǎn)品:一個工廠最核心的功能就是生產(chǎn)產(chǎn)品。在Spring里,不用Bean自己來實(shí)例化,而是交給Spring,應(yīng)該怎么實(shí)現(xiàn)呢?——答案毫無疑問,反射

            那么這個廠子的生產(chǎn)管理是怎么做的?你應(yīng)該也知道——工廠模式

          • 庫存產(chǎn)品:工廠一般都是有庫房的,用來庫存產(chǎn)品,畢竟生產(chǎn)的產(chǎn)品不能立馬就拉走。Spring我們都知道是一個容器,這個容器里存的就是對象,不能每次來取對象,都得現(xiàn)場來反射創(chuàng)建對象,得把創(chuàng)建出的對象存起來。

          • 訂單處理:還有最重要的一點(diǎn),工廠根據(jù)什么來提供產(chǎn)品呢?訂單。這些訂單可能五花八門,有線上簽簽的、有到工廠簽的、還有工廠銷售上門簽的……最后經(jīng)過處理,指導(dǎo)工廠的出貨。

            在Spring里,也有這樣的訂單,它就是我們bean的定義和依賴關(guān)系,可以是xml形式,也可以是我們最熟悉的注解形式。

          那對應(yīng)我們的萌芽版的Spring容器是什么樣的呢?

          mini版本Spring IOC

          訂單:Bean定義

          Bean可以通過一個配置文件定義,我們會把它解析成一個類型。

          Bean定義
          • beans.properties

            為了偷懶,這里直接用了最方便解析的properties,用一個類型的配置來代表Bean的定義,其中key是beanName,value是class

            userDao:cn.fighter3.bean.UserDao
          • BeanDefinition.java

            bean定義類,配置文件中bean定義對應(yīng)的實(shí)體

            public?class?BeanDefinition?{

            ????private?String?beanName;

            ????private?Class?beanClass;
            ?????//省略getter、setter??
            ?}???

          獲取訂單:資源加載

          接下訂單之后,就要由銷售向生產(chǎn)部門交接,讓生產(chǎn)部門知道商品的規(guī)格、數(shù)量之類。

          資源加載器,就是來完成這個工作的,由它來完成配置文件中配置的加載。

          public?class?ResourceLoader?{

          ????public?static?Map?getResource()?{
          ????????Map?beanDefinitionMap?=?new?HashMap<>(16);
          ????????Properties?properties?=?new?Properties();
          ????????try?{
          ????????????InputStream?inputStream?=?ResourceLoader.class.getResourceAsStream("/beans.properties");
          ????????????properties.load(inputStream);
          ????????????Iterator?it?=?properties.stringPropertyNames().iterator();
          ????????????while?(it.hasNext())?{
          ????????????????String?key?=?it.next();
          ????????????????String?className?=?properties.getProperty(key);
          ????????????????BeanDefinition?beanDefinition?=?new?BeanDefinition();
          ????????????????beanDefinition.setBeanName(key);
          ????????????????Class?clazz?=?Class.forName(className);
          ????????????????beanDefinition.setBeanClass(clazz);
          ????????????????beanDefinitionMap.put(key,?beanDefinition);
          ????????????}
          ????????????inputStream.close();
          ????????}?catch?(IOException?|?ClassNotFoundException?e)?{
          ????????????e.printStackTrace();
          ????????}
          ????????return?beanDefinitionMap;
          ????}

          }

          訂單分配:Bean注冊

          對象注冊器,這里用于單例bean的緩存,我們大幅簡化,默認(rèn)所有bean都是單例的。可以看到所謂單例注冊,也很簡單,不過是往HashMap里存對象。

          public?class?BeanRegister?{

          ????//單例Bean緩存
          ????private?Map?singletonMap?=?new?HashMap<>(32);

          ????/**
          ?????*?獲取單例Bean
          ?????*
          ?????*?@param?beanName?bean名稱
          ?????*?@return
          ?????*/

          ????public?Object?getSingletonBean(String?beanName)?{
          ????????return?singletonMap.get(beanName);
          ????}

          ????/**
          ?????*?注冊單例bean
          ?????*
          ?????*?@param?beanName
          ?????*?@param?bean
          ?????*/

          ????public?void?registerSingletonBean(String?beanName,?Object?bean)?{
          ????????if?(singletonMap.containsKey(beanName))?{
          ????????????return;
          ????????}
          ????????singletonMap.put(beanName,?bean);
          ????}

          }

          生產(chǎn)車間:對象工廠

          好了,到了我們最關(guān)鍵的生產(chǎn)部門了,在工廠里,生產(chǎn)產(chǎn)品的是車間,在IOC容器里,生產(chǎn)對象的是BeanFactory。

          BeanFactory
          • 對象工廠,我們最核心的一個類,在它初始化的時候,創(chuàng)建了bean注冊器,完成了資源的加載。

          • 獲取bean的時候,先從單例緩存中取,如果沒有取到,就創(chuàng)建并注冊一個bean

            public?class?BeanFactory?{

            ????private?Map?beanDefinitionMap?=?new?HashMap<>();

            ????private?BeanRegister?beanRegister;

            ????public?BeanFactory()?{
            ????????//創(chuàng)建bean注冊器
            ????????beanRegister?=?new?BeanRegister();
            ????????//加載資源
            ????????this.beanDefinitionMap?=?new?ResourceLoader().getResource();
            ????}

            ????/**
            ?????*?獲取bean
            ?????*
            ?????*?@param?beanName?bean名稱
            ?????*?@return
            ?????*/

            ????public?Object?getBean(String?beanName)?{
            ????????//從bean緩存中取
            ????????Object?bean?=?beanRegister.getSingletonBean(beanName);
            ????????if?(bean?!=?null)?{
            ????????????return?bean;
            ????????}
            ????????//根據(jù)bean定義,創(chuàng)建bean
            ????????return?createBean(beanDefinitionMap.get(beanName));
            ????}

            ????/**
            ?????*?創(chuàng)建Bean
            ?????*
            ?????*?@param?beanDefinition?bean定義
            ?????*?@return
            ?????*/

            ????private?Object?createBean(BeanDefinition?beanDefinition)?{
            ????????try?{
            ????????????Object?bean?=?beanDefinition.getBeanClass().newInstance();
            ????????????//緩存bean
            ????????????beanRegister.registerSingletonBean(beanDefinition.getBeanName(),?bean);
            ????????????return?bean;
            ????????}?catch?(InstantiationException?|?IllegalAccessException?e)?{
            ????????????e.printStackTrace();
            ????????}
            ????????return?null;
            ????}
            }

          生產(chǎn)銷售:測試

          • UserDao.java

            我們的Bean類,很簡單

            public?class?UserDao?{

            ????public?void?queryUserInfo(){
            ????????System.out.println("A?good?man.");
            ????}
            }
          • 單元測試

            public?class?ApiTest?{
            ????@Test
            ????public?void?test_BeanFactory()?{
            ????????//1.創(chuàng)建bean工廠(同時完成了加載資源、創(chuàng)建注冊單例bean注冊器的操作)
            ????????BeanFactory?beanFactory?=?new?BeanFactory();

            ????????//2.第一次獲取bean(通過反射創(chuàng)建bean,緩存bean)
            ????????UserDao?userDao1?=?(UserDao)?beanFactory.getBean("userDao");
            ????????userDao1.queryUserInfo();

            ????????//3.第二次獲取bean(從緩存中獲取bean)
            ????????UserDao?userDao2?=?(UserDao)?beanFactory.getBean("userDao");
            ????????userDao2.queryUserInfo();
            ????}
            }
          • 運(yùn)行結(jié)果

            A?good?man.
            A?good?man.

          至此,我們一個萌芽版的Spring容器就完成了。

          考慮一下,它有哪些不足呢?是否還可以抽象、擴(kuò)展、解耦……

          細(xì)細(xì)想想這些東西,你是不是對真正的Spring IOC容器為何如此復(fù)雜,有所理解了呢?




          參考:

          • [1]. 《Spring揭秘》

          • [2].小傅哥 《手?jǐn)]Spring》

          • [3].《精通Spring4.X企業(yè)應(yīng)用開發(fā)實(shí)戰(zhàn)》


          往期推薦

          Spring 奪命 35 問!


          Spring Boot 優(yōu)雅配置多數(shù)據(jù)源


          IDEA 版 Postman 面世了,功能真心強(qiáng)大!


          瀏覽 32
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  音彰先锋成人无码视频 | 小骚逼无码内射 | 日本欧洲久久精品视频 | 一级特黄性生活视频在线播放 | 韩国一区二区无码视频 |