spring beans原始碼解讀之--Bean的定義及包裝
bean的定義,包裝是java bean的基礎。再怎麼強調它的重要性都不為過,因此深入 瞭解這塊的程式碼對以後的程式碼研究可以起到事半功倍的功效。
1. Bean的定義BeanDefinition
1.1 BeanDefinition 作用
一個BeanDefinition描述了一個bean的例項,包括屬性值,構造方法引數值和繼承自它的類的更多資訊。BeanDefinition僅僅是一個最簡單的介面,主要功能是允許BeanFactoryPostProcessor 例如PropertyPlaceHolderConfigure 能夠檢索並修改屬性值和別的bean的元資料。
1.2 BeanDefinition的繼承關係
父介面:
AttributeAccessor, BeanMetadataElement
子介面:
AnnotatedBeanDefinition
子類:
AbstractBeanDefinition, AnnotatedGenericBeanDefinition, ChildBeanDefinition, GenericBeanDefinition, RootBeanDefinition, ScannedGenericBeanDefinition
其中,AttributeAccessor介面定義了最基本的對任意物件的元資料的修改或者獲取,主要方法有:
String[] attributeNames() Object getAttribute(String name)boolean hasAttribute(String name) Object removeAttribute(String name) void setAttribute(String name, Object value)
BeanMetadataElement介面提供了一個getResource()方法,用來傳輸一個可配置的源物件。
1.3 BeanDefinition的抽象類AbstractBeanDefinition
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessorimplements BeanDefinition, Cloneable { }
其中,BeanMetadataAttributeAccessor介面既實現了BeanMetadataElement介面提供的getResource()方法也提供了AttributeAccessorSupport 針對屬性的增刪改查,如上AttributeAccessor的方法。
public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement { }
我們來看看一個抽象的beanDefinition 的建立涉及到哪些屬性?
構造方法之一,建立一個新的預設設定的AbstractBeanDefinition,如下面程式碼所示,具體資訊也可以參考BeanDefinitionDefaults這個類。
構造方法之二,根據構造引數值和屬性引數值來建立。
/** * Create a new AbstractBeanDefinition with default settings. */ protected AbstractBeanDefinition() { this(null, null); } /** * Create a new AbstractBeanDefinition with the given * constructor argument values and property values. */ protected AbstractBeanDefinition(ConstructorArgumentValues cargs, MutablePropertyValues pvs) { setConstructorArgumentValues(cargs); setPropertyValues(pvs); }
構造方法之三是深複製一個原有的beandefinition。
/** * Create a new AbstractBeanDefinition as a deep copy of the given * bean definition. * @param original the original bean definition to copy from */ protected AbstractBeanDefinition(BeanDefinition original) { setParentName(original.getParentName()); setBeanClassName(original.getBeanClassName()); setFactoryBeanName(original.getFactoryBeanName()); setFactoryMethodName(original.getFactoryMethodName()); setScope(original.getScope()); setAbstract(original.isAbstract()); setLazyInit(original.isLazyInit()); setRole(original.getRole()); setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); setSource(original.getSource()); copyAttributesFrom(original); if (original instanceof AbstractBeanDefinition) { AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original; if (originalAbd.hasBeanClass()) { setBeanClass(originalAbd.getBeanClass()); } setAutowireMode(originalAbd.getAutowireMode()); setDependencyCheck(originalAbd.getDependencyCheck()); setDependsOn(originalAbd.getDependsOn()); setAutowireCandidate(originalAbd.isAutowireCandidate()); copyQualifiersFrom(originalAbd); setPrimary(originalAbd.isPrimary()); setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); setInitMethodName(originalAbd.getInitMethodName()); setEnforceInitMethod(originalAbd.isEnforceInitMethod()); setDestroyMethodName(originalAbd.getDestroyMethodName()); setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod()); setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides())); setSynthetic(originalAbd.isSynthetic()); setResource(originalAbd.getResource()); } else { setResourceDescription(original.getResourceDescription()); } }
上述三個方法涉及到的介面和類有:
ConstructorArgumentValues:構造引數,儲存了構造方法所有的引數值,通常作為bean definition的一部分來使用。它不僅支援型別匹配的普通引數,也支援根據引數列表中的索引位置來提供引數。提供了兩個變數來儲存引數:帶索引的和不帶索引的
public class ConstructorArgumentValues { private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>(0); private final List<ValueHolder> genericArgumentValues = new LinkedList<ValueHolder>(); }
MutablePropertyValues:PropertyValues介面的預設實現,支援對屬性的簡單操作,為構造方法提供深度複製和使用map獲取構造的支援。
1.4 bean definition實現類ChildBeanDefinition, GenericBeanDefinition, RootBeanDefinition
1.4.1 ChildBeanDefinition是一種bean definition,它可以繼承它父類的設定,即ChildBeanDefinition對RootBeanDefinition有一定的依賴關係。
ChildBeanDefinition從父類繼承構造引數值,屬性值並可以重寫父類的方法,同時也可以增加新的屬性或者方法。(類同於java類的繼承關係)。若指定初始化方法,銷燬方法或者靜態工廠方法, ChildBeanDefinition將重寫相應父類的設定。depends on,autowire mode,dependency check,sigleton,lazy init 一般由子類自行設定。
注意:從spring 2.5 開始,提供了一個更好的註冊bean definition類GenericBeanDefinition,它支援動態定義父依賴,方法是GenericBeanDefinition.setParentName(java.lang.String),GenericBeanDefinition可以有效的替代ChildBeanDefinition的絕大分部使用場合。
1.4.2 GenericBeanDefinition是一站式的標準bean definition,除了具有指定類、可選的構造引數值和屬性引數這些其它bean definition一樣的特性外,它還具有通過parenetName屬性來靈活設定parent bean definition。
通常, GenericBeanDefinition用來註冊使用者可見的bean definition(可見的bean definition意味著可以在該類bean definition上定義post-processor來對bean進行操作,甚至為配置parent name做擴充套件準備)。RootBeanDefinition
/ ChildBeanDefinition用來預定義具有
parent/child關係的bean definition。
1.4.3 RootBeanDefinition
一個RootBeanDefinition定義表明它是一個可合併的bean definition:即在spring beanFactory執行期間,可以返回一個特定的bean。RootBeanDefinition可以作為一個重要的通用的bean definition 檢視。
RootBeanDefinition用來在配置階段進行註冊bean definition。然後,從spring 2.5後,編寫註冊bean definition有了更好的的方法:GenericBeanDefinition。GenericBeanDefinition支援動態定義父類依賴,而非硬編碼作為root bean definition。
涉及到的類:BeanDefinitionHolder,根據名稱或者別名持有beanDefinition。可以為一個內部bean 註冊為placeholder。
BeanDefinitionHolder也可以編寫一個內部bean definition的註冊,如果你不關注BeanNameAware等,完全可以使用RootBeanDefinition或者ChildBeanDefinition來替代。
2. Bean的包裝BeanWrapper
2.1 作用:提供對標準javabean的分析和操作方法:單個或者批量獲取和設定屬性值,獲取屬性描述符,查詢屬性的可讀性和可寫性等。支援屬性的巢狀設定,深度沒有限制。
2.2 繼承關係:
public interface BeanWrapper extends ConfigurablePropertyAccessor { } public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter { }
其中,ConfigurablePropertyAccessor 介面封裝了PropertyAccessor的配置方法,同時繼承了PropertyEditorRegistry介面,具有了對PropertyEditor進行管理的方法。該介面的固有方法:
ConversionService getConversionService() 返回關聯的ConversionService,如果存在的話。
boolean isExtractOldValueForEditor() 返回標示位。如果為true,表示當使用屬性編輯器編輯一個屬性的值時提取舊的屬性值,如果為false,則表示不提取舊值。
void setConversionService(ConversionService conversionService) conversionservice是從spring3.0引入的,可以作為java bean 屬性編輯器的替代功能,作用是改變屬性的值。
void setExtractOldValueForEditor(boolean extractOldValueForEditor) 設定是否提取舊的屬性值標示位,如上描述。
另外,ConfigurablePropertyAccessor 介面繼承的方法有:
從PropertyAccessor繼承的方法有:getPropertyType, getPropertyTypeDescriptor, getPropertyValue, isReadableProperty, isWritableProperty, setPropertyValue, setPropertyValue, setPropertyValues, setPropertyValues, setPropertyValues, setPropertyValues;
從PropertyEditorRegistry繼承的方法有:findCustomEditor, registerCustomEditor, registerCustomEditor;
從TypeConverter 繼承的方法有:convertIfNecessary, convertIfNecessary, convertIfNecessary 。
2.3 BeanWrapper的實現類:BeanWrapperImpl
BeanWrapperImpl作用:可以根據需求,將集合與陣列的值轉換到對應目標物件的集合和陣列。自定義的屬性編輯器通過屬性編輯器的setValue,setAsText方法實現上述的轉換功能。
BeanWrapperImpl 預設的PropertyEditor的實現如下:(PropertyEditorRegistrySupport.java)
private void createDefaultEditors() { this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64); // Simple editors, without parameterization capabilities. // The JDK does not contain a default editor for any of these target types. this.defaultEditors.put(Charset.class, new CharsetEditor()); this.defaultEditors.put(Class.class, new ClassEditor()); this.defaultEditors.put(Class[].class, new ClassArrayEditor()); this.defaultEditors.put(Currency.class, new CurrencyEditor()); this.defaultEditors.put(File.class, new FileEditor()); this.defaultEditors.put(InputStream.class, new InputStreamEditor()); this.defaultEditors.put(InputSource.class, new InputSourceEditor()); this.defaultEditors.put(Locale.class, new LocaleEditor()); this.defaultEditors.put(Pattern.class, new PatternEditor()); this.defaultEditors.put(Properties.class, new PropertiesEditor()); this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); this.defaultEditors.put(TimeZone.class, new TimeZoneEditor()); this.defaultEditors.put(URI.class, new URIEditor()); this.defaultEditors.put(URL.class, new URLEditor()); this.defaultEditors.put(UUID.class, new UUIDEditor()); if (zoneIdClass != null) { this.defaultEditors.put(zoneIdClass, new ZoneIdEditor()); } // Default instances of collection editors. // Can be overridden by registering custom instances of those as custom editors. this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class)); this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class)); this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class)); this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class)); this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); // Default editors for primitive arrays. this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); // The JDK does not contain a default editor for char! this.defaultEditors.put(char.class, new CharacterEditor(false)); this.defaultEditors.put(Character.class, new CharacterEditor(true)); // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor. this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); // The JDK does not contain default editors for number wrapper types! // Override JDK primitive number editors with our own CustomNumberEditor. this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false)); this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true)); this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false)); this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true)); this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); // Only register config value editors if explicitly requested. if (this.configValueEditorsActive) { StringArrayPropertyEditor sae = new StringArrayPropertyEditor(); this.defaultEditors.put(String[].class, sae); this.defaultEditors.put(short[].class, sae); this.defaultEditors.put(int[].class, sae); this.defaultEditors.put(long[].class, sae); } }
其中涉及到很多編輯器,在此就不贅敘了,如有興趣,可以自行查詢。
3. 小結:
bean的定義,包裝是java bean的基礎。可以這麼說,這一塊是spring的基石。本文僅僅揭開spring 中java bean的面紗,希望能起到拋磚引玉的功能,以饗讀者。
相關推薦
spring beans原始碼解讀之--Bean的定義及包裝
bean的定義,包裝是java bean的基礎。再怎麼強調它的重要性都不為過,因此深入 瞭解這塊的程式碼對以後的程式碼研究可以起到事半功倍的功效。 1. Bean的定義BeanDefinition 1.1 BeanDefinition 作用 一個BeanDefinition描述了一個bean的例項,
spring beans原始碼解讀之--bean definiton解析器
spring提供了有兩種方式的bean definition解析器:PropertiesBeanDefinitionReader和XmLBeanDefinitionReader即屬性檔案格式的bean definition解析器和xml檔案格式的bean definition解析器。 我們先從簡單的Prop
spring beans原始碼解讀之--Bean的註解(annotation)
隨著spring註解的引入,越來越多的開發者開始使用註解,這篇文章將對註解的機制進行串聯式的講解,不求深入透徹,但求串起spring beans註解的珍珠,展示給大家。 1. spring beans常用的註解: public @interface Autowired:可以對成員變數、方法和建構函式進
spring beans原始碼解讀之 ioc容器之始祖--DefaultListableBeanFactory
spring Ioc容器的實現,從根源上是beanfactory,但真正可以作為一個可以獨立使用的ioc容器還是DefaultListableBeanFactory,因此可以這麼說, DefaultListableBeanFactory 是整個spring ioc的始祖,研究透它
spring beans原始碼解讀之--總結篇
spring beans下面有如下原始檔包: org.springframework.beans, 包含了操作java bean的介面和類。org.springframework.beans.annotation, 支援包,提供對java 5註解處理bean樣式的支援。org.springframework
spring beans原始碼解讀之--XmlBeanFactory
導讀: XmlBeanFactory繼承自DefaultListableBeanFactory,擴充套件了從xml文件中讀取bean definition的能力。從本質上講,XmlBeanFactory等同於DefaultListableBeanFactory+XmlBeanDefinitionReader
Spring原始碼解讀之——bean的生命週期(隨筆)
bean建立---初始化----銷燬的過程 容器管理bean的生命週期; 我們可以自定義初始化和銷燬方法;容器在bean進行到當前生命週期的時候來呼叫我們自定義的初始化和銷燬方法 構造(物件建立) 單例項:在容器啟動的時候建立物件 多例項:在每次獲取的時
Spring Ioc 原始碼分析之Bean的載入和構造
我們都知道,Spring Ioc和Aop是Spring的核心的功能,因此花一點時間去研究還是很有意義的,如果僅僅是知其所以然,也就體會不到大師設計Spring的精華,還記得那句話,Spring為JavaEE開發帶來了春天。IOC就是Inversion of control 也就是控制反轉的意思,另一種稱呼叫做
spring原始碼學習之路---IOC容器初始化要義之bean定義載入(四)
上章說到要帶各位去看看bean定義載入的要義,其實就是loadBeanDefinitions這個方法的具體實現步驟,下面我們跟隨這個方法去看下它到底是如何載入bean定義的。 上面是我擷取的實現了loadBeanDefinitions的類級別截圖,loadBeanDefinit
Spring(五)之Bean定義繼承和依賴註入
dia 繼承 map() path 形式 集合 .text inf ima 一、Bean定義繼承 bean定義可以包含許多配置信息,包括構造函數參數,屬性值和特定於容器的信息,例如初始化方法,靜態工廠方法名稱等。 子bean定義從父定義繼承配置數據。子定義可以根據需要覆蓋某
Spring原始碼解讀之核心容器上節
Spring架構圖 說明 Spring的流行程度就不用我來說了,相信大家如果使用JAVA開發就一定知道它。寫這篇文章的初衷在於:1.瞭解Spring底層實現原理,提升對Spring的認識與理解。2.學習優秀框架程式設計實現,學習優秀的設計模式。3.使用Spring三年多,對於底層細節希望知道更多,便於
Spring原始碼解讀之核心容器下節
續 上一篇我們通過ClassPathXmlApplicationContext載入xml檔案,通過BeanFactory獲取例項bean的demo程式碼去解讀了Spring Core Container中的spring-beans,spring-core,spring-context三個元件之間的一些具體類
Spring原始碼解讀之Spring MVC HandlerMapping元件(二)
一、HandlerMapping HandlerMapping作用是根據request找到相應的處理器Handler和Interceptors,並將Handler和Interceptors封裝成HandlerExecutionChain 物件返回。Handler
Spring原始碼解讀之——元件註冊(隨筆)
@ComponentScan value:指定要掃描的包 excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些元件 includeFilters = Filt
spring原始碼解讀之 JdbcTemplate原始碼
在Spring中,JdbcTemplate是經常被使用的類來幫助使用者程式操作資料庫,在JdbcTemplate為使用者程式提供了許多便利的資料庫操作方法,比如查詢,更新等,而且在Spring中,有許多類似 JdbcTemplate的模板,比如HibernateT
Spring原始碼解讀之——自動裝配(隨筆)
Spring利用依賴注入(DI),完成對IOC容器中中各個元件的依賴關係賦值; 1、@Autowired:自動注入: 1)、預設優先按照型別去容器中找對應的元件:applicationContext.getBean(BookDao.class);找到就賦值
Spring原始碼閱讀之Bean載入(xml)1
先上兩張圖,簡單的畫了一下beanFactory各個類之間的關係,XmlBeanFactory是bean載入的入口和核心。Spring中大量使用了設計模式和UML中的設計原則,比如單一職責原則,從類圖可以看出,BeanFactory派生的各個介面,根據名字的不同,都增加了
Spring原始碼解析之bean的建立
閱讀須知 Spring原始碼版本:4.3.8 文章中使用/* */註釋的方法會做深入分析 正文 之前我們都是在圍繞 ApplicationContext applicationContext = new ClassPathXmlApplicati
我該如何學習spring原始碼以及解析bean定義的註冊
如何學習spring原始碼 前言 本文屬於spring原始碼解析的系列文章之一,文章主要是介紹如何學習spring的原始碼,希望能夠最大限度的幫助到有需要的人。文章總體難度不大,但比較繁重,學習時一定要耐住性子堅持下去。 獲取原始碼 原始碼的獲取有多種途徑 GitHub spring-framework sp
Spring原始碼解讀之BeanFactoryPostProcessor的處理
前言 前段時間旁聽了某課堂兩節Spring原始碼解析課,剛好最近自己又在重新學習中,便在這裡記錄一下學習所得。我之前寫過一篇博文,是介紹BeanFactoryPostProcessor跟BeanPostProcessor是如何發揮作用的,當時覺得講的還行,但是現在看來,太粗劣了,