在Spring中使用Elastic-Job的示例如下:
<!--配置作业注册中心 -->
<reg:zookeeper id="regCenter" server-lists="${gis.dubbo.registry.address}" namespace="example-job" base-sleep-time-milliseconds="${elasticJob.zkBaseSleepTimeMilliseconds}" max-sleep-time-milliseconds="${elasticJob.zkMaxSleepTimeMilliseconds}" max-retries="${elasticJob.zkMaxRetries}" />
本文重点剖析如何在Spring中自定义命名空间 。
1、在META-INF目录下定义xsd文件,Elastic-Job reg.xsd文件定义如下:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.dangdang.com/schema/ddframe/reg" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.dangdang.com/schema/ddframe/reg" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:element name="zookeeper">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="server-lists" type="xsd:string" use="required" />
<xsd:attribute name="namespace" type="xsd:string" use="required" />
<xsd:attribute name="base-sleep-time-milliseconds" type="xsd:string" />
<xsd:attribute name="max-sleep-time-milliseconds" type="xsd:string" />
<xsd:attribute name="max-retries" type="xsd:string" />
<xsd:attribute name="session-timeout-milliseconds" type="xsd:string" />
<xsd:attribute name="connection-timeout-milliseconds" type="xsd:string" />
<xsd:attribute name="digest" type="xsd:string" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
1)xsd:schema元素详解
a、xmlns=”http://www.dangdang.com/schema/ddframe/reg”:定义默认命名空间。如果元素没有前缀,默认为该命名空间下的元素。
b、xmlns:xsd=”http://www.w3.org/2001/XMLSchema”,引入xsd命名空间,该命名空间的URL为http://www.w3.org/2001/XMLSchema,元素前缀为xsd。
c、xmlns:beans=”http://www.springframework.org/schema/beans”,引入Spring beans命名空间。
xmlns:xx=”“表示引入已存在的命名空间。
d、targetNamespace=”http://www.dangdang.com/schema/ddframe/reg”:定义该命名空间所对应的url,在xml文件中如果要使用,其
xsi:schemaLocation定义reg.xsd路径时必须以该值为键,例如应用程序中定义elasticjob的xml文件如下:
e、elementFormDefault=”qualified”:指定该xsd所对应的实例xml文件,引用该文件中定义的元素必须被命名空间所限定。例如在reg.xsd中定义了
zookeeper这个元素,那么在spring-elastic-job.xml(xml文档实例)中使用该元素来定义时,必须这样写:
<reg:zookeeper id="regCenter" reg:server-lists="" .../>。
2)xsd:import,导入其他命名空间,表示导入spirng beans命名空间。
如果目标命名空间定义文件没有指定targetNamespace,则需要使用include导入其他命令空间,例如:
<import namespace="tnsB" schemaLocation="B.xsd">
3)xsd:zookeeper> 定义zookeeper元素,xml文件中可以使用reg:zookeeper/>。
4)xsd:complexType,zookeeper元素的类型为复杂类型。
5)xsd:extension base=”beans:identifiedType”>继承beans命名空间identifiedType的属性。(id 定义)。
2、定义NamespaceHandlerSupport实现类。
继承NamespaceHandlerSupport,重写init方法。
public final class RegNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("zookeeper", new ZookeeperBeanDefinitionParser());
}
}
注册BeanDefinitionParser解析reg:zookeeper/>标签,并初始化实例。
ZookeeperBeanDefinitionParser源码:
public final class ZookeeperBeanDefinitionParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {
BeanDefinitionBuilder result = BeanDefinitionBuilder.rootBeanDefinition(ZookeeperRegistryCenter.class);// @1
result.addConstructorArgValue(buildZookeeperConfigurationBeanDefinition(element)); // @2
result.setInitMethodName("init"); // @3
return result.getBeanDefinition(); // @4
}
// ....省略部分代码
}
代码@1:构建器模式,表明标签对应的实体Bean对象为ZookeeperRegistryCenter,zk注册中心实现类。
代码@2:最终创建ZookeeperRegistryCenter,其属性通过构造方法注入。
代码@3:设置initMethod,相当于配置文件的init-method属性,表明在创建实例时将调用该方法进行初始化。
代码@4:返回AbstractBeanDefinition对象,方便Spring针对该配置创建实例。
ZookeeperBeanDefinitionParser#buildZookeeperConfigurationBeanDefinition
private AbstractBeanDefinition buildZookeeperConfigurationBeanDefinition(final Element element) {
BeanDefinitionBuilder configuration = BeanDefinitionBuilder.rootBeanDefinition(ZookeeperConfiguration.class);
configuration.addConstructorArgValue(element.getAttribute("server-lists"));
configuration.addConstructorArgValue(element.getAttribute("namespace"));
addPropertyValueIfNotEmpty("base-sleep-time-milliseconds", "baseSleepTimeMilliseconds", element, configuration);
addPropertyValueIfNotEmpty("max-sleep-time-milliseconds", "maxSleepTimeMilliseconds", element, configuration);
addPropertyValueIfNotEmpty("max-retries", "maxRetries", element, configuration);
addPropertyValueIfNotEmpty("session-timeout-milliseconds", "sessionTimeoutMilliseconds", element, configuration);
addPropertyValueIfNotEmpty("connection-timeout-milliseconds", "connectionTimeoutMilliseconds", element, configuration);
addPropertyValueIfNotEmpty("digest", "digest", element, configuration);
return configuration.getBeanDefinition();
}
根据reg:zookeeper/>元素,获取element的server-lists、namespace属性,使用ZookeeperConfiguration构造方式初始化ZookeeperConfiguration属性,然后解析其他非空属性并使用set方法注入到ZookeeperConfiguration实例。
3、将自定义的NameSpace、xsd文件纳入Spring的管理范围内。
在META-INF目录下创建spring.handlers、spring.schemas文件,其内容分别是:
spring.handlers:
http://www.dangdang.com/schema/ddframe/reg=io.elasticjob.lite.spring.reg.handler.RegNamespaceHandler
格式如下:xsd文件中定义的targetNamespace=自定义namespace实现类。
spring.schemas:
http://www.dangdang.com/schema/ddframe/reg/reg.xsd=META-INF/namespace/reg.xsd
格式如下:xsd文件uri = xsd文件目录。
xsi:schemaLocation=”http://www.dangdang.com/schema/ddframe/reg/reg.xsd=META-INF/namespace/reg.xsd”,取的就是该文件的内容。
然后元素解析后,然后实例化Bean并调用ZookeeperRegistryCenter的init方法,开始注册中心的启动流程。
下一篇将详细介绍elastic-job注册中心的启动流程。