spring 自定义解析类

Posted R.Z

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring 自定义解析类相关的知识,希望对你有一定的参考价值。

  • 设计配置属性和JavaBean
  • 编写XSD文件
  • 编写NamespaceHandler和BeanDefinitionParser完成解析工作
  • 编写spring.handlers和spring.schemas串联起所有部件
  • 在Bean文件中应用

 

 

会用到NamespaceHandler和BeanDefinitionParser这两个概念。具体说来NamespaceHandler会根据schema和节点名找到某个BeanDefinitionParser,然后由BeanDefinitionParser完成具体的解析工作。因此需要分别完成NamespaceHandler和BeanDefinitionParser的实现类,Spring提供了默认实现类NamespaceHandlerSupport和AbstractSingleBeanDefinitionParser,简单的方式就是去继承这两个类。
先看个示例吧。spring  scheduling命名空间下的   scheduled-tasks 解析。

/**
* Parser for the ‘scheduled-tasks‘ element of the scheduling namespace.
*
* @author Mark Fisher
* @author Chris Beams
* @since 3.0
*/
public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

private static final String ELEMENT_SCHEDULED = "scheduled";

private static final long ZERO_INITIAL_DELAY = 0;

//解析方法
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.setLazyInit(false); // lazy scheduled tasks are a contradiction in terms -> force to false
ManagedList<RuntimeBeanReference> cronTaskList = new ManagedList<>();
ManagedList<RuntimeBeanReference> fixedDelayTaskList = new ManagedList<>();
ManagedList<RuntimeBeanReference> fixedRateTaskList = new ManagedList<>();
ManagedList<RuntimeBeanReference> triggerTaskList = new ManagedList<>();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if (!isScheduledElement(child, parserContext)) {
continue;
}
Element taskElement = (Element) child;
String ref = taskElement.getAttribute("ref");
String method = taskElement.getAttribute("method");

// Check that ‘ref‘ and ‘method‘ are specified
if (!StringUtils.hasText(ref) || !StringUtils.hasText(method)) {
parserContext.getReaderContext().error("Both ‘ref‘ and ‘method‘ are required", taskElement);
// Continue with the possible next task element
continue;
}

String cronAttribute = taskElement.getAttribute("cron");
String fixedDelayAttribute = taskElement.getAttribute("fixed-delay");
String fixedRateAttribute = taskElement.getAttribute("fixed-rate");
String triggerAttribute = taskElement.getAttribute("trigger");
String initialDelayAttribute = taskElement.getAttribute("initial-delay");

boolean hasCronAttribute = StringUtils.hasText(cronAttribute);
boolean hasFixedDelayAttribute = StringUtils.hasText(fixedDelayAttribute);
boolean hasFixedRateAttribute = StringUtils.hasText(fixedRateAttribute);
boolean hasTriggerAttribute = StringUtils.hasText(triggerAttribute);
boolean hasInitialDelayAttribute = StringUtils.hasText(initialDelayAttribute);

if (!(hasCronAttribute || hasFixedDelayAttribute || hasFixedRateAttribute || hasTriggerAttribute)) {
parserContext.getReaderContext().error(
"one of the ‘cron‘, ‘fixed-delay‘, ‘fixed-rate‘, or ‘trigger‘ attributes is required", taskElement);
continue; // with the possible next task element
}

if (hasInitialDelayAttribute && (hasCronAttribute || hasTriggerAttribute)) {
parserContext.getReaderContext().error(
"the ‘initial-delay‘ attribute may not be used with cron and trigger tasks", taskElement);
continue; // with the possible next task element
}

String runnableName =
runnableReference(ref, method, taskElement, parserContext).getBeanName();

if (hasFixedDelayAttribute) {
fixedDelayTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedDelayAttribute, taskElement, parserContext));
}
if (hasFixedRateAttribute) {
fixedRateTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedRateAttribute, taskElement, parserContext));
}
if (hasCronAttribute) {
cronTaskList.add(cronTaskReference(runnableName, cronAttribute,
taskElement, parserContext));
}
if (hasTriggerAttribute) {
String triggerName = new RuntimeBeanReference(triggerAttribute).getBeanName();
triggerTaskList.add(triggerTaskReference(runnableName, triggerName,
taskElement, parserContext));
}
}
String schedulerRef = element.getAttribute("scheduler");
if (StringUtils.hasText(schedulerRef)) {
builder.addPropertyReference("taskScheduler", schedulerRef);
}
builder.addPropertyValue("cronTasksList", cronTaskList);
builder.addPropertyValue("fixedDelayTasksList", fixedDelayTaskList);
builder.addPropertyValue("fixedRateTasksList", fixedRateTaskList);
builder.addPropertyValue("triggerTasksList", triggerTaskList);
}

以上就是默认的xml解析

注解解析的类是 AnnotationDrivenBeanDefinitionParser


/**
* Parser for the ‘annotation-driven‘ element of the ‘task‘ namespace.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Ramnivas Laddad
* @author Chris Beams
* @author Stephane Nicoll
* @since 3.0
*/
public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {

private static final String ASYNC_EXECUTION_ASPECT_CLASS_NAME =
"org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect";



//解析方法

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);

// Register component for the surrounding <task:annotation-driven> element.
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);

// Nest the concrete post-processor bean in the surrounding component.
BeanDefinitionRegistry registry = parserContext.getRegistry();

String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerAsyncExecutionAspect(element, parserContext);
}
else {
// mode="proxy"
if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {
parserContext.getReaderContext().error(
"Only one AsyncAnnotationBeanPostProcessor may exist within the context.", source);
}
else {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {
builder.addPropertyReference("executor", executor);
}
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {
builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
if (Boolean.valueOf(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {
builder.addPropertyValue("proxyTargetClass", true);
}
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
}
}

if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
parserContext.getReaderContext().error(
"Only one ScheduledAnnotationBeanPostProcessor may exist within the context.", source);
}
else {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
String scheduler = element.getAttribute("scheduler");
if (StringUtils.hasText(scheduler)) {
builder.addPropertyReference("scheduler", scheduler);
}
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
}

// Finally register the composite component.
parserContext.popAndRegisterContainingComponent();

return null;
}






以上是关于spring 自定义解析类的主要内容,如果未能解决你的问题,请参考以下文章

spring自定义标签

Spring 源码分析--自定义标签的解析

dubbo系列dubbo启动过程源码解析

Dubbbo spring配置方式解析

Dubbbo spring配置方式解析

Spring源码解析-自定义标签解析和SPI机制-3