<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)]一個(gè)Spring容器!

          共 10252字,需瀏覽 21分鐘

           ·

          2022-06-30 21:10

          大家好,我是魚(yú)皮~今天帶大家手?jǐn)]一個(gè)Spring容器,讓我們回歸Spring的本質(zhì),揭開(kāi)Spring神秘的面紗~

          從什么是IOC開(kāi)始?

          Spring——春天,Java編程世界的春天是由一位音樂(lè)家——Rod Johnson帶來(lái)的。

          Rod Johnson先后編寫(xiě)了兩本巨著《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兩大著作-來(lái)自百度百科

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

          Spring Logo

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

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

          引入IOC之前和引入IOC之后

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

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

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

          工廠(chǎng)和Spring容器

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

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

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

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

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

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

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

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

          mini版本Spring IOC

          訂單:Bean定義

          Bean可以通過(guò)一個(gè)配置文件定義,我們會(huì)把它解析成一個(gè)類(lèi)型。

          Bean定義
          • beans.properties

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

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

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

            public class BeanDefinition {

                private String beanName;

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

          獲取訂單:資源加載

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

          資源加載器,就是來(lái)完成這個(gè)工作的,由它來(lái)完成配置文件中配置的加載。

          public class ResourceLoader {

              public static Map<String, BeanDefinition> getResource() {
                  Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(16);
                  Properties properties = new Properties();
                  try {
                      InputStream inputStream = ResourceLoader.class.getResourceAsStream("/beans.properties");
                      properties.load(inputStream);
                      Iterator<String> 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注冊(cè)

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

          public class BeanRegister {

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

              /**
               * 獲取單例Bean
               *
               * @param beanName bean名稱(chēng)
               * @return
               */

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

              /**
               * 注冊(cè)單例bean
               *
               * @param beanName
               * @param bean
               */

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

          }

          生產(chǎn)車(chē)間:對(duì)象工廠(chǎng)

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

          BeanFactory
          • 對(duì)象工廠(chǎng),我們最核心的一個(gè)類(lèi),在它初始化的時(shí)候,創(chuàng)建了bean注冊(cè)器,完成了資源的加載。

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

            public class BeanFactory {

                private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

                private BeanRegister beanRegister;

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

                /**
                 * 獲取bean
                 *
                 * @param beanName bean名稱(chēng)
                 * @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)銷(xiāo)售:測(cè)試

          • UserDao.java

            我們的Bean類(lèi),很簡(jiǎn)單

            public class UserDao {

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

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

                    //2.第一次獲取bean(通過(guò)反射創(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.

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

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

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


          以上就是本期分享了。

          最后,歡迎加入 魚(yú)皮的編程知識(shí)星球(點(diǎn)擊了解詳情),和 8600 多名小伙伴們一起交流學(xué)習(xí),向魚(yú)皮和大廠(chǎng)同學(xué) 1 對(duì) 1 提問(wèn)、幫你制定學(xué)習(xí)計(jì)劃不迷茫、跟著魚(yú)皮直播做項(xiàng)目(往期項(xiàng)目可無(wú)限回看)領(lǐng)取魚(yú)皮原創(chuàng)編程學(xué)習(xí)/求職資料等。


          往期推薦

          編程導(dǎo)航,火了!

          錯(cuò)失字節(jié)跳動(dòng)數(shù)億身價(jià)!我有話(huà)說(shuō)

          沒(méi)有操作系統(tǒng),程序還能運(yùn)行嗎?

          全棧初中生,牛皮!

          這些JS題面試時(shí)一定要答對(duì)

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  人人摸人人草 | 亚洲成人网站免费 | 亚洲黄色在线网站 | a视频在线免费 | 五月婷婷激情综合 |