傻瓜源碼-內容簡介 |
---|
🤪【職場經驗】(持續更新) 精編短文:如何成爲值錢的Java開發-指南 如何平常學習、如何書寫簡歷、引導面試官、系統準備面試、選擇offer、提升績效、晉升TeamLeader..... |
🧐【源碼解讀】(持續更新) <br/>1. 源碼選材:Java架構師必須掌握的全部框架和類庫源碼<br/>2. 內容大綱:按照「企業應用Demo」講解執行源碼:總綱「閱讀指南」、第一章「源碼基礎」、第二章「相關Java基礎」、第三章「白話講源碼」、第四章「代碼解讀」、第五章「設計模式」、第六章「附錄-面試習題、相關JDK方法、中文註釋可運行源碼項目」 3. 讀後問題:粉絲羣答疑解惑 |
已收錄:HashMap、ReentrantLock、ThreadPoolExecutor、《Spring源碼解讀》、《Dubbo源碼解讀》..... |
🤩【面試題集】(持續更新)<br/>1. 面試題選材:Java面試常問的全部面試題和必會知識點<br/>2. 內容大綱:第一部分」注意事項「、第二部分「面試題解讀」(包括:」面試題「、」答案「、」答案詳解「、「實際開發解說」) 3. 深度/廣度:面試題集中的答案和答案詳解,都是對齊通常面試要求的深度和廣度 4. 讀後問題:粉絲羣答疑解惑 |
已收錄:Java基礎面試題集、Java併發面試題集、JVM面試題集、數據庫(Mysql)面試題集、緩存(Redis)面試題集 ..... |
🤤【粉絲羣】(持續更新) <br/>收錄:阿里、字節跳動、京東、小米、美團、嗶哩嗶哩等大廠內推 |
😛 做者介紹:Spring系源碼貢獻者、世界五百強互聯網公司、TeamLeader、Github開源產品做者 😛 做者微信:wowangle03 (企業內推聯繫我) |
加入個人粉絲社羣,閱讀更多內容。從學習到面試,從面試到工做,從 coder 到 TeamLeader,天天給你答疑解惑,還能有第二份收入!html
本書建議分爲兩個學習階段,掌握了第一階段,再進行第二階段;java
源碼項目中的註釋含義;git
如下注釋的源碼,暫時不深刻講解:面試
代碼示例 1spring
public class PersionA { private PersionB pb; public PersionB getPb() { return pb; } public void setPb(PersionB pb) { this.pb = pb; } }
代碼示例 2sql
public class PersionB { private PersionA pa; public PersionA getPa() { return pa; } public void setPa(PersionA pa) { this.pa = pa; } }
代碼示例 3 application.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="persionA" class="org.springframework.demo.PersionA"> <property name="pb" ref="persionB"/> </bean> <bean id="persionB" class="org.springframework.demo.PersionB"> <property name="pa" ref="persionA"/> </bean> </beans>
代碼示例 4 啓動 Spring 設計模式
public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml"); PersionA persion = (PersionA) context.getBean("persionA"); System.out.println(persion.getPb()); } }
暫時由「基礎入門 Demo」代替,」企業應用 Demo 「以及配套的第 2 版《Spring 源碼解讀》正在修改中...。緩存
代碼示例 1 接口微信
public interface Person { public abstract void eat(); }
代碼示例 2 實例化接口
public class Demo { public static void main(String[] args) { // 使用 Lambda 直接建立 Persion 接口實例 Person p1 = () -> System.out.println("eat something!"); // 打印結果:eat something! p1.eat(); } }
直接實例化接口適用於在多個不一樣的調用場合,抽象方法會有不一樣實現邏輯的場景。反過來想,若是不使用 Lambda 建立 Persion 接口實例,想要在不一樣調用場合,執行不一樣實現邏輯,就必須爲每一個場合定義一個實現了接口的類,而後在實現類的方法裏實現對應邏輯。這樣比較,使用 Lambda 表達式直接建立接口實例是否是大大簡化了代碼呢!
1. Spring 中的對象種類
在」企業應用 Demo「中,有涉及到兩種對象:Pojo、Bo;
ClassPathXmlApplicationContext(Bo),繼承自 AbstractRefreshableConfigApplicationContext ,調用構造函數實例化的同時,啓動了 Spring ;在「企業應用 Demo」中主要負責建立 DefaultListableBeanFactory 工廠對象和 XmlBeanDefinitionReader 對象來執行邏輯。
代碼示例 重要成員變量
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { // 繼承自 AbstractRefreshableConfigApplicationContext // configLocations 表示 application.xml 配置文件的路徑,能夠配置多個配置文件,例:["classpath*:applicationContext.xml"] private String[] configLocations; // 繼承自 AbstractRefreshableApplicationContext // beanFactory 表示 DefaultListableBeanFactory 實例,總的來講就是用於生成 Bean 的工廠。好比:生成目標對象(例:PersionA)。 private DefaultListableBeanFactory beanFactory;
XmlBeanDefinitionReader(Bo),簡稱:XmlBean定義讀取器;負責讀取 application.xml 配置文件,解析成 Resource 實例(Spring 定義的,是用來封裝文件資源的類),再根據 Resource 實例獲取到的 inputStream 輸入流,轉化成 Document 實例;而後交由 DefaultBeanDefinitionDocumentReader 對象進行下一步操做。
代碼示例 重要成員變量
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { // resourceLoader 表示 ClassPathXmlApplicationContext 實例,負責讀取 applicaiton.xml 文件爲 Resource 實例 private ResourceLoader resourceLoader; // documentLoader 負責將表明 Resource的inputStream輸入流轉換成 Document 對象 private DocumentLoader documentLoader = new DefaultDocumentLoader(); // resourcesCurrentlyBeingLoaded 保存當前線程加載了的 application.xml 配置文件(包括<import/> 標籤引進的 xml 資源),用來檢查 <import/> 形成的循環導入 private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<>("XML bean definition resources currently being loaded"); // 繼承自 AbstractBeanDefinitionReader // registry 表示 DefaultListableBeanFactory 實例,XmlBeanDefinitionReader 是經過構造函數獲取到並持有的這個對象,是爲了向後續邏輯傳遞下去 private final BeanDefinitionRegistry registry;
DefaultBeanDefinitionDocumentReader(Bo),簡稱:Bean 定義 Document 讀取器;負責讀取 Document 實例中的節點信息,如:< bean/>、< import/> 等;而後交由 BeanDefinitionParserDelegate 對象進行下一步操做。
代碼示例 重要成員變量
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { // readerContext 表示 XmlReaderContext 實例,Xml讀取器上下文 // 做用:爲了將 XmlBeanDefinitionReader 實例、 Resource 實例、DefaultListableBeanFactory 實例等 統一封裝到XmlReaderContext 裏,向後傳遞使用 private XmlReaderContext readerContext; // delegate 表明 BeanDefinitionParserDelegate 實例;負責將 Document 對象(例如:< bean/>)裝載爲 GenericBeanDefinition private BeanDefinitionParserDelegate delegate;
BeanDefinitionParserDelegate(Bo),簡稱:Bean 定義解析代理;負責將 Document 對象(例如:< bean/>)裝載成 GenericBeanDefinition 對象;而後交由 DefaultListableBeanFactory 對象進行下一步操做。
代碼示例 重要成員變量
public class BeanDefinitionParserDelegate { // readerContext 表示 XmlReaderContext 實例,上文提過,是Xml讀取器上下文 // 用於從 XmlReaderContext 裏獲取 DefaultListableBeanFactory 實例等對象) private final XmlReaderContext readerContext;
GenericBeanDefinition(Pojo),簡稱:通用 Bean 定義;是用來裝載 < bean/> 配置的實體類。
代碼示例 重要成員變量
public class GenericBeanDefinition extends AbstractBeanDefinition { // beanClass 對應<bean class=""/>中的 class 值,一開始會被賦值爲 class 設置的字符串,後面會被賦值爲解析後的 Class 對象 private volatile Object beanClass; // 繼承自 AbstractBeanDefinition // propertyValues 是保存 <property/> 信息的實體類 private MutablePropertyValues propertyValues;
BeanDefinitionHolder(Pojo),簡稱:Bean定義持有者;負責持有 GenericBeanDefinition 對象(也就是說 GenericBeanDefinition 對象是 BeanDefinitionHolder 一個成員變量),在「企業應用 Demo」中,只起到數據傳輸的做用。
BeanDefinitionHolder 的必要性和 BeanNameAware 相關;」企業應用 Demo「不涉及。
代碼示例 重要成員變量
public class BeanDefinitionHolder implements BeanMetadataElement { // beanDefinition 表示 GenericBeanDefinition 實例;用於裝載從 application.xml 配置文件中解析出來的 < bean/> private final BeanDefinition beanDefinition; // beanName 表示 <bean/> 在 Spring 中的名字,通常爲 <bean id=""/> 中的 id 值 private final String beanName;
DefaultListableBeanFactory(Bo);總的來講就是生成 Bean 的工廠。在」企業應用 Demo「中,主要負責根據 GenericBeanDefinition 對象,生成目標對象(例:PersionA)並注入屬性值,放到 Map<String, Object> singletonObjects 裏保存起來,供應用程序使用。
代碼示例 重要成員變量
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { // beanDefinitionNames 用於存放從 application.xml 文件中解析出來的 beanName(通常爲 <bean/>標籤中的 id 值),按註冊順序排列 private volatile List<String> beanDefinitionNames = new ArrayList<>(256); // 數據結構:{beanName -> GenericBeanDefinition 對象},用於後續邏輯根據 beanName 獲取 GenericBeanDefinition 實例來用 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // 繼承自 AbstractBeanFactory // 數據結構:{beanName -> RootBeanDefinition 實例} 緩存,用於防止重複建立 beanName 的 RootBeanDefinition private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); // 繼承自 DefaultSingletonBeanRegistry // singletonsCurrentlyInDestruction 用於標記 Spring 是否處在銷燬單例的過程,默認爲false;若是設置爲 true,建立單例bean的時候,就會拋出 BeanCreationNotAllowedException 異常 private boolean singletonsCurrentlyInDestruction = false; /** * * 如下成員變量,參考下一節「循環依賴」,進行理解 * */ // 繼承自 DefaultSingletonBeanRegistry // singletonsCurrentlyInCreation 中存儲的beanName都是處於建立過程當中的 // 當該目標對象建立完成後,會將對應的 beanName 從 singletonsCurrentlyInCreation 集合中剔除掉 // 做用:主要用於解決 IOC 循環依賴的問題 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 繼承自 DefaultSingletonBeanRegistry // 數據結構:{beanName ->單例 bean 對象(例:PersionA 實例)} ,也被稱爲一級緩存; // 添加場景:在「企業應用 Demo」中,當 application.xml 中定義的 bean 對象被徹底實例化後(徹底實例化是指實例化並注入屬性值後),則會被放入本緩存中 // 做用:單例 bean 會被放到這個緩存裏,當應用系統想要獲得 Spring 管理的 <bean/> 時(例:context.getBean("persion");),就能夠直接從這個緩存裏獲取 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 繼承自 DefaultSingletonBeanRegistry // 數據結構:{beanName —> ObjectFactory 接口的實現類實例} ,也稱爲三級緩存 // ObjectFactory 是生產目標對象的工廠接口;不一樣場景下,生成對象的邏輯不一樣,因此這裏使用了工廠接口(好比:生成 AOP 代理對象和經過構造函數生成普通對象等) // 添加場景:在「企業應用 Demo」中,當 bean 對象(例:PersionA 實例)實例化後,沒有注入屬性值以前,會放入本緩存; // 移除場景:在「企業應用 Demo」中,當 bean 對象徹底實例化後,則會從本緩存中剔除掉 // 做用:在「企業應用 Demo」中,singletonObjects 存放的 value 值是 lambda 表達式建立的 ObjectFactory 接口實例; // singletonFactories 是建立目標對象過程當中,用於存放處於中狀態對象的臨時容器 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 繼承自 DefaultSingletonBeanRegistry // 數據結構:{beanName -> bean 對象(例:PersionA 實例)} ,是提早曝光的單例對象緩存,也稱爲二級緩存; // 添加場景:在「企業應用 Demo」中,當 bean 對象(例:PersionA 實例)實例化後,發現成員變量指定了其它 Spring 管理的 <bean/> 對象(例:PersionB 實例),而且這個 <bean/> 對象(例:PersionB 實例)存在於 singletonsCurrentlyInCreation ,也存在於三級緩存中,就會把 PersionB 對象從三級緩存中移除,放到二級緩存裏;(若是未發生過循環依賴的場景,二級緩存從始至終沒有存在過值) // 移除場景:在「企業應用 Demo」中,當 bean 對象徹底實例化後,則會從本緩存中剔除掉 // 做用:用於解決 IOC 循環依賴的問題 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
1. 問題
若是 persionA 依賴 persionB ,persionB 依賴 persionA ,Spring 是如何初始化 PersionA 和 PersionB 的?(這個現象稱之爲」循環依賴「)
2. 答案
persionA | persionB |
---|---|
1.要開始建立 persionA 對象以前,向 singletonsCurrentlyInCreation 添加該對象的對應 beanName(旨在標記 persionA 處於’建立中‘) | |
2.建立完 persionA 對象後,再把persionA 對象存在三級緩存中,再準備開始注入屬性 | |
3.注入屬性時,發現依賴 persionB ,要建立 persionB 對象 | |
總結:這時,persionA 對象的 pb 屬性爲空;三級緩存包含 persionA | |
1.要開始建立 persionB 對象以前,向 singletonsCurrentlyInCreation 添加該對象的對應 beanName(旨在標記 persionB 處於’建立中‘) | |
2.建立完 psersionB 對象後,再把 persionB 對象存在三級緩存裏,再準備開始注入屬性 | |
2.注入屬性時,發現依賴 persionA 對象 | |
3.建立 persionA,發現 singletonsCurrentlyInCreation 存有相應 beanName(PersionA 處於'建立中' ),而且保存在三級緩存裏,則直接從三級緩存中移除 PersionA 對象,而後放到二級緩存裏 | |
4.將 persionA 對象注入到 persionB 對象的 pa 屬性裏 | |
5.從三級緩存中刪掉 persionB 對象,放到一級緩存裏 | |
總結:這時,persionB 對象的 pa 屬性不爲空,可是 pa 屬性(persionA)的 pb 屬性爲空;二級緩存包含 persionA,一級緩存包含 persionB | |
4.得到 persionB 對象,放到 pb 屬性裏 | |
5.從二級緩存中刪掉 persionA對象,放到一級緩存裏 | |
總結:這時,persionA 對象的 pb 屬性不爲空,pb 屬性的 pa 屬性也不爲空;一級緩存包含 persionA 和 persionB |
RootBeanDefinition(Pojo); < bean/> 有繼承的能力(< bean parent=""/> ),因此 Spring 會進行對父子 < bean/> 進行合併操做,最後合併成 RootBeanDefinition 實例,區別於 GenericBeanDefinition 實例 。
代碼示例 重要成員變量
public class RootBeanDefinition extends AbstractBeanDefinition { // beanClass 表示 <bean class="org.springframework.PersionA"/> 中的 class 值,一開始爲"org.springframework.PersionA"字符串,而後會解析爲 PersionA Class 對象,再 set 到當前屬性裏 private volatile Object beanClass; // 繼承自 AbstractBeanDefinition // propertyValues 表示對應 < property/> 信息的實體類 private MutablePropertyValues propertyValues; // scope 表示 <bean/> 的單例模式;scope 默認爲"",當 Spring 發現值是空字符串時,而且用戶沒有指定,就會將值修改成"singleton"(單例),也就是說 Spring 的 <bean/> 默認是單例的。 private String scope = "";
MutablePropertyValues(Pojo),在 Spring 中,用於封裝 < property/> 信息的實體類。
代碼示例 重要成員變量
public class MutablePropertyValues implements PropertyValues, Serializable { // propertyValueList 表示 <property/> 集合(集合中的一個元素對應一個<property/>標籤) private final List<PropertyValue> propertyValueList;
PropertyValue(Pojo),在 Spring 中,對應 < property/> 的實體類,保存了 < property/> 的配置信息,好比屬性名、屬性值等;這裏 Spring 之因此不使用 Map 這種鍵值對類,是由於自定義類有更強的擴展性。
代碼示例 重要成員變量
public class PropertyValue extends BeanMetadataAttributeAccessor implements Serializable { // name 表示 <property/> 中的 name 屬性 private final String name; // value 表示 <property/> 指定的值;例:<property name="persionB" ref="pB">,value一開始爲指代 ref 的 RuntimeBeanReference 對象;後續邏輯將 RuntimeBeanReference 對象解析爲 PersionB 對象,從新覆蓋到 value 屬性上 private final Object value; // source 是 PropertyValue 實例;在將 RuntimeBeanReference 對象解析爲 PersionB對象以前和以後,分別會使用兩個 PropertyValue 對象去裝載,這個 source 屬性就是以前的 PropertyValue 對象(例:<property name="persionB" ref="pB">) private Object source; // conversionNecessary 表示是否轉換 <Property/> 指定的值,默認爲空(表示有必要進行轉換),Spring就會查找用戶自定義的轉換器進行轉換,當發現沒有轉換器,就會將 conversionNecessary 設置爲 false ,不須要轉換 volatile Boolean conversionNecessary;
RuntimeBeanReference(Pojo),在 Spring 中,用於裝載 < property ref=""/> 中 ref 指定的值。
代碼示例 重要成員變量
public class RuntimeBeanReference implements BeanReference { // beanName 表示 ref 的值 private final String beanName;
BeanWrapperImpl(Bo),持有目標對象(例:PersionA 對象),能夠對其設置/獲取屬性的描述信息,好比:查詢只讀/可寫屬性等。」企業應用 Demo」中,主要負責給 < bean/> 實例化後的目標對象(例:PersionA 對象)注入的 < property/> 所配置的值。
代碼示例 重要成員變量
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper { // 繼承自 AbstractNestablePropertyAccessor // wrappedObject 表示 <bean/> 所表明的目標對象,例:PersionA 對象 Object wrappedObject; // 私有類 // BeanPropertyHandler 表示通用屬性描述器,用於保存 < property/> 中的相關信息(例:屬性所屬類 Class 、屬性對應 get/set 方法 Method 對象等);」企業應用 Demo」中,主要用於從本對象獲取相應屬性的set方法 Method 對象 private class BeanPropertyHandler extends PropertyHandler{...}
BeanWrapperImpl$BeanPropertyHandler(Bo)($ 表示 BeanPropertyHandler 是 BeanWrapperImpl 中的內部類),Bean屬性處理器,負責管理 < property/> 屬性;」企業應用 Demo」中,主要負責利用反射,調用 setter 方法,對 < bean/> 設置 < property /> 指定的值。
代碼示例 重要成員變量
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper { private class BeanPropertyHandler extends PropertyHandler { // GenericTypeAwarePropertyDescriptor 實例,繼承自 PropertyDescriptor(來自第三方jar包),能夠得到類的信息,比 setter 方法、setter 方法的參數類型等 private final PropertyDescriptor pd;
GenericTypeAwarePropertyDescriptor(Pojo), 通用屬性描述器,用於保存 < property/> 中的相關信息(例:屬性所屬類 Class 、屬性的對應 get/set 方法 Method 對象等);」企業應用 Demo」中,主要用於從本對象獲取相應屬性的 set 方法 Method 對象。
代碼示例 重要成員變量
final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { // beanClass 表示 <property/> 的所屬類的 Class 對象(例:PersionA.Class) private final Class<?> beanClass; // 繼承自 PropertyDescriptor(第三方jar) // writeMethodRef 記錄了 <bean/> 對象(例:PersionA )的 set<property/> 的 Method 對象,用於獲取 set 方法反射設置屬性值 private final MethodRef writeMethodRef = new MethodRef(); // writeMethod 表示 setter 方法的 Method 對象 private final Method writeMethod; // propertyType 表示 <property/> 指代值的 Class 對象 private Class<?> propertyType;
<br/>
加入個人粉絲社羣,閱讀所有內容
從學習到面試,從面試到工做,從 coder 到 TeamLeader,天天給你答疑解惑,還能有第二份收入,這樣的知識星球,難道你還要猶豫!