領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多最近我似乎一直專注於建立 Spring XML 名稱空間。在 XSD 和 Spring 兩方面,為了找到建立解析器的良好模式,經歷了大量的嘗試和錯誤。我遇到的最大困惑之一是 AbstractBeanDefinitionParser 層次結構。目前它的文件不是特別好(但有一個 JIRA 問題,所以會在 GA 之前修復),所以我將為您介紹您的選擇、它們的作用以及如何使用它們。
我將從最具體的情況開始,然後逐步轉向最概括的情況,以展示如何在需要時獲得更多功能。如果您想跳過示例,直接檢視摘要,請在此處檢視。
<util:properties location="..." />
public class PropertiesFactoryBean extends PropertiesLoaderSupport
implements FactoryBean, InitializingBean {
...
public void setLocation(Resource location) {
this.locations = new Resource[] {location};
}
...
}
您會注意到 util:properties 標籤上的 location 屬性與 PropertiesFactoryBean 型別的 Java bean 屬性相匹配。AbstractSimpleBeanDefinitionParser 會自動提取屬性並將其對映到該屬性。要實現此行為,您只需要實現一個名為 getBeanClass() 的方法。因此,此示例的實現如下:
public class PropertiesBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
protected Class getBeanClass(Element element) {
return PropertiesFactoryBean.class;
}
}
與所有抽象解析器一樣,框架在後臺為您處理 bean 定義的建立,並將其註冊到應用程式上下文中。
<tx:advice>
<tx:attributes>
<tx:method name="get*" read-only="false" />
</tx:attributes>
</tx:advice>
public class TransactionInterceptor extends TransactionAspectSupport
implements MethodInterceptor, Serializable {
...
public void setTransactionAttributes(Properties transactionAttributes) {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
this.transactionAttributeSource = tas;
}
...
}
正如您所見,tx:advice 具有複雜的巢狀結構,這不像我們之前看到的那麼一對一對映。然而,使用 AbstractSingleBeanDefinitionParser,您可以進行任意的 DOM 結構遍歷,如下所示:
class TxAdviceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
...
protected void doParse(Element element, BeanDefinitionBuilder builder) {
// Set the transaction manager property.
builder.addPropertyReference(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY,
element.getAttribute(TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE));
List txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES);
if (txAttributes.size() > 1) {
throw new IllegalStateException("Element 'attributes' is allowed at most once inside element 'advice'");
}
else if (txAttributes.size() == 1) {
// Using attributes source.
parseAttributes((Element) txAttributes.get(0), builder);
}
else {
// Assume annotations source.
Class sourceClass = TxNamespaceUtils.getAnnotationTransactionAttributeSourceClass();
builder.addPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, new RootBeanDefinition(sourceClass));
}
}
...
}
您可以看到,我們正在檢查 DOM 並根據它做出複雜的 bean 定義決策。正如我之前所說的,我認為這將是用於 bean 定義解析的最常用的支援類之一。
<tx:annotation-driven />
熟悉 Spring 2.0 及其新名稱空間的人應該會認識到這個標籤,它是一個單行語句,可以自動檢測 @Transactional 註解並代理包含它們的類。現在,在底層,建立了與 Spring 1.2.8 中 DefaultAutoProxyCreator 行為相同的 bean 定義集;總共 4 個 bean。那麼這種行為的示例是什麼樣的呢?
class AnnotationDrivenBeanDefinitionParser extends AbstractBeanDefinitionParser {
...
protected BeanDefinition parseInternal(Element element, ParserContext parserContext) {
// Register the APC if needed.
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext);
boolean proxyTargetClass = TRUE.equals(element.getAttribute(PROXY_TARGET_CLASS));
if (proxyTargetClass) {
AopNamespaceUtils.forceAutoProxyCreatorToUseClassProxying(parserContext.getRegistry());
}
String transactionManagerName = element.getAttribute(TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE);
Class sourceClass = TxNamespaceUtils.getAnnotationTransactionAttributeSourceClass();
// Create the TransactionInterceptor definition
RootBeanDefinition interceptorDefinition = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDefinition.getPropertyValues().addPropertyValue(
TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY, new RuntimeBeanReference(transactionManagerName));
interceptorDefinition.getPropertyValues().addPropertyValue(
TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, new RootBeanDefinition(sourceClass));
// Create the TransactionAttributeSourceAdvisor definition.
RootBeanDefinition advisorDefinition = new RootBeanDefinition(TransactionAttributeSourceAdvisor.class);
advisorDefinition.getPropertyValues().addPropertyValue(TRANSACTION_INTERCEPTOR, interceptorDefinition);
return advisorDefinition;
}
...
}
這裡最大的新增功能是能夠訪問 ParserContext。此上下文使您能夠將子元素委託給名稱空間處理器,讓它們的解析器建立並返回 bean 定義。這實際上是我非常喜歡的功能之一。ParserContext 還允許您建立自己的定義並直接註冊它們,如果您願意的話。
好了,這就是 bean 定義解析的快速入門。我想知道有多少人在這樣做?您為哪些內容建立了名稱空間,以及您是如何使用解析器層次結構的?在評論區發表您的看法。誰知道呢,您的經驗和建議可能會轉化為 JIRA 中的一個增強功能...