1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官:講講Spring IOC!

        共 21957字,需瀏覽 44分鐘

         ·

        2024-04-10 22:39

        來(lái)源:juejin.cn/post/7327447632111779891

        推薦:https://t.zsxq.com/17Qr4cXwo

        IOC(Inversion of Control),即控制反轉(zhuǎn),它是一種設(shè)計(jì)思想

        • 控制(誰(shuí)控制誰(shuí))

        之前通過(guò)new()進(jìn)行創(chuàng)建對(duì)象,主動(dòng)去創(chuàng)建依賴(lài)對(duì)象,而現(xiàn)在通過(guò)IOC容器負(fù)責(zé)實(shí)例化、配置和組裝 bean。

        ?

        在Spring IOC中,控制反轉(zhuǎn)指的是將對(duì)象的創(chuàng)建和管理交給Spring容器來(lái)完成,而不是由程序員手動(dòng)管理。因此,在Spring IOC中,Spring容器控制對(duì)象的創(chuàng)建和管理,而不是對(duì)象控制容器。因此,可以說(shuō)在Spring IOC中,Spring容器控制對(duì)象。

        • 反轉(zhuǎn)(反轉(zhuǎn)什么)

        之前對(duì)象主動(dòng)直接去獲取依賴(lài)對(duì)象,而現(xiàn)在通過(guò)Ioc容器查找及注入(DI) 依賴(lài)對(duì)象。

        ?

        在Spring IOC中,控制反轉(zhuǎn)(Inversion of Control,IoC)指的是將對(duì)象的創(chuàng)建和管理交給Spring容器來(lái)完成,而不是由應(yīng)用程序自己來(lái)創(chuàng)建和管理對(duì)象??刂品崔D(zhuǎn)反轉(zhuǎn)的是控制權(quán),即原本由應(yīng)用程序控制對(duì)象的創(chuàng)建和生命周期,變成了由Spring容器控制對(duì)象的創(chuàng)建和生命周期。這種反轉(zhuǎn)的控制權(quán)可以帶來(lái)更好的松耦合、更高的可維護(hù)性和可測(cè)試性。

        • 依賴(lài)注入

        DI(Dependency Injection),即依賴(lài)注入,是IOC具體的實(shí)現(xiàn),IOC容器動(dòng)態(tài)的將某個(gè)依賴(lài)注入到對(duì)象之中

        4bcee39d9af315a08cd9ceda4603131f.webp

        Spring Bean 在Spring中,Spring IoC 容器管理的對(duì)象稱(chēng)為 bean。

        Spring IOC

        Spring提供了兩種容器:BeanFactoryApplicationContext

        BeanFactory 接口提供配置框架和基本功能,能夠管理任何類(lèi)型的對(duì)象。

        ApplicationContextBeanFactory的子接口

        通過(guò)上圖我們可以看到ApplicationContext還繼承了其他接口,增加了消息資源處理(用于國(guó)際化)、事件發(fā)布、資源訪(fǎng)問(wèn)等功能。

        初始化流程

        通過(guò)前面的內(nèi)容,我們可以了解到Spring IOC 容器,主要負(fù)責(zé)管理 Bean 的實(shí)例化、配置和組裝,接下來(lái)我們看看Spring IOC的初始化過(guò)程(以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">


            <bean id="clientMessageReq" class="com.tx.general.rtnp.ws.req.ClientMessageReq" scope="prototype">
            </bean>
        </beans>
              
              public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("clientMessageReq.xml");
            ClientMessageReq clientMessageReq = context.getBean("clientMessageReq", ClientMessageReq.class);
            clientMessageReq.setParams("text");
            System.out.println(JSON.toJSONString(clientMessageReq));
        }

        通過(guò)new ClassPathXmlApplicationContext()方法創(chuàng)建了一個(gè)IOC容器,我們主要這個(gè)構(gòu)造方法開(kāi)始,分析一下IOC容器的初始化過(guò)程。

              
              /**
         * 構(gòu)造一個(gè)ClassPathXmlApplicationContext對(duì)象。
         *
         * @param configLocations 配置文件路徑數(shù)組
         * @param refresh 是否刷新上下文
         * @param parent 父上下文對(duì)象,可能為空
         * @throws BeansException 如果在創(chuàng)建對(duì)象時(shí)發(fā)生錯(cuò)誤,拋出BeansException異常
         */

        public ClassPathXmlApplicationContext(
          String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

          throws BeansException 
        {
                        
          // 設(shè)置Bean資源加載器
         super(parent);
                
          // 設(shè)置Xml配置路徑
         setConfigLocations(configLocations);
         if (refresh) {
          refresh();
         }
        }

        重點(diǎn)就是refresh()方法,它是IOC容器初始化的核心

              
              public void refresh() throws BeansException, IllegalStateException {
           synchronized (this.startupShutdownMonitor) {
              StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

              // ▲1.調(diào)用容器準(zhǔn)備刷新的方法,獲取容器的當(dāng)時(shí)時(shí)間,同時(shí)給容器設(shè)置同步標(biāo)識(shí) 
              prepareRefresh();

              // ▲2.初始化BeanFactory
              ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

              // ▲3.準(zhǔn)備Bean工廠(chǎng)以在上下文中使用
              prepareBeanFactory(beanFactory);

              try {
                 // ▲4.為子類(lèi)設(shè)置BeanFactory的后置處理器
                 postProcessBeanFactory(beanFactory);

                 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                 
                 // ▲5.調(diào)用實(shí)現(xiàn)了BeanFactoryPostProcessor的類(lèi)
                 invokeBeanFactoryPostProcessors(beanFactory);

                 // ▲6.注冊(cè)bean初始化時(shí)候的processor
                 registerBeanPostProcessors(beanFactory);
                 beanPostProcess.end();

                 // ▲7.對(duì)上下文的消息源進(jìn)行初始化
                 initMessageSource();

                 // ▲8.初始化上下文的事件機(jī)制
                 initApplicationEventMulticaster();

                 // ▲9.初始化其他特殊的Bean
                 onRefresh();

                 // ▲10.注冊(cè)實(shí)現(xiàn)了ApplicationListener的listener
                 registerListeners();

                 // ▲11.初始化配置為lazy-init=false的bean
                 finishBeanFactoryInitialization(beanFactory);

                 // ▲12.觸發(fā)所有監(jiān)聽(tīng)ContextRefreshedEvent事件的listener
                 finishRefresh();
              }

              catch (BeansException ex) {
                 if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                          "cancelling refresh attempt: " + ex);
                 }

                 destroyBeans();

                 cancelRefresh(ex);

                 throw ex;
              }

              finally {
                
                 resetCommonCaches();
                 contextRefresh.end();
              }
           }
        }

        可以看到容器的創(chuàng)建和初始化就在obtainFreshBeanFactory()方法,重點(diǎn)來(lái)看一下

        • obtainFreshBeanFactory()初始化BeanFactory
              
                 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
              refreshBeanFactory();
              return getBeanFactory();
           }

         /**
          * 刷新Bean工廠(chǎng) 委托模式
          */

         @Override
         protected final void refreshBeanFactory() throws BeansException {
                   
               // 如果已經(jīng)有容器存在,則需要把已有的容器銷(xiāo)毀和關(guān)閉,以保證在refresh之后使用的是新建立起來(lái)的IoC容器
             if (hasBeanFactory()) {
                 destroyBeans();
                 closeBeanFactory();
             }
             try {
                 // 創(chuàng)建DefaultListableBeanFactory對(duì)象
                 DefaultListableBeanFactory beanFactory = createBeanFactory();
                 // 設(shè)置序列化ID
                 beanFactory.setSerializationId(getId());
                 // 自定義Bean工廠(chǎng)
                 customizeBeanFactory(beanFactory);
                 // 加載定義的Bean
                 loadBeanDefinitions(beanFactory);
                 // 將beanFactory賦值給類(lèi)成員變量
                 this.beanFactory = beanFactory;
             }
             catch (IOException ex) {
                 // 解析bean定義源時(shí)發(fā)生I/O錯(cuò)誤拋出ApplicationContextException異常
                 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
             }
         }

        定位Resource(bean的Xml)

        • AbstractXmlApplicationContext#loadBeanDefinitions() 加載BeanDefinition
              
              protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

           // 創(chuàng)建XmlBeanDefinitionReader讀取器
           XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
           
           beanDefinitionReader.setEnvironment(this.getEnvironment());
           
           // 設(shè)置Spring資源加載器
           beanDefinitionReader.setResourceLoader(this);
           beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

           // 讀取器讀取Bean定義的Xml資源文件時(shí),啟用Xml的校驗(yàn)機(jī)制
           initBeanDefinitionReader(beanDefinitionReader);

           // 通過(guò)beanDefinitionReader加載BeanDefinitions 
           loadBeanDefinitions(beanDefinitionReader);
        }
        • AbstractXmlApplicationContext#loadBeanDefinitions() 定位資源,以Resource的形式去加載資源
              
              protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
            
            // 獲得Bean配置文件的資源位置
            Resource[] configResources = getConfigResources();    
            if (configResources != null) {
                // 讀取AbstractBeanDefinitionReader中定位的資源
                reader.loadBeanDefinitions(configResources);
            }
            // 獲取ClassPathXmlApplicationContext構(gòu)造方法中setConfigLocations方法設(shè)置的資源  
            String[] configLocations = getConfigLocations();    
            if (configLocations != null) {
                //通過(guò)AbstractBeanDefinitionReader#loadBeanDefinitions()方法,以Resource的形式去加載資源。
                reader.loadBeanDefinitions(configLocations);
            }
        }

        載入BeanDefinition

        經(jīng)過(guò)上面的步驟我們定義的資源以及容器本身需要的資源全部加載到reader中,通過(guò)XmlBeanDefinitionReader#loadBeanDefinitions()方法會(huì)得到一個(gè)XML文件的InputStream,然后 將Bean定義資源轉(zhuǎn)換成Document對(duì)象。最后在registerBeanDefinitions()方法中完成對(duì)解析

              
              public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
           // 創(chuàng)建DefaultBeanDefinitionDocumentReader對(duì)象
           BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
           int countBefore = getRegistry().getBeanDefinitionCount();
           // 通過(guò)DefaultBeanDefinitionDocumentReader對(duì)象的registerBeanDefinitions()方法解析Document
           documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
           return getRegistry().getBeanDefinitionCount() - countBefore;
        }

        而具體的解析過(guò)程由BeanDefinitionParserDelegate()來(lái)實(shí)現(xiàn)

              
              protected void doRegisterBeanDefinitions(Element root) {
            // ... 代碼部分省略
            
            // 執(zhí)行XML預(yù)處理操作
            preProcessXml(root);

            // 解析Bean定義
            parseBeanDefinitions(root, this.delegate);

            // 執(zhí)行XML后處理操作
            postProcessXml(root);
            
            // ... 代碼部分省略
        }

        通過(guò)BeanDefinitionParserDelegate#parseBeanDefinitionElement()方法,得到結(jié)果BeanDefinitionHolderBeanDefinitionHolder是BeanDefinition的封裝類(lèi),封裝了BeanDefinition,Bean的名字、別名)

              
              protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
           // 對(duì)給定的<bean>標(biāo)簽進(jìn)行解析,得到BeanDefinitionHolder對(duì)象
           BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
           if (bdHolder != null) {
              bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
              try {
                 // 向IOC容器注冊(cè)解析到BeanDefinition
                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
              }
              catch (BeanDefinitionStoreException ex) {
                 getReaderContext().error("Failed to register bean definition with name '" +
                       bdHolder.getBeanName() + "'", ele, ex);
              }
              
             // 在BeanDefinition像IOC容器注冊(cè)完以后,發(fā)送事件消息
              getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
           }
        }

        BeanDefiniton注冊(cè)

        最終Xml配置被解析成了BeanDefinitionHolder類(lèi),通過(guò)DefaultListableBeanFactory#registerBeanDefinition()方法,將BeanDefinition注冊(cè)到beanDefinitionsMap

              
              public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
              throws BeanDefinitionStoreException 
        {

           Assert.hasText(beanName, "Bean name must not be empty");
           Assert.notNull(beanDefinition, "BeanDefinition must not be null");

           if (beanDefinition instanceof AbstractBeanDefinition) {
              try {
                 ((AbstractBeanDefinition) beanDefinition).validate();
              }
              catch (BeanDefinitionValidationException ex) {
                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                       "Validation of bean definition failed", ex);
              }
           }

           BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
           if (existingDefinition != null) {
              if (!isAllowBeanDefinitionOverriding()) {
                 throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
              }
              else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                 if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                          "' with a framework-generated bean definition: replacing [" +
                          existingDefinition + "] with [" + beanDefinition + "]");
                 }
              }
              else if (!beanDefinition.equals(existingDefinition)) {
                 if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                          "' with a different definition: replacing [" + existingDefinition +
                          "] with [" + beanDefinition + "]");
                 }
              }
              else {
                 if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                          "' with an equivalent definition: replacing [" + existingDefinition +
                          "] with [" + beanDefinition + "]");
                 }
              }
              this.beanDefinitionMap.put(beanName, beanDefinition);
           }
           else {
              if (hasBeanCreationStarted()) {
                 // Cannot modify startup-time collection elements anymore (for stable iteration)
                 synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                 }
              }
              else {
                 // Still in startup registration phase
                 this.beanDefinitionMap.put(beanName, beanDefinition);
                 this.beanDefinitionNames.add(beanName);
                 removeManualSingletonName(beanName);
              }
              this.frozenBeanDefinitionNames = null;
           }

           if (existingDefinition != null || containsSingleton(beanName)) {
              resetBeanDefinition(beanName);
           }
           else if (isConfigurationFrozen()) {
              clearByTypeCache();
           }
        }

        至此,IOC容器完成了初始化,其內(nèi)部使用ConcurrentHashMap(Spring IOC容器本質(zhì))保存了BeanDefinition信息

        總結(jié)

        Spring IOC初始化可以分為三個(gè)步驟

        • 通過(guò) ResourceLoader 來(lái)完成資源文件位置的定位(Resource)
        • 將Resource定位好的資源載入到BeanDefinition(通過(guò) BeanDefinitionReader來(lái)完成定義信息的解析)
        • 將BeanDefiniton注冊(cè)到容器中(通過(guò)BeanDefinitionRegistry接口,將BeanDefinition保存到ConcurrentHashMap中)

        Spring IOC容器管理了定義的各種Bean對(duì)象及其相互的關(guān)系,降低了耦合度

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            中国黄片永久免费 | 黄网站免费入口 | 美女久久久久久 | 啊~喷水了~嗯~高潮了视频 | 韩国一区二区无码视频 | 国产精品久久久久久久久久懂色 | 奇米影视亚洲春色 | 无码中文视频 | 99re在线精品视频 | 三级黄色电视 |