手写解析配置文件,实例化所有的bean2

例子:

/**
* 在该构造方法中,解析myspring.xml文件,创建所有的Bean实例,并将Bean实例存放到Map集合中。
* @param resource 配置文件路径(要求在类路径当中)
*/
public ClassPathXmlApplicationContext(String resource) {
    try {
        SAXReader reader = new SAXReader();
        Document document = reader.read(ClassLoader.getSystemClassLoader().getResourceAsStream(resource));
        // 获取所有的bean标签
        List<Node> beanNodes = document.selectNodes("//bean");
        // 遍历集合
        beanNodes.forEach(beanNode -> {
            Element beanElt = (Element) beanNode;
            // 获取id
            String id = beanElt.attributeValue("id");
            // 获取className
            String className = beanElt.attributeValue("class");
            try {
                // 通过反射机制创建对象
                Class<?> clazz = Class.forName(className);
                Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
                Object bean = defaultConstructor.newInstance();
                // 存储到Map集合
                beanMap.put(id, bean);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
}

在ClassPathXmlApplicationContext的构造方法中解析配置文件,获取所有bean的类名,通过反射机制调用无参数构造方法创建Bean。并且将Bean对象存放到Map集合中



 

Java 8中的Lambda表达式语法,对beanNodes集合进行了遍历操作。Lambda表达式的语法如下:

 
beanNodes.forEach(beanNode -> {
    // 在这里编写针对每个beanNode的操作
});

其中beanNode -> { // 在这里编写针对每个beanNode的操作 }是一个Lambda表达式,它代表了一个函数式接口Consumer的实例。在这里,beanNode是函数的参数,箭头后面的部分是函数的执行体,即对每个beanNode要执行的操作。

这种方式相比传统的for循环语法更加简洁和易读,是Java 8引入的函数式编程特性之一。


 

Element beanElt = (Element) beanNode;

这行代码是将beanNode对象转换为Element类型的对象,并将其赋值给beanElt变量。这种类型转换称为强制类型转换,它将beanNode对象转换为Element类型,前提是beanNode对象实际上就是Element类型或者是Element类型的子类。

在这段代码中,假设beanNode对象是Element类型或者是Element类型的子类,那么这行代码就会将其转换为Element类型的对象,以便后续对beanElt对象进行操作。如果beanNode对象不是Element类型或者是Element类型的子类,那么在运行时会抛出ClassCastException异常。因此,在实际使用中,需要确保类型转换的安全性。

在Java中,Element类型通常是指代XML文档中的元素(element)。在XML处理的上下文中,Element表示XML文档中的一个元素节点,它包含了标签、属性和子元素等信息。在使用Java中的XML解析库(比如DOM、SAX、JDOM等)时,通常会将XML文档中的元素表示为Element类型的对象。

在上下文中,假设beanNode是XML文档中的一个元素节点,那么将其转换为Element类型的对象beanElt是为了使用Element类型提供的方法和属性来访问和操作XML元素的相关信息。通过将beanNode转换为Element类型,可以方便地获取元素的属性值、子元素等信息,从而进行后续的处理和操作。

因此,将beanNode转换为Element类型是为了在处理XML文档时能够更方便地操作元素节点的相关信息。




SAXReader reader = new SAXReader();的解释

详细介绍 SAXReader类-CSDN博客



 

ClassLoader.getSystemClassLoader().getResourceAsStream(resource)



这部分代码使用系统类加载器获取资源的输入流。ClassLoader.getSystemClassLoader()返回系统类加载器,然后调用getResourceAsStream(resource)来获取资源文件的输入流。这个方法会根据类加载器的规则来查找资源文件,一般会在类路径下查找指定的文件。

当使用ClassLoader.getSystemClassLoader().getResourceAsStream(resource)时,系统类加载器会尝试加载指定的资源文件并返回对应的输入流。这个方法通常用于从类路径中获取资源文件的输入流。让我通过一个简单的例子来说明这个过程:

假设我们有一个名为"example.xml"的XML文件,它被放置在项目的资源文件夹(例如src/main/resources)中。我们想要使用ClassLoader.getSystemClassLoader().getResourceAsStream(resource)来获取这个文件的输入流。

import java.io.InputStream;

public class ResourceExample {
    public static void main(String[] args) {
        String resource = "example.xml"; // 资源文件的路径
        InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resource);
        if (inputStream != null) {
            // 从输入流中读取数据或进行其他操作
            // 这里假设我们将输入流传递给SAXReader来读取XML内容
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            // 对XML文档进行处理
        } else {
            System.out.println("无法找到指定的资源文件");
        }
    }
}

在这个例子中,我们首先定义了资源文件的路径"example.xml",然后使用ClassLoader.getSystemClassLoader().getResourceAsStream(resource)来获取这个资源文件的输入流。如果找到了资源文件,就可以对输入流进行操作,比如将其传递给SAXReader来读取XML内容。

这种方法特别适用于从类路径中获取资源文件的输入流,比如在Java项目中读取放在resources目录下的文件。

在Java中,reader.read() 方法需要一个 java.io.File 对象或者一个 java.io.InputStream 对象作为参数,用来指定要读取的文件或者输入流。直接传递文件名字符串是不合法的,因为 reader.read() 方法不支持直接传入文件名字符串。

因此,如果你想要直接使用 reader.read() 方法来读取一个 XML 文件,你需要首先创建一个 java.io.File 对象,然后将其作为参数传递给 reader.read() 方法。

Document document = reader.read(new File("example.xml"));

如果你不想创建一个 java.io.File 对象,而是想直接传递文件名字符串,你可以使用 org.dom4j.io.SAXReaderread() 方法来读取一个输入流,这样你就可以直接使用 ClassLoader.getSystemClassLoader().getResourceAsStream(resource) 返回的输入流来读取 XML 内容。

InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("example.xml");

Document document = reader.read(inputStream);

/ /获取所有的bean标签

List<Node> beanNodes = document.selectNodes("//bean");

这行代码使用XPath表达式//bean来选择XML文档中所有的<bean>标签,并将它们存储在一个列表中。

让我来解释一下这行代码的具体作用:

  1. document.selectNodes("//bean") - 这部分代码使用了selectNodes方法来执行XPath表达式//bean,这个表达式的含义是选择XML文档中所有名为bean的元素,不论它们在文档中的位置如何。这个方法返回一个包含所有匹配元素的列表。

  2. List<Node> beanNodes = ... - 这部分代码将selectNodes方法返回的列表存储在名为beanNodesList<Node>类型的变量中。每个Node对象代表一个匹配的<bean>元素。

这样,通过执行XPath表达式//bean,我们就能够获取XML文档中所有的<bean>标签,并将它们存储在一个列表中,以便进一步处理或者遍历。XPath表达式在XML文档处理中非常常用,它能够灵活地选择XML文档中的特定元素。

在这段代码中,选择使用List<Node>的主要原因是selectNodes方法返回的结果是一个包含匹配元素的节点列表,每个节点都是XML文档中的一个元素。因此,为了存储这些匹配的节点,我们使用了List<Node>来保存这些节点对象。

使用List<Node>的好处包括:

  1. 类型安全性: 通过将匹配的节点存储在List<Node>中,可以确保我们只存储XML文档节点对象,避免混淆或错误地存储其他类型的对象。

  2. 方便的遍历和处理: 一旦我们将匹配的节点存储在List<Node>中,就可以方便地遍历这个列表,对每个节点进行处理,比如提取节点的属性、子节点等等。

  3. 兼容性: 使用List<Node>作为结果的数据结构,使得代码更具灵活性,可以方便地传递给其他方法或模块进行进一步处理。

因此,选择List<Node>作为结果的数据结构是为了方便存储和处理selectNodes方法返回的匹配节点列表。

虽然可以写成List而不指定具体的泛型类型,但是这并不是推荐的做法。在实际的开发中,为了代码的清晰和可维护性,最好还是将泛型类型明确指定为具体的类型,比如List<Node>

因此,建议还是使用List<Node>而不是简单地写成List,以便在代码中明确表示这个列表是存储了Node类型的元素,提高代码的可读性和可维护性。

在这种情况下,选择使用Node类型是因为在XML文档处理中,Node是代表XML文档中的一个节点的通用接口。在许多XML处理库中,包括DOM、JDOM和DOM4J等,Node通常是表示XML文档中元素、属性、文本节点等的通用类型。

因此,当我们使用DOM4J库来处理XML文档时,selectNodes方法返回的结果是一个包含匹配元素的节点列表,每个节点都是XML文档中的一个元素,可能是元素节点、属性节点或者文本节点等。因此,为了能够存储这些不同类型的节点,我们选择使用Node类型来表示这些节点。

通过使用通用的Node类型,我们可以灵活地处理和操作XML文档中的各种节点,而不用关心具体是元素节点、属性节点还是其他类型的节点。这种通用性使得我们能够更加灵活地处理XML文档的结构。

因此,选择Node类型是为了能够存储XML文档中各种类型的节点,并且能够灵活地处理和操作这些节点。
 

当使用DOM4J库来处理XML文档时,可以使用Node类型来表示XML文档中的不同类型的节点。以下是一个简单的例子,假设我们有一个XML文档如下:

<root>
    <element1>Value 1</element1>
    <element2 attribute="attribute value">Value 2</element2>
</root>

我们可以使用DOM4J库来解析这个XML文档,并使用Node类型来表示不同类型的节点。以下是一个简单的示例代码:

 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.util.List;

public class XmlParser {
    public static void main(String[] args) {
        try {
            // 读取XML文档
            SAXReader reader = new SAXReader();
            Document document = reader.read("example.xml");

            // 选择所有节点
            List<Node> nodes = document.selectNodes("//*");

            // 遍历并打印每个节点
            for (Node node : nodes) {
                System.out.println("Node name: " + node.getName() + ", Node type: " + node.getNodeType());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们使用DOM4J的selectNodes方法选择了XML文档中的所有节点,并将它们存储在List<Node>中。然后我们遍历这个列表,并打印每个节点的名称和类型。这里的Node类型可以表示XML文档中的元素节点、属性节点、文本节点等不同类型的节点。

输出结果可能如下所示:

Node name: root, Node type: 1
Node name: element1, Node type: 1
Node name: element2, Node type: 1

在这个示例中,我们遍历了XML文档中的所有节点,并打印了每个节点的名称和类型。根据给定的XML文档,我们得到了三个节点:rootelement1element2,它们都是元素节点(节点类型为1)。

这个输出结果表明我们成功地使用Node类型来表示XML文档中的不同类型的节点,并对它们进行了处理。

xpath表达式:

XPath 是一种用于在 XML 文档中定位和选择节点的语言。它提供了一种灵活的方式来导航和查询 XML 文档的各个部分。以下是一些常见的 XPath 表达式及其用法:

  1. 选择所有的元素

    • 表达式://*
    • 说明:这将选择 XML 文档中的所有元素节点。
  2. 选择指定名称的元素

    • 表达式://book
    • 说明:这将选择 XML 文档中所有名为 "book" 的元素节点。
  3. 选择具有指定属性的元素

    • 表达式://book[@category='fiction']
    • 说明:这将选择 XML 文档中具有 category 属性为 "fiction" 的所有 "book" 元素节点。
  4. 选择具有指定位置的元素

    • 表达式:(//book)[1]
    • 说明:这将选择 XML 文档中的第一个 "book" 元素节点。
  5. 选择子元素

    • 表达式://book/title
    • 说明:这将选择 XML 文档中所有 "book" 元素的子元素 "title"。

以上是一些常见的 XPath 表达式示例。XPath 还支持更多的功能和语法,包括谓词、函数等。通过灵活使用 XPath 表达式,可以轻松地定位和选择 XML 文档中的各种节点。

如果您有特定的 XML 结构和查询需求,我可以帮助您编写相应的 XPath 表达式。


// 通过反射机制创建对象 Class<?> clazz = Class.forName(className); Constructor<?> defaultConstructor = clazz.getDeclaredConstructor(); Object bean = defaultConstructor.newInstance();的解释

1、使用Class.forName(className)方法根据提供的类名(className)获取对应的Class对象。这里的className是一个字符串,表示要创建对象的类的完整类名。

2、通过获取类的默认构造函数(无参构造函数),即clazz.getDeclaredConstructor(),并存储在defaultConstructor变量中。

3、使用defaultConstructor.newInstance()方法来实例化对象,这里假设类具有无参构造函数。这个方法会调用类的无参构造函数来创建一个新的对象,并将其赋值给bean变量。


通过这些步骤,代码实现了根据类名动态创建对象的功能。这种动态创建对象的方式在某些场景下非常有用,比如在框架中根据配置文件中指定的类名来创建对象实例。需要注意的是,反射机制的使用应谨慎,因为它会影响代码的可读性和性能。

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Tin9898

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值