源码分析ElasticJob前置篇之自定义Spring命名空间

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 源码分析ElasticJob前置篇之自定义Spring命名空间

在Spring中使用Elastic-Job的示例如下


1<!--配置作业注册中心 -->
2<reg:zookeeper id="regCenter" server-lists="${gis.dubbo.registry.address}"
3      namespace="example-job" base-sleep-time-milliseconds="${elasticJob.zkBaseSleepTimeMilliseconds}"
4      max-sleep-time-milliseconds="${elasticJob.zkMaxSleepTimeMilliseconds}"
5      max-retries="${elasticJob.zkMaxRetries}" />


本文将通过<reg:zookeeper/>来讲解如何在Spring中自定义标签,其中更是包含了ElasticJob的启动入口。


Spring自定义标签的实现步骤主要包括:


  1. 在META-INF目录下定义xsd文件
  2. 定义NamespaceHandlerSupport实现类
  3. 注册BeanDefinitionParser
  4. 将自定义的NameSpace、xsd文件纳入Spring的管理范围内


下面将详细介绍各个步骤的实现细节。


1、在META-INF目录下定义xsd文件

Elastic-Job reg.xsd文件定义如下


1<?xml version="1.0" encoding="UTF-8"?>
 2<xsd:schema xmlns="http://www.dangdang.com/schema/ddframe/reg"
 3        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 4        xmlns:beans="http://www.springframework.org/schema/beans"
 5        targetNamespace="http://www.dangdang.com/schema/ddframe/reg"
 6        elementFormDefault="qualified"
 7        attributeFormDefault="unqualified">
 8    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
 9
10    <xsd:element name="zookeeper">
11        <xsd:complexType>
12            <xsd:complexContent>
13                <xsd:extension base="beans:identifiedType">
14                    <xsd:attribute name="server-lists" type="xsd:string" use="required" />
15                    <xsd:attribute name="namespace" type="xsd:string" use="required" />
16                    <xsd:attribute name="base-sleep-time-milliseconds" type="xsd:string" />
17                    <xsd:attribute name="max-sleep-time-milliseconds" type="xsd:string" />
18                    <xsd:attribute name="max-retries" type="xsd:string" />
19                    <xsd:attribute name="session-timeout-milliseconds" type="xsd:string" />
20                    <xsd:attribute name="connection-timeout-milliseconds" type="xsd:string" />
21                    <xsd:attribute name="digest" type="xsd:string" />
22                </xsd:extension>
23            </xsd:complexContent>
24        </xsd:complexType>
25    </xsd:element>
26</xsd:schema>

下面对文档中的标签进行详细阐述。


xsd:schema元素详解


  • xmlns="http://www.dangdang.com/schema/ddframe/reg"
    定义默认命名空间。如果元素没有前缀,则元素的命名空间为xmlns定义的命名空间。
  • xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    引入xsd命名空间,该命名空间的URL为http://www.w3.org/2001/XMLSchema,元素前缀为xsd。
  • xmlns:beans="http://www.springframework.org/schema/beans"
    引入Spring beans命名空间。xmln-s:xx=""表示引入已存在的命名空间。
  • targetNamespace="http://www.dangdang.com/schema/ddframe/reg"
    定义该命名空间所对应的url,在xml文件中如果要使用,其xsi:schema-Location定义reg.xsd路径时必须以该值为键,例如应用程序中定义ela-sticjob的xml文件如下:

858b94dacdc46ada82f6e7f52fcd3fc1.jpg

  • elementFormDefault="qualified"


指定该xsd所对应的实例xml文件,引用该文件中定义的元素必须被命名空间所限定。例如在reg.xsd中定义了zookeeper这个元素,那么在spring-elastic-job.xml(xml文档实例)中使用该元素来定义时,必须这样写


<reg:zookeeper id="regCenter"/>
  • attributeFormDefault
    指定该xsd所对应的示例xml文件,引用该文件中定义的元素属性是否需要被限定,unqualified表示不需要被限定。如果设置为qualified:

   则错误写法:

1<reg:zookeeper id="regCenter" server-lists="" …/>


   其正确写法:

1<reg:zookeeper id="regCenter" reg:server-lists="" …/>


xsd:import


导入其他命名空间,<xsd:import name-space="http://www.springframework.org/schema/beans"/>表示导入spirng bea-ns命名空间。如果目标命名空间定义文件中没有指定targetNamespace,则需要使用include导入其他命令空间,例如:<import namespace="tnsB" schema-Lcation="B.xsd">


xsd:element


<xsd:element name="zookeeper">:定义zookeeper元素,xml文件中可以使用<reg:zookeeper/>。


xsd:complexType


<xsd:complexType>,zookeeper元素的类型为复杂类型。


xsd:extension


<xsd:extension base="beans:identifiedType">

继承beans命名空间identifiedType的属性(id 定义)。


2、定义NamespaceHandlerSupport实现类。


继承NamespaceHandlerSupport,重写init方法。


1public final class RegNamespaceHandler extends NamespaceHandlerSupport {
2
3    @Override
4    public void init() {
5        registerBeanDefinitionParser("zookeeper", new ZookeeperBeanDefinitionParser());
6    }
7}


3、注册BeanDefinitionParser


注册BeanDefinitionParser解析标签,并初始化实例。


ZookeeperBeanDefinitionParser源码:

1public final class ZookeeperBeanDefinitionParser extends AbstractBeanDefinitionParser {
 2    @Override
 3    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {
 4        BeanDefinitionBuilder result = BeanDefinitionBuilder.rootBeanDefinition(ZookeeperRegistryCenter.class);// @1
 5        result.addConstructorArgValue(buildZookeeperConfigurationBeanDefinition(element));  // @2
 6        result.setInitMethodName("init");   // @3
 7        return result.getBeanDefinition();  // @4
 8    }
 9 //  ....省略部分代码
10}

代码@1:构建器模式,表明标签对应的实体Bean对象为ZookeeperRegistryCe-nter,zk注册中心实现类。

代码@2:最终创建ZookeeperRegistr-yCenter,其属性通过构造方法注入。

代码@3:设置initMethod,相当于配置文件的init-method属性,表明在创建实例时将调用该方法进行初始化。

代码@4:返回AbstractBeanDefinition对象,方便Spring针对该配置创建实例。


接下来重点分析一下buildZookeeperCo-nfigurationBeanDefinition的实现细节:

1private AbstractBeanDefinition buildZookeeperConfigurationBeanDefinition(final Element element) {
 2        BeanDefinitionBuilder configuration = BeanDefinitionBuilder.rootBeanDefinition(ZookeeperConfiguration.class);
 3        configuration.addConstructorArgValue(element.getAttribute("server-lists"));
 4        configuration.addConstructorArgValue(element.getAttribute("namespace"));
 5        addPropertyValueIfNotEmpty("base-sleep-time-milliseconds", "baseSleepTimeMilliseconds", element, configuration);
 6        addPropertyValueIfNotEmpty("max-sleep-time-milliseconds", "maxSleepTimeMilliseconds", element, configuration);
 7        addPropertyValueIfNotEmpty("max-retries", "maxRetries", element, configuration);
 8        addPropertyValueIfNotEmpty("session-timeout-milliseconds", "sessionTimeoutMilliseconds", element, configuration);
 9        addPropertyValueIfNotEmpty("connection-timeout-milliseconds", "connectionTimeoutMilliseconds", element, configuration);
10        addPropertyValueIfNotEmpty("digest", "digest", element, configuration);
11        return configuration.getBeanDefinition();
12    }

上述代码比较简单明了,主要是根据<r-eg:zookeeper/>标签,获取element的s-erver-lists、namespace属性,使用Zoo-keeperConfiguration构造方式初始化Zo-keeperConfiguration属性,然后解析其他非空属性并使用set方法注入到Zook-eeperConfiguration实例中。


4、将自定义的NameSpace、xsd文件纳入Spring的管理范围内。


在META-INF目录下创建spring.handle-rs、spring.schemas文件,其内容分别是:


  • spring.handlers
1http://www.dangdang.com/schema/ddframe/reg=io.elasticjob.lite.spring.reg.handler.RegNamespaceHandler


其定义格式:xsd文件中定义的targetN-amespace=自定义namespace实现类。


  • spring.schemas:
1http\://www.dangdang.com/schema/ddframe/reg/reg.xsd=META-INF/namespace/reg.xsd


其定义格式:xsd文件uri = xsd文件目录。


xml中xsi:schemaLocation取的就是该文件中的内容,其示例如下:

1xsi:schemaLocation="http\://www.dangdang.com/schema/ddframe/reg/reg.xsd=META-INF/namespace/reg.xsd",

上述简单的通过elasticjob命名空间的引入示例展示如何在Spring自定义标签,也引出了Elasticjob的启动入口,下文将详细介绍ElasticJob Spring方式的启动流程。


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
1月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
56 1
|
3天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
37 14
|
23天前
|
安全 Java 应用服务中间件
如何将Spring Boot应用程序运行到自定义端口
如何将Spring Boot应用程序运行到自定义端口
34 0
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
34 1
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
32 1
|
2月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
25 0
|
4月前
|
监控 安全 Java
【开发者必备】Spring Boot中自定义注解与处理器的神奇魔力:一键解锁代码新高度!
【8月更文挑战第29天】本文介绍如何在Spring Boot中利用自定义注解与处理器增强应用功能。通过定义如`@CustomProcessor`注解并结合`BeanPostProcessor`实现特定逻辑处理,如业务逻辑封装、配置管理及元数据分析等,从而提升代码整洁度与可维护性。文章详细展示了从注解定义、处理器编写到实际应用的具体步骤,并提供了实战案例,帮助开发者更好地理解和运用这一强大特性,以实现代码的高效组织与优化。
230 0
|
4月前
|
存储 Java API
|
4月前
|
安全 搜索推荐 Java
下一篇
DataWorks