更上一層樓
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;
}
...
}
這裡最大的補充是能夠訪問 <span style="font-family:courier>ParserContext。 此上下文使你能夠將子元素委託給名稱空間處理程式,並讓他們的解析器建立和返回 bean 定義。 它實際上是我非常喜歡的功能之一。 <span style="font-family:courier>ParserContext 還允許你建立自己的定義並直接註冊它們(如果你願意)。
所以這就是它,bean 定義解析的快速介紹。 我想知道的是有多少人正在這樣做? 你已經為哪些內容建立了名稱空間,以及你如何使用解析器層次結構? 使用評論來表達你的聲音。 誰知道呢,你的經驗和建議可能會作為增強功能進入 JIRA...