摘要:生成的兩種方式通過反射調用構造函數通過優點依賴關系的管理被反轉并交給容器,使復雜的依賴關系管理從應用中解放出來。
IOC概述
1、理解:
(1)控制反轉。將生成對象的控制權交IOC容器,由容器生成依賴的對象。調用類只依賴接口,而不依賴具體的實現類,減少了耦合。在運行的時候,才由容器將具體的實例注入到調用類的對象中。
(2)依賴注入,就是向Ioc容器索要bean的過程。getBean是依賴注入的起點。依賴注入的過程是用戶第一次向Ioc容器索要Bean時觸發的。
(3)生成bean的兩種方式
a、通過反射調用構造函數 b、通過CGLib
2、優點:
(1)依賴關系的管理被反轉并交給容器,使復雜的依賴關系管理從應用中解放出來。
(2)代碼解耦
3、啟動過程(依賴注入的實現過程):
a、Resource尋找資源(XML文件形式的beanDefinition) b、將XML文件載入內存中,解析成org.springframework.beans.factory.config.BeanDefinition對象 c、將org.springframework.beans.factory.config.BeanDefinition對象注冊到HashMap容器中 d、客戶想Ioc容器索要bean,觸發依賴注入基礎使用
一、首先講解依賴注入的3種方式:
1、set方式注入:
假設有一個SpringAction,類中需要實例化一個SpringDao對象,那么就可以定義一個private的SpringDao成員變量,然后創建SpringDao的set方法(這是ioc的注入入口):
package com.bless.springdemo.action; public class SpringAction { //注入對象springDao private SpringDao springDao; //一定要寫被注入對象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void ok(){ springDao.ok(); } }
隨后編寫spring的xml文件,
2、構造器注入:
這種方式的注入是指帶有參數的構造函數注入,看下面的例子,我創建了兩個成員變量SpringDao和User,但是并未設置對象的set方法,所以就不能支持Set注入方式,這里的注入方式是在SpringAction的構造函數中注入,也就是說在創建SpringAction對象時要將SpringDao和User兩個參數值傳進來:
public class SpringAction { //注入對象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("構造方法調用springDao和user"); } public void save(){ user.setName("卡卡"); springDao.save(user); } }
在XML文件中同樣不用
解決構造方法參數的不確定性,你可能會遇到構造方法傳入的兩參數都是同類型的,為了分清哪個該賦對應值,則需要進行一些小處理:
下面是設置index,就是參數位置:
另一種是設置參數類型:
3、接口注入:
ClassA依賴于InterfaceB,在運行期, InterfaceB 實例將由容器提供。
public class ClassA { private InterfaceB clzB; public Object doSomething(InterfaceB b) { clzB = b; return clzB.doIt(); } } …… }
二、Bean標簽
1、scope屬性:
(1)singleton:單例模式,即該bean對應的類只有一個實例;在spring 中是scope(作用范圍)參數的默認值 ;
(2)prototype:表示每次從容器中取出bean時,都會生成一個新實例;相當于new出來一個對象;
(3)request:基于web,表示每次接受一個HTTP請求時,都會生成一個新實例;
(4)session:表示在每一個session中只有一個該對象.
(5)global session
global session作用域類似于標準的HTTP Session作用域,不過它僅僅在基于portlet的web應用中才有意義。Portlet規范定義了全局Session的概念,它被所有構成某個portlet web應用的各種不同的portlet所共享。在global session作用域中定義的bean被限定于全局portlet Session的生命周期范圍內。如果你在web中使用global session作用域來標識bean,那么web會自動當成session類型來使用。
配置實例:
和request配置實例的前提一樣,配置好web啟動文件就可以如下配置:
(6)自定義bean裝配作用域:
在spring2.0中作用域是可以任意擴展的,你可以自定義作用域,甚至你也可以重新定義已有的作用域(但是你不能覆蓋singleton和prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope來定義,自定義自己的作用域只要實現該接口即可,下面給個實例:
我們建立一個線程的scope,該scope在表示一個線程中有效,代碼如下:
publicclass MyScope implements Scope { privatefinal ThreadLocal threadScope = new ThreadLocal() { protected Object initialValue() { returnnew HashMap(); } }; public Object get(String name, ObjectFactory objectFactory) { Map scope = (Map) threadScope.get(); Object object = scope.get(name); if(object==null) { object = objectFactory.getObject(); scope.put(name, object); } return object; } public Object remove(String name) { Map scope = (Map) threadScope.get(); return scope.remove(name); } publicvoid registerDestructionCallback(String name, Runnable callback) { } public String getConversationId() { // TODO Auto-generated method stub returnnull; } }源碼解析
一、IOC容器:
1、對于Spring的使用者而言,IOC容器實際上是什么呢?我們可以說BeanFactory就是我們看到的IoC容器,當然了Spring為我們準備了許多種IoC容器來使用,比如說ApplicationContext。這樣可以方便我們從不同的層面,不同的資源位置,不同的形式的定義信息來建立我們需要的IoC容器。
在Spring中,最基本的IOC容器接口是BeanFactory - 這個接口為具體的IOC容器的實現作了最基本的功能規定 - 不管怎么著,作為IOC容器,這些接口你必須要滿足應用程序的最基本要求,查看BeanFactory的源碼:
public interface BeanFactory { //這里是對FactoryBean的轉義定義,因為如果使用bean的名字檢索FactoryBean得到的對象是工廠生成的對象, //如果需要得到工廠本身,需要轉義 String FACTORY_BEAN_PREFIX = "&"; //這里根據bean的名字,在IOC容器中得到bean實例,這個IOC容器就是一個大的抽象工廠。 Object getBean(String name) throws BeansException; //這里根據bean的名字和Class類型來得到bean實例,和上面的方法不同在于它會拋出異常:如果根據名字取得的bean實例的Class類型和需要的不同的話。 Object getBean(String name, Class requiredType) throws BeansException; //這里提供對bean的檢索,看看是否在IOC容器有這個名字的bean boolean containsBean(String name); //這里根據bean名字得到bean實例,并同時判斷這個bean是不是單件 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; //這里對得到bean實例的Class類型 Class getType(String name) throws NoSuchBeanDefinitionException; //這里得到bean的別名,如果根據別名檢索,那么其原名也會被檢索出來 String[] getAliases(String name); }
2、容器加載流程解析:
這里我們以ClassPathXmlApplicationContext的初始化為例
(1)首先從容器構造函數入口:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { //這里是IoC容器的初始化過程,其初始化過程的大致步驟由AbstractApplicationContext來定義 refresh(); } }
(2)再看AbstractApplicationContext中refresh函數定義,這個方法包含了整個BeanFactory初始化的過程。這里使用到模板模式。
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 準備這個上下文來刷新 prepareRefresh(); // 告訴子類刷新其beanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 準備將要在上下文中使用的bean工廠 prepareBeanFactory(beanFactory); try { // 允許在上下文子類中對bean工廠進行后處理 postProcessBeanFactory(beanFactory); // 調用 factory processors注冊為上下文中的bean invokeBeanFactoryPostProcessors(beanFactory); // 注冊 攔截bean創建的bean處理器 registerBeanPostProcessors(beanFactory); // 初始化此上下文的消息源 initMessageSource(); // 初始化此上下文的時間多播器 initApplicationEventMulticaster(); // 在特殊上下文子類中初始化其特殊的bean onRefresh(); // 檢查監聽器bean,并且注冊它們 registerListeners(); // 初始化所有剩下的(非懶加載)單例 finishBeanFactoryInitialization(beanFactory); // 發布相應的事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // 銷毀已經創建的單例,以避免資源泄漏 destroyBeans(); // 重置active標志位 cancelRefresh(ex); // 拋出異常給調用者 throw ex; } finally { // 在Spring的核心中重置常見的自檢緩存,因為我們可能不再需要單例對象的元數據了 resetCommonCaches(); } } }
(4)進入obtainFreshBeanFactory()函數,發現調用refreshBeanFactory(),而refreshBeanFactory()里面調用了loadBeanDefinitions()函數,該函數描述了加載bean定義的過程,最終會調用”具體的解析和注冊過程“。
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 為給定的BeanFactory創建一個新的XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 使用此上下文的資源加載環境,去配置bean定義閱讀器。 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 允許子類提供reader的自定義初始化,然后執行實際加載bean定義。 initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { // 調用XmlBeanDefinitionReader來載入bean定義信息。 reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } } // XmlBeanDefinitionReader.java public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } SetcurrentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet (4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //這里是具體的解析和注冊過程 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //通過解析得到DOM,然后完成bean在IOC容器中的注冊 Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } ....
我們看到先把定義文件解析為DOM對象,然后進行具體的注冊過程:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 具體的注冊過程,首先得到XmlBeanDefinitionReader,來處理xml的bean定義文件 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
(5)在BeanDefinitionDocumentReader中完成bean定義文件的解析和IOC容器bean的初始化。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } // 對配置文件(xml文件)進行解析 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { //這里是解析過程的調用,對缺省的元素進行分析比如bean元素 parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { //這里對我們最熟悉的bean元素進行處理 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //委托給BeanDefinitionParserDelegate來完成對bean元素的處理,這個類包含了具體的bean解析的過程。 // 把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要載體,也是IOC容器的管理對象。 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 這里是向IOC容器注冊,實際上是放到IOC容器的一個map里 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name "" + bdHolder.getBeanName() + """, ele, ex); } // 這里向IOC容器發送事件,表示解析和注冊完成 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
(6)我們看到在parseBeanDefinition中對具體bean元素的解析式交給BeanDefinitionParserDelegate來完成的,下面我們看看解析完的bean是怎樣在IOC容器中注冊的:
在BeanDefinitionReaderUtils調用的是:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); //這是調用IOC來注冊的bean的過程,需要得到BeanDefinition registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 別名也是可以通過IOC容器和bean聯系起來的進行注冊 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
(7)我們看看XmlBeanFactory中的注冊實現:
//--------------------------------------------------------------------- // 這里是IOC容器對BeanDefinitionRegistry接口的實現 //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { .....//這里省略了對BeanDefinition的驗證過程 //先看看在容器里是不是已經有了同名的bean,如果有拋出異常。 Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { ........... } else { //把bean的名字加到IOC容器中去 this.beanDefinitionNames.add(beanName); } //這里把bean的名字和Bean定義聯系起來放到一個HashMap中去,IOC容器通過這個Map來維護容器里的Bean定義信息。 this.beanDefinitionMap.put(beanName, beanDefinition); removeSingleton(beanName); }
這樣就完成了Bean定義在IOC容器中的注冊,就可被IOC容器進行管理和使用了。
總結IOC容器初始化流程:1、初始化的入口在容器實現中的refresh()調用來完成
2、將bean定義信息載入IOC容器。使用的方法是loadBeanDefinition,其中的大致過程如下:
(1)通過ResourceLoader來完成資源文件位置的定位,DefaultResourceLoader是默認的實現,同時上下文本身就給出了ResourceLoader的實現,可以從類路徑,文件系統, URL等方式來定為資源位置。如果是XmlBeanFactory作為IOC容器,那么需要為它指定bean定義的資源,也就是說bean定義文件時通過抽象成Resource來被IOC容器處理的
(2)容器通過BeanDefinitionReader來完成定義信息的解析和Bean信息的注冊,往往使用的是XmlBeanDefinitionReader來解析bean的xml定義文件 - 實際的處理過程是委托給BeanDefinitionParserDelegate來完成的,從而得到bean的定義信息,這些信息在Spring中使用BeanDefinition對象來表示 - 這個名字可以讓我們想到loadBeanDefinition,RegisterBeanDefinition這些相關的方法 - 他們都是為處理BeanDefinitin服務的,IoC容器解析得到BeanDefinition以后,需要把它在IOC容器中注冊,這由IOC實現 BeanDefinitionRegistry接口來實現。注冊過程就是在IOC容器內部維護的一個HashMap來保存得到的 BeanDefinition的過程。這個HashMap是IoC容器持有bean信息的場所,以后對bean的操作都是圍繞這個HashMap來實現的。
(3)然后我們就可以通過BeanFactory和ApplicationContext來享受到Spring IOC的服務了.
1、BeanFactory 指的是IOC容器的編程抽象,比如ApplicationContext, XmlBeanFactory等,這些都是IOC容器的具體表現,需要使用什么樣的容器由客戶決定但Spring為我們提供了豐富的選擇。
2、Factory bean 是一個可以在IOC容器中被管理的一個bean,是對各種處理過程和資源使用的抽象,Factory bean在需要時產生另一個對象,而不返回FactoryBean本省,我們可以把它看成是一個抽象工廠,對它的調用返回的是工廠生產的產品。所有的 Factory bean都實現特殊的org.springframework.beans.factory.FactoryBean接口,當使用容器中factory bean的時候,該容器不會返回factory bean本身,而是返回其生成的對象。Spring包括了大部分的通用資源和服務訪問抽象的Factory bean的實現,其中包括:
對JNDI查詢的處理,對代理對象的處理,對事務性代理的處理,對RMI代理的處理等,這些我們都可以看成是具體的工廠,看成是SPRING為我們建立好的工廠。也就是說Spring通過使用抽象工廠模式為我們準備了一系列工廠來生產一些特定的對象,免除我們手工重復的工作,我們要使用時只需要在IOC容器里配置好就能很方便的使用了。
一、lazy-init延遲加載
1、執行原理:
lazy-init屬性:為true的話,在Ioc容器初始化過程中,會對BeanDefinitionMap中所有的Bean進行依賴注入,這樣在初始化過程結束后,容器執行getBean得到的就是已經準備好的Bean,不需要進行依賴注入。
2、優點:當應用第一次向容器索取所需的Bean時,容器不再需要對Bean進行初始化,直接從已經完成實例化的Bean中取出需要的bean,這樣就提高了第一次獲取Bean的性能。
二、BeanPostProcessor后置處理器:
1、BeanPostProcessor后置處理器是Spring IoC容器經常使用到的一個特性,這個Bean后置處理器是一個監聽器,可以監聽容器觸發的Bean聲明周期事件。后置處理器想容器注冊以后,容器中管理的Bean就具備了接收IoC容器事件回調的能力。
2、BeanPostProcessor的使用非常簡單,只需要提供一個實現接口BeanPostProcessor的實現類,然后在Bean的配置文件中設置即可。
3、API解釋:
public interface BeanPostProcessor { /** * Apply this BeanPostProcessor to the given new bean instance before any bean * initialization callbacks (like InitializingBean"s {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. */ //實例化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的初始化任務 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; /** * Apply this BeanPostProcessor to the given new bean instance after any bean * initialization callbacks (like InitializingBean"s {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. */ //實例化、依賴注入、初始化完畢時執行 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
三、自動裝配:
1、概念:無須在Spring配置文件中描述javaBean之間的依賴關系(如配置
2、在Spring中,支持 5 自動裝配模式。
(1)no – 缺省情況下,自動配置是通過“ref”屬性手動設定
(2)byName – 根據屬性名稱自動裝配。如果一個bean的名稱和其他bean屬性的名稱是一樣的,將會自裝配它。
(3)byType – 按數據類型自動裝配。如果一個bean的數據類型是用其它bean屬性的數據類型,兼容并自動裝配它。
(4)constructor – 在構造函數參數的byType方式。
ApplicationContext容器中,Bean的生命周期流程如上圖所示,流程大致如下:
1.首先容器啟動后,會對scope為singleton且非懶加載的bean進行實例化,
2.按照Bean定義信息配置信息,注入所有的屬性,
3.如果Bean實現了BeanNameAware接口,會回調該接口的setBeanName()方法,傳入該Bean的id,此時該Bean就獲得了自己在配置文件中的id,
4.如果Bean實現了BeanFactoryAware接口,會回調該接口的setBeanFactory()方法,傳入該Bean的BeanFactory,這樣該Bean就獲得了自己所在的BeanFactory,
5.如果Bean實現了ApplicationContextAware接口,會回調該接口的setApplicationContext()方法,傳入該Bean的ApplicationContext,這樣該Bean就獲得了自己所在的ApplicationContext,
6.如果有Bean實現了BeanPostProcessor接口,則會回調該接口的postProcessBeforeInitialzation()方法,
7.如果Bean實現了InitializingBean接口,則會回調該接口的afterPropertiesSet()方法,
8.如果Bean配置了init-method方法,則會執行init-method配置的方法,
9.如果有Bean實現了BeanPostProcessor接口,則會回調該接口的postProcessAfterInitialization()方法,
10.經過流程9之后,就可以正式使用該Bean了,對于scope為singleton的Bean,Spring的ioc容器中會緩存一份該bean的實例,而對于scope為prototype的Bean,每次被調用都會new一個新的對象,期生命周期就交給調用方管理了,不再是Spring容器進行管理了
11.容器關閉后,如果Bean實現了DisposableBean接口,則會回調該接口的destroy()方法,
12.如果Bean配置了destroy-method方法,則會執行destroy-method配置的方法,至此,整個Bean的生命周期結束
參考:
http://www.iteye.com/topic/86339
http://blessht.iteye.com/blog...
https://blog.csdn.net/masterm...
https://blog.csdn.net/sugar_r...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/69181.html
摘要:使用的好處知乎的回答不用自己組裝,拿來就用。統一配置,便于修改。 前言 只有光頭才能變強 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡單啦 單例模式你會幾種寫法? 工廠模式理解了沒有? 在刷Spring書籍的時候花了點時間去學習了單例模式和工廠模式,總的來說還是非常值得的! 本來想的是刷完《Spring 實戰 (第4版)》和《精通Spring4.x 企業應用開發實戰》...
摘要:簡介本篇文章是容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對象是方法,該方法用于對已完成屬性填充的做最后的初始化工作。后置處理器是拓展點之一,通過實現后置處理器接口,我們就可以插手的初始化過程。 1. 簡介 本篇文章是Spring IOC 容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對象是 initializeBean 方法,該方法用于對已完成屬性填充的 bean 做最...
摘要:本文是容器源碼分析系列文章的第一篇文章,將會著重介紹的一些使用方法和特性,為后續的源碼分析文章做鋪墊。我們可以通過這兩個別名獲取到這個實例,比如下面的測試代碼測試結果如下本小節,我們來了解一下這個特性。 1. 簡介 Spring 是一個輕量級的企業級應用開發框架,于 2004 年由 Rod Johnson 發布了 1.0 版本。經過十幾年的迭代,現在的 Spring 框架已經非常成熟了...
摘要:實例化時,發現又依賴于。一些緩存的介紹在進行源碼分析前,我們先來看一組緩存的定義。可是看完源碼后,我們似乎仍然不知道這些源碼是如何解決循環依賴問題的。 1. 簡介 本文,我們來看一下 Spring 是如何解決循環依賴問題的。在本篇文章中,我會首先向大家介紹一下什么是循環依賴。然后,進入源碼分析階段。為了更好的說明 Spring 解決循環依賴的辦法,我將會從獲取 bean 的方法getB...
摘要:在寫完容器源碼分析系列文章中的最后一篇后,沒敢懈怠,趁熱打鐵,花了天時間閱讀了方面的源碼。從今天開始,我將對部分的源碼分析系列文章進行更新。全稱是,即面向切面的編程,是一種開發理念。在中,切面只是一個概念,并沒有一個具體的接口或類與此對應。 1. 簡介 前一段時間,我學習了 Spring IOC 容器方面的源碼,并寫了數篇文章對此進行講解。在寫完 Spring IOC 容器源碼分析系列...
閱讀 5765·2021-11-24 10:25
閱讀 2701·2021-11-16 11:44
閱讀 3860·2021-10-11 11:09
閱讀 3177·2021-09-02 15:41
閱讀 3261·2019-08-30 14:14
閱讀 2289·2019-08-29 14:10
閱讀 2353·2019-08-29 11:03
閱讀 1131·2019-08-26 13:47