Spring源碼——ClassPathXmlApplicationContext

一、ClassPathXmlApplicationContext的作用

? ??ClassPathXmlApplicationContext是Spring讀取xml最常用的類,它只能讀取放在WEB-INF/classes/目錄下的配置文件,所以在使用ClassPathXmlApplicationContext的時候可以將配置文件放在項目的原文件夾下面,這樣編譯的時候會將配置文件拷貝到WEB-INF下面去。如果是Springboot項目,一般要把文件呢放到resources配置文件夾下,才可以被ClassPathXmlApplicationContext讀取到。

二、ClassPathXmlApplicationContext類的繼承關系

ClassPathXmlApplicationContext 類的繼承結構

? ? ? ? PS:藍色實線為類繼承關系、綠色虛線為類實現接口、綠色實線為接口繼承接口

三、ClassPathXmlApplicationContext是怎么讀取配置文件的

? ? 1、常用的ClassPathXmlApplicationContext使用方式:
? ?????? ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("spring-ioc.xml");
? ? 2、構造方法;

????參數parent是自動傳遞上下文;
? ??
? ? 2.1???super(parent);方法一直引用到AbstractApplicationContext中,將ApplicationContext的環境屬性設置給本類的環境屬性,包括一些profile、系統屬性等;

? ? 2.2 this.setConfigLocations(configLocations);? 設置xml配置文件地址;

? ? 2.3?refresh()進行初始化工作;
????????refresh()方法是用來刷新IOC容器的,此方法會去調用父類的刷新方法,所有的bean都會在此方法中實現加載。

refresh源碼

? ? 3、加載Bean
? ? ? ? 在 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();方法執行結束之后,xml中定義的bean就已經加載到IOC容器中了。

obtainFreshBeanFactory源碼

if語句邏輯,如果beanFactory存在就銷毀關閉,然后在下面重新創建。
DefaultListableBeanFactory類是整個Bean加載的核心部分,是Spring注冊加載Bean的默認實現,也是整個Spring IOC的始祖。
紅框方法為注冊bean

加載Bean

這里實現主要分幾個步驟:
????首先判斷本類的DefaultListableBeanFactory屬性是否為null,如果不為null,就先清除一寫跟Bean有關的Map或者List等屬性集合
? ??將BeanFactory設置為null,序列化id設置為null,
????創建DefaultListableBeanFactory,這個類很重要,是springBean初始化的核心類,
????對beanFactory進行設置,bean注冊等操作,最后將beanFactory賦值給本類的beanFactory屬性
其中customizeBeanFactory只做了兩件事,設置bean是否允許覆蓋、設置Bean是否允許循環使用。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
?????// 實例化一個用于讀取和轉化xml文件內容的XmlBeanDefinitionReader
?????XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

?????// 設置reader的環境屬性
?????beanDefinitionReader.setEnvironment(this.getEnvironment());
?????beanDefinitionReader.setResourceLoader(this);
?????beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
?????// 通過beanDefinitionReader 加載bean
?????initBeanDefinitionReader(beanDefinitionReader);
?????loadBeanDefinitions(beanDefinitionReader);
?}


加載資源、加載之前設置的xml配置文件資源
reader.loadBeanDefinitions(configLocations); 循環加載xml文件的Bean,返回Bean總個數,查看加載方法。

3.1 加載入口
? ?

調用AbstractBeanDefinitionReader中的loadBeanDefinitions(String... locations)方法

? ? 3.2 將xml文件轉化為Resource流對象

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//獲取之前設置的加載起
?????ResourceLoader resourceLoader = this.getResourceLoader();
?????if (resourceLoader == null) {
?????????throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
?????} else {
?????????int count;
//通配符加載器
?????????if (resourceLoader instanceof ResourcePatternResolver) {
?????????????try {
?????????????????Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
? ? ? ? ? ? ? ? ?count = this.loadBeanDefinitions(resources);? // 讀取bean
?????????????????if (actualResources != null) {
?????????????????????Collections.addAll(actualResources, resources);
?????????????????}
? ? ? ? ? ? ? ? ?if (this.logger.isTraceEnabled()) {
?????????????????????this.logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
?????????????????}
?????????????????return count;
?????????????} catch (IOException var6) {
?????????????????throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var6);
? ? ? ? ? ? ?}
?????????} else {
? ? ? ? ? ? //讀取單個絕對路徑的配置文件
?????????????Resource resource = resourceLoader.getResource(location);
?????????????count = this.loadBeanDefinitions((Resource)resource);? //進入該方法中
?????????????if (actualResources != null) {
?????????????????actualResources.add(resource);
?????????????}
?????????????if (this.logger.isTraceEnabled()) {
?????????????????this.logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
?????????????}
?????????????return count;
?????????}
?????}
?}

主要步驟:
? ? 1、獲取加載起中的Resource[]數組
? ? 2、加載資源中的Bean,返回加載數量? ?
?3.3?解析xml中的內容并注冊bean
? ??????在XmlBeanDefinitionReader中,通過Document doc = doLoadDocument(inputSource, resource),讀取Resource流的內容,并封裝為Document 對象。然后調用doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法加載bean。

loadBeanDefinitions

? ? 3.4 將XML中的標簽內容封裝為Element對象
? ??????調用DefaultBeanDefinitionDocumentReader中registerBeanDefinitions(Document doc, XmlReaderContext readerContext)方法。最終,通過委派方式,將Element對象交由BeanDefinitionParserDelegate解析

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
?????this.readerContext = readerContext;
?????this.doRegisterBeanDefinitions(doc.getDocumentElement());
?}? ??

protected void doRegisterBeanDefinitions(Element root) {
?????BeanDefinitionParserDelegate parent = this.delegate;
?????this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
?????if (this.delegate.isDefaultNamespace(root)) {
?????????String profileSpec = root.getAttribute("profile");
?????????if (StringUtils.hasText(profileSpec)) {
?????????????String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
?????????????if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
?????????????????if (this.logger.isDebugEnabled()) {
?????????????????????this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
?????????????????}
?????????????????return;
? ? ? ? ? ? ? }
?????????}
?????}
?????this.preProcessXml(root);? ?//預處理XML
?????this.parseBeanDefinitions(root, this.delegate);? // 解析XML中的<bean>標簽
?????this.postProcessXml(root);? //后處理XML
?????this.delegate = parent;
?}

// 解析XML中<bean>標簽
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
?????if (delegate.isDefaultNamespace(root)) {
?????????NodeList nl = root.getChildNodes();? //獲取xml中的所有子標簽節點
?????????for(int i = 0; i < nl.getLength(); ++i) {
?????????????Node node = nl.item(i);
?????????????if (node instanceof Element) {? ?//判斷是否是<bean>標簽
?????????????????Element ele = (Element)node;? // 將xml標簽封裝為Element元素
?????????????????if (delegate.isDefaultNamespace(ele)) {
?????????????????????this.parseDefaultElement(ele, delegate);? //解析xml標簽元素
?????????????????} else {
?????????????????????delegate.parseCustomElement(ele);
?????????????????}
?????????????}
?????????}
?????} else {
?????????delegate.parseCustomElement(root);
?????}
?}


private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
?????if (delegate.nodeNameEquals(ele, "import")) {? ? ? ? //解析引入其他XML節點
?????????this.importBeanDefinitionResource(ele);
?????} else if (delegate.nodeNameEquals(ele, "alias")) {? // 解析別名節點
?????????this.processAliasRegistration(ele);
?????} else if (delegate.nodeNameEquals(ele, "bean")) {? //解析bean節點
?????????this.processBeanDefinition(ele, delegate);? ?
?????} else if (delegate.nodeNameEquals(ele, "beans")) {? //解析嵌套bean節點
?????????this.doRegisterBeanDefinitions(ele);
?????}
?}

? ? 3.5 解析BeanDefinitionElement
? ??????在BeanDefinitionParserDelegate中通過parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)方法,對xml文件中定義的bean做解析。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
?????String id = ele.getAttribute("id");
?????String nameAttr = ele.getAttribute("name");
?????List<String> aliases = new ArrayList();
?????if (StringUtils.hasLength(nameAttr)) {
?????????String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
?????????aliases.addAll(Arrays.asList(nameArr));
?????}
?????String beanName = id;
?????if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
?????????beanName = (String)aliases.remove(0);
?????????if (this.logger.isTraceEnabled()) {
?????????????this.logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
?????????}
?????}
//檢查id是否是唯一值
?????if (containingBean == null) {
?????????this.checkNameUniqueness(beanName, aliases, ele);
?????}
//通過id解析得到bean Definition實例
?????AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
?????if (beanDefinition != null) {
?????????if (!StringUtils.hasText(beanName)) {
?????????????try {
?????????????????if (containingBean != null) {
?????????????????????beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
?????????????????} else {
?????????????????????beanName = this.readerContext.generateBeanName(beanDefinition);
?????????????????????String beanClassName = beanDefinition.getBeanClassName();
?????????????????????if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
?????????????????????????aliases.add(beanClassName);
?????????????????????}
?????????????????}
?????????????????if (this.logger.isTraceEnabled()) {
?????????????????????this.logger.trace("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
?????????????????}
?????????????} catch (Exception var9) {
?????????????????this.error(var9.getMessage(), ele);
?????????????????return null;
?????????????}
?????????}
?????????String[] aliasesArray = StringUtils.toStringArray(aliases);
?????????return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
?????} else {
?????????return null;
?????}
?}


//通過id解析得到bean Definition實例方法
@Nullable
?public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
//通過id實例化BeanFactory對象,并將它放入當前的BeanDefinitionParserDelegate對象的parseState對象屬性的LinkedList屬性中
?????this.parseState.push(new BeanEntry(beanName));
//獲取<bean>標簽中定義的Class屬性
?????String className = null;
?????if (ele.hasAttribute("class")) {
?????????className = ele.getAttribute("class").trim();
?????}
//獲取是否存在父類,及其信息
?????String parent = null;
?????if (ele.hasAttribute("parent")) {
?????????parent = ele.getAttribute("parent");
?????}
?????try {
//通過<bean>標簽中定義的類信息創建一個bean
?????????AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
// 解析bean對象的實例化相關信息(作用域、懶加載、依賴關系等)
//既<bean ... scope="singleton" lazy-init="true" primary="true" depends-on="emp" init-method="" ...>這些屬性
?????????this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
?????????bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
//j解析bean中源數據的信息
?????????this.parseMetaElements(ele, bd);
//解析覆蓋的方法
?????????this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
?????????this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析依賴注入信息
?????????this.parseConstructorArgElements(ele, bd);? //解析構造器參數注入元素
?????????this.parsePropertyElements(ele, bd);? ?//解析屬性(set)注入元素
?????????this.parseQualifierElements(ele, bd);? ?//解析限定(Qualifier)注入元素:當容器中有多個類型相同的bean時,想要用一個屬性置頂他們其中的一個進行匹配,常見的是@Autowired聯合@Qualifier("beanID")的方式
?????????bd.setResource(this.readerContext.getResource());
?????????bd.setSource(this.extractSource(ele));
?????????AbstractBeanDefinition var7 = bd;
?????????return var7;
?????} catch (ClassNotFoundException var13) {
?????????this.error("Bean class [" + className + "] not found", ele, var13);
?????} catch (NoClassDefFoundError var14) {
?????????this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
?????} catch (Throwable var15) {
?????????this.error("Unexpected failure during bean definition parsing", ele, var15);
?????} finally {
?????????this.parseState.pop();
?????}
?????return null;
?}


//創建一個bean
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName) throws ClassNotFoundException {?????
????return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());?
}

public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
?????GenericBeanDefinition bd = new GenericBeanDefinition();
?????bd.setParentName(parentName);
?????if (className != null) {
?????????if (classLoader != null) {
//如果使用自定義的classLoader—類加載器,則通過反射加載類信息
?????????????bd.setBeanClass(ClassUtils.forName(className, classLoader));
?????????} else {
?????????????bd.setBeanClassName(className);
?????????}
? ? ?}
?????return bd;
?}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容