吃透Spring源码(三):自定义配置文件标签

Spring的强大之处不仅仅在于它为Java开发者提供了极大便利,更在于它的开放式架构,使得用户可以拥有最大扩展Spring的能力。

我们在用xml定义spring信息时,默认的element只包含beans,bean,import,alias这四个,其它任何标签都属于自定义标签,均需要引入相应的命名空间,如:context,aop标签等。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						//处理默认的标签元素
						parseDefaultElement(ele, delegate);
					}
					else {
						//处理自定义的标签元素
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

对应的源码处理在DefaultBeanDefinitionDocumentReader类的parseBeanDefinitions方法里面。

自定义标签元素

1,定义People.java
public class People {
    private String id;
    private int age;
    private String name;
    private String address;

    public People(String id, int age, String name, String address) {
        this.id = id;
        this.age = age;
        this.name = name;
        this.address = address;
    }

    public People() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "People{" +
                "id='" + id + '\'' +
                ", age=" + age +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
2,在resources/META-INF目录下定义people.xsd,spring.handlers,spring.schemas文件

people.xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.bobo.com/schema/people"
        xmlns:tns="http://www.bobo.com/schema/people"
        elementFormDefault="qualified">
    <element name="people">
        <complexType>
            <attribute name ="id" type = "string"/>
            <attribute name ="age" type = "int"/>
            <attribute name ="name" type = "string"/>
            <attribute name ="address" type = "string"/>
        </complexType>
    </element>
</schema>

spring.handlers

http\://www.bobo.com/schema/people=com.bobo.custom.PeopleNamespaceHandler

spring.schemas

http\://www.bobo.com/schema/people.xsd=META-INF/people.xsd
3,创建对应的namespaceHandler类PeopleNamespaceHandler.java
package com.bobo.custom;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * @author bobo
 * @date 2020-10-20
 */

public class PeopleNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        super.registerBeanDefinitionParser("people",new PeopleBeanDefinitionParser());
    }
}

4,创建对应的BeanDefinitionParser类PeopleBeanDefinitionParser.java
package com.bobo.custom;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

/**
 * @author bobo
 * @date 2020-10-20
 */

public class PeopleBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        return People.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String id = element.getAttribute("id");
        String age = element.getAttribute("age");
        String name = element.getAttribute("name");
        String address = element.getAttribute("address");
        if (StringUtils.hasLength(id)){
            builder.addPropertyValue("id",id);
        }
        if (StringUtils.hasLength(age)){
            builder.addPropertyValue("age",age);
        }
        if (StringUtils.hasLength(name)){
            builder.addPropertyValue("name",name);
        }
        if (StringUtils.hasLength(address)){
            builder.addPropertyValue("address",address);
        }
    }
}

5,创建application-context.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:bo="http://www.bobo.com/schema/people"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.bobo.com/schema/people http://www.bobo.com/schema/people.xsd">

    <bo:people id="bo" age="20" name="bobo" address="广东省深圳市"></bo:people>

</beans>
6,创建测试类
package com.bobo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        System.out.println(context.getBean("bo"));
    }
}
运行输出
People{id='bo', age=20, name='bobo', address='广东省深圳市'}
### DataX 的使用方法及源码调用解析 #### 数据同步工具概述 DataX 是阿里巴巴开源的一款异构数据源离线同步工具,能够高效完成多种不同数据源之间的数据传输任务。它支持丰富的插件扩展机制,允许开发者自定义数据读取器(Reader)、写入器(Writer)以及其他组件。 --- #### Java 调用 DataX 并返回任务执行详情的方法 Java 集成方式可以通过封装 DataX 的核心逻辑来实现任务的启动与监控。以下是具体实现的关键点: 1. **加载配置文件** DataX 支持通过 JSON 文件指定任务的具体配置项。这些配置包括 Reader 和 Writer 描述的数据源信息、字段映射关系等内容。在 Java 中可通过 `ConfigParser` 类解析本地或远程路径下的配置文件[^3]。 2. **初始化 Job 容器** 创建一个继承自 `AbstractJobContainer` 的类实例化对象,并传入已解析的任务配置参数集合。此过程会触发内部框架自动构建 Task 列表并划分多个 TaskGroup 来管理并发度[^4]。 3. **调度与执行** 当所有准备工作完成后进入 schedule 方法阶段,在这里主要完成了步操作:统计总 task 数量;设定每组最大 channel 值,默认为 5;最后依据实际需求调整总的 group 数目以适应资源限制条件。 4. **捕获异常处理日志记录** 整个流程中不可避免会出现各种错误情况比如连接失败或者超时等问题,则需要合理设计 try-catch 结构加以应对同时做好充分的日志留存以便后续排查定位问题所在位置[^1]。 ```java public class DataXRunner { public static void main(String[] args) throws Exception { Configuration configuration = new Configuration(); // 加载JSON配置文件 String jobJsonPath = "/path/to/your/job.json"; InputStream inputStream = Files.newInputStream(Paths.get(jobJsonPath)); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null){ sb.append(line); } JSONObject jsonObject = JSON.parseObject(sb.toString()); configuration.from(jsonArray); // 初始化容器环境变量设置等必要前置动作 AbstractJobContainer containerInstance = new CustomizedJobContainer(configuration); containerInstance.init(); // 开始正式运行job主体部分 boolean successFlag = false; try{ successFlag = containerInstance.startup(); }catch(Exception e){ System.err.println("Error occurred during execution:" +e.getMessage()); } if(successFlag){ System.out.println("The entire ETL process has been successfully completed."); }else{ throw new RuntimeException("ETL failed please check logs for more details"); } } } ``` --- #### 关键技术细节说明 - **动态调整并发策略** 根据用户输入的不同并发级别重新规划分配子任务至各个小组之中从而达到最优性能表现效果[^2]。 - **灵活适配多场景应用需求** 不仅限于简单的单向迁移还可以满足复杂业务逻辑定制开发要求例如增量更新全量覆盖等多种模式切换自如。 - **完善的错误恢复机制保障稳定性** 即使遇到中途断网等情况也能快速重试直至最终顺利完成全部预定目标为止。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃透Java

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值