免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
[轉(zhuǎn)] Spring4.3.x 淺析xml配置的解析過程(6)property-placeholder和property-override的區(qū)別

在上一篇解析自定義命名空間的標(biāo)簽 中,我們已經(jīng)知道解析自定義命名空間的標(biāo)簽需要用到NamespaceHandler接口的實(shí)現(xiàn)類,并且知道spring是如何獲取命名空間對應(yīng)的命名空間處理器對象的。因此我們很容易就能在spring-context包下的META-INF/spring.handlers文件中找到http://www.springframework.org/schema/context命名空間(即本文說的context命名空間)的處理器org.springframework.context.config.ContextNamespaceHandler,下面是ContextNamespaceHandler類的源碼。

public class ContextNamespaceHandler extends NamespaceHandlerSupport {    @Override    public void init() {        registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());        registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());        registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());        registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());        registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());        registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());        registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());    }}

ContextNamespaceHandler 實(shí)現(xiàn)了NamespaceHandler接口的init方法來為context命名空間下的標(biāo)簽注冊解析器BeanDefinitionParser對象。

Spring context命名空間有property-placeholder、property-override、annotation-config、component-scan、load-time-weaver、spring-configured、mbean-export和mbean-server 8個標(biāo)簽。這8個標(biāo)簽都有一個BeanDefinitionParser實(shí)現(xiàn)類與之對應(yīng)。這一節(jié)我們分別探討property-placeholder和property-override標(biāo)簽的解析。

解析property-placeholder標(biāo)簽


property-placeholder標(biāo)簽用于加載property屬性文件。如果bean的<property>value值與屬性文件中的某個值相同,那么,默認(rèn)情況下,定義<property>的value值可以使用表達(dá)式“${key}”,其中key為屬性文件中=左邊的字符串。

property-placeholder標(biāo)簽對應(yīng)的BeanDefinitionParser實(shí)現(xiàn)類是PropertyPlaceholderBeanDefinitionParser,下面是這個類的繼承結(jié)構(gòu)。 

AbstractBeanDefinitionParser是PropertyPlaceholderBeanDefinitionParser類的一個抽象父類,它實(shí)現(xiàn)了BeanDefinitionParser接口的parse(Element element, ParserContext parserContext)方法,代碼如下。

    @Override    public final BeanDefinition parse(Element element, ParserContext parserContext) {        // 調(diào)用抽象方法parseInternal(Element element, ParserContext parserContext)        // 這個方法有子類實(shí)現(xiàn),把解析指定Element對象的任務(wù)交給子類完成        AbstractBeanDefinition definition = parseInternal(element, parserContext);        if (definition != null && !parserContext.isNested()) {            try {                // 解析并未bean生成一個id值                String id = resolveId(element, definition, parserContext);                if (!StringUtils.hasText(id)) {                    parserContext.getReaderContext().error(                            "Id is required for element '" + parserContext.getDelegate().getLocalName(element)                                    + "' when used as a top-level tag", element);                }                String[] aliases = null;                // 檢測是否應(yīng)該把name屬性作為bean的別名,默認(rèn)為true                // 子類可以重寫shouldParseNameAsAliases()來決定                if (shouldParseNameAsAliases()) {                    // 獲取bean的別名                    String name = element.getAttribute("name");                    if (StringUtils.hasLength(name)) {                        aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));                    }                }                // 創(chuàng)建BeanDefinitionHolder對象                BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);                // 注冊BeanDefintion                registerBeanDefinition(holder, parserContext.getRegistry());                if (shouldFireEvents()) {                    BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);                    postProcessComponentDefinition(componentDefinition);                    parserContext.registerComponent(componentDefinition);                }            } catch (BeanDefinitionStoreException ex) {                parserContext.getReaderContext().error(ex.getMessage(), element);                return null;            }        }        return definition;    }

AbstractBeanDefinitionParser的parse方法,首先把解析節(jié)點(diǎn)的任務(wù)交給子類來完成,子類需要實(shí)現(xiàn)parseInternal(Element element, ParserContext parserContext)方法并返回一個AbstractBeanDefinition 對象;然后根據(jù)需要設(shè)置bean的id和別名;最后創(chuàng)建并注冊BeanDefinitionHolder對象。下面我們重點(diǎn)看parseInternal方法,在PropertyPlaceholderBeanDefinitionParser的繼承體系中,parseInternal方法的實(shí)現(xiàn)在AbstractSingleBeanDefinitionParser類中,代碼如下。

    @Override    protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {        // 創(chuàng)建BeanDefinitionBuilder對象,這個對象只是代理了一個GenericBeanDefinition對象        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();        String parentName = getParentName(element);        if (parentName != null) {            builder.getRawBeanDefinition().setParentName(parentName);        }        // 獲取要實(shí)例化bean的類對象,默認(rèn)為null,一般由子類提供。        Class<?> beanClass = getBeanClass(element);        if (beanClass != null) {            builder.getRawBeanDefinition().setBeanClass(beanClass);        } else {            String beanClassName = getBeanClassName(element);            if (beanClassName != null) {                builder.getRawBeanDefinition().setBeanClassName(beanClassName);            }        }        builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));        if (parserContext.isNested()) {            // 嵌套的bean定義,必須和外層的bean在同一個作用域            builder.setScope(parserContext.getContainingBeanDefinition().getScope());        }        if (parserContext.isDefaultLazyInit()) {            // 默認(rèn)為延遲加載            builder.setLazyInit(true);        }        // 把繼續(xù)解析標(biāo)簽的任務(wù)交給子類        doParse(element, parserContext, builder);        return builder.getBeanDefinition();    }

AbstractSingleBeanDefinitionParser的parseInternal方法創(chuàng)建了一個BeanDefinitionBuilder對象,這個對象只是代理了GenericBeanDefinition對象,以簡化對GenericBeanDefinition對象的操作,然后就是一些基本的配置,這在代碼中已經(jīng)體現(xiàn)了。parseInternal也并未對節(jié)點(diǎn)做實(shí)質(zhì)性的操作,它只調(diào)用為子類創(chuàng)建的一些鉤子方法,這些方法有:

用于獲取要實(shí)例化bean的類(Class)對象或者類全名稱的方法:

    protected Class<?> getBeanClass(Element element) {        return null;    }    protected String getBeanClassName(Element element) {        return null;    }

以及用于進(jìn)一步解析節(jié)點(diǎn)的方法

    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {        doParse(element, builder);    }    protected void doParse(Element element, BeanDefinitionBuilder builder) {    }

property-placeholder標(biāo)簽的解析器PropertyPlaceholderBeanDefinitionParser類重寫了上面2組方法中的getBeanClass(Element element)方法和doParse(Element element, BeanDefinitionBuilder builder) 方法。 
下面是getBeanClass(Element element)方法的源碼。

    @Override    protected Class<?> getBeanClass(Element element) {        // 從spring3.1開始system-properties-mode屬性的默認(rèn)值就為ENVIRONMENT,不再是FALLBACK        if ("ENVIRONMENT".equals(element.getAttribute("system-properties-mode"))) {            // PropertySourcesPlaceholderConfigurer對象可以從上下文的環(huán)境對象中獲取屬性值            return PropertySourcesPlaceholderConfigurer.class;        }        return PropertyPlaceholderConfigurer.class;    }

說明:PropertyPlaceholderConfigurer和PropertySourcesPlaceholderConfigurer都是抽象類PlaceholderConfigurerSupport的直接子類,見總結(jié)。

下面是doParse(Element element, BeanDefinitionBuilder builder)方法的源碼。

    @Override    protected void doParse(Element element, BeanDefinitionBuilder builder) {        super.doParse(element, builder);        builder.addPropertyValue("ignoreUnresolvablePlaceholders",                Boolean.valueOf(element.getAttribute("ignore-unresolvable")));        String systemPropertiesModeName = element.getAttribute("system-properties-mode");        if (StringUtils.hasLength(systemPropertiesModeName) &&                !systemPropertiesModeName.equals("system-properties-mode")) {            builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);        }        // 指定一個分隔符用于分隔默認(rèn)值,默認(rèn)為英文冒號:        // 比如${user.name:chyohn},如果user.name沒有在屬性文件中定義,則使用默認(rèn)值chyohn        // 假設(shè)設(shè)置的分隔符為英文?,則上面的定義應(yīng)該為${name?choyhn}        if (element.hasAttribute("value-separator")) {            builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));        }        // 設(shè)置是否允許trim獲取到的屬性值,默認(rèn)為false        if (element.hasAttribute("trim-values")) {            builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));        }        // 指定一個值用于表示null,比如指定的為hasNull,        // 如果某一個屬性值定義的時候?yàn)閔aveNull,那么生成的bean的這個屬性真正值就是null        if (element.hasAttribute("null-value")) {            builder.addPropertyValue("nullValue", element.getAttribute("null-value"));        }    }

PropertyPlaceholderBeanDefinitionParser類的doParse方法首先調(diào)用父類AbstractPropertyLoadingBeanDefinitionParser的doParse方法,然后根據(jù)節(jié)點(diǎn)配置的屬性值來修改PlaceholderConfigurerSupport的屬性值。這里我們在繼續(xù)看看AbstractPropertyLoadingBeanDefinitionParser的doParse方法源代碼。

    @Override    protected void doParse(Element element, BeanDefinitionBuilder builder) {        // 獲取屬性文件的地址參數(shù)        String location = element.getAttribute("location");        if (StringUtils.hasLength(location)) {            // 如果有多個屬性文件,每個屬性文件可以使用英文逗號隔開。            String[] locations = StringUtils.commaDelimitedListToStringArray(location);            builder.addPropertyValue("locations", locations);        }        // 獲取指定的Properties對象的bean名稱        // 如果local-override屬性為true,這里設(shè)置的properties將覆蓋屬性文件中的內(nèi)容        String propertiesRef = element.getAttribute("properties-ref");        if (StringUtils.hasLength(propertiesRef)) {            builder.addPropertyReference("properties", propertiesRef);        }        // 獲取屬性文件編碼        String fileEncoding = element.getAttribute("file-encoding");        if (StringUtils.hasLength(fileEncoding)) {            builder.addPropertyValue("fileEncoding", fileEncoding);        }        // 設(shè)置排序,即優(yōu)先級        String order = element.getAttribute("order");        if (StringUtils.hasLength(order)) {            builder.addPropertyValue("order", Integer.valueOf(order));        }        // 設(shè)置是否忽略指定的屬性文件不存在的錯誤,true為是        builder.addPropertyValue("ignoreResourceNotFound",                Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));        // 一般來說,屬性文件的內(nèi)容更后加載。        // 如果localOverride為true,那么PropertiesLoaderSupport的localProperties內(nèi)容就會覆蓋屬性文件中相同key的的內(nèi)容。        // 如果標(biāo)簽是property-placeholder且localOverride為true,上下文的環(huán)境對象中的數(shù)據(jù)也會覆蓋屬性文件中相同key的內(nèi)容。        // 默認(rèn)為false        builder.addPropertyValue("localOverride",                Boolean.valueOf(element.getAttribute("local-override")));        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);    }

解析property-override標(biāo)簽


property-override標(biāo)簽的作用是為xml配置文件中的bean的屬性指定最終結(jié)果。

property-override標(biāo)簽的解析器類為PropertyOverrideBeanDefinitionParser,這個類和property-placeholder標(biāo)簽的解析器類PropertyPlaceholderBeanDefinitionParser一樣是AbstractPropertyLoadingBeanDefinitionParser類的直接子類,并且PropertyOverrideBeanDefinitionParser重寫了getBeanClass(Element element)和doParse(Element element, BeanDefinitionBuilder builder)方法,代碼如下。

    @Override    protected Class<?> getBeanClass(Element element) {        return PropertyOverrideConfigurer.class;    }    @Override    protected void doParse(Element element, BeanDefinitionBuilder builder) {        super.doParse(element, builder);        // 設(shè)置忽略不正確的鍵,也就是忽略格式不正確的鍵,或者是.左邊的bean名稱不存在的鍵        // 默認(rèn)為false,表示不忽略        builder.addPropertyValue("ignoreInvalidKeys",                Boolean.valueOf(element.getAttribute("ignore-unresolvable")));    }

關(guān)于AbstractPropertyLoadingBeanDefinitionParser類在前面已經(jīng)探討過了,關(guān)于這段代碼也就沒有什么要多說的。

總結(jié)


(1)property-override和property-placeholder的不同點(diǎn)。

  • 功能不一樣,property-override標(biāo)簽的作用是為xml配置文件中的bean的屬性指定最終結(jié)果;而property-placeholder標(biāo)簽的作用是把xml配置文件中bean 的<property>標(biāo)簽的value值替換成正真的值,而且<property>標(biāo)簽的value值必須符合特定的表達(dá)式格式,默認(rèn)為“${key}”,其中key為屬性文件中的key。

  • 屬性文件內(nèi)容要求不一樣,property-override標(biāo)簽加載的properties文件中的key的格式有嚴(yán)格的要求,必須為“bean名稱.bean屬性”。如果屬性ignore-unresolvable的值為false,那么屬性文件中的bean名稱必須在當(dāng)前容器中能找到對應(yīng)的bean。

(2)property-override和property-placeholder的共同點(diǎn)。

  • 兩者都是以properties文件作為數(shù)據(jù)來源。

  • 兩者的解析器BeanDefinitionParser類都繼承自AbstractPropertyLoadingBeanDefinitionParser類。因此它們共有AbstractPropertyLoadingBeanDefinitionParser及其父類中所處理的標(biāo)簽屬性,并且這些屬性在兩個標(biāo)簽中具有相同的作用。這其實(shí)都?xì)w于它們所代表的工廠后處理器都繼承了PropertiesLoaderSupport類,具體看下面的繼承結(jié)構(gòu)圖,其中第一個是property-override的,后面兩個是property-placeholder的。 

     
     

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
編程語言Spring 源碼閱讀-2-自定義標(biāo)簽簡單使用與解析
spring源碼分析之——spring 事務(wù)管理實(shí)現(xiàn)方式 (不太清晰,不明白aop會看不懂)
Spring Security3源碼分析-authentication-manager
elementUi-一個為Vue而生的UI框架
開發(fā)者必須知道的HTML5十五大新特性
Angular封裝表單控件以及一些思想
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服