手写XML版Spring容器

目标:

  类似原生的Spring框架,在spring.xml中定义bean信息,通过自定义ChenClassPathXmlApplicationContext解析xml文件,将bean对象实例化。

实现:

思路:

  自定义ChenClassPathXmlApplicationContext,完成解析XML文件并将bean对象实例化的功能。大致步骤如下:

  • 首先读取配置文件,获取根节点信息。
  • 其次使用beanId查找对应的class地址。
  • 最后使用反射机制实例化该bean对象。

一、具体开发流程

  实现通过ChenClassPathXmlApplicationContext获取自定义User类。

1、加入依赖

  本项目需要解析XML文件,所以需要dom4j等jar包。源码如下:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>handwritingproject</artifactId>
        <groupId>com.njust</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springanno</artifactId>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

    </dependencies>
</project>

2、定义User实体类

  定义User类。只有简单的iduserName属性。tostring()方法可以不要,但是为了便于测试,此处将其加入源码中。源码如下:

User .java

package com.njust.spring.entity;

public class User {

    private Integer id = 1;
    private String userName = "userName";

    public Integer getId() {
        return id;
    }

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

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                '}';
    }
}

3、定义spring.xml

  spring.xml中主要定义一个user对象,和spring语法一致。源码如下:

spring.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    	 http://www.springframework.org/schema/beans/spring-beans.xsd
     	 http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
     	 http://www.springframework.org/schema/tx/spring-tx.xsd">

	<bean id="user" class="com.njust.spring.entity.User"></bean>

</beans>

4、定义容器类

  定义ChenClassPathXmlApplicationContext类,对外暴露的主要就是getBean()方法,具体操作流程如下:首先读取配置文件,获取根节点信息,其次使用beanId查找对应的class地址。最后使用反射机制实例化该bean对象。源码如下:

ChenClassPathXmlApplicationContext .java

package com.njust.spring;

import java.io.InputStream;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 手写Spring专题 XML方式注入bean
 */
public class ChenClassPathXmlApplicationContext {
	// xml路径地址
	private String xmlPath;

	public ChenClassPathXmlApplicationContext(String xmlPath) {
		this.xmlPath = xmlPath;
	}

	public Object getBean(String beanId) throws Exception {
		// 1. 读取配置文件
		List<Element> elements = readerXml();
		if (elements == null) {
			throw new Exception("该配置文件没有子元素");
		}
		// 2. 使用beanId查找对应的class地址
		String beanClass = findXmlByIDClass(elements, beanId);
		if (StringUtils.isEmpty(beanClass)) {
			throw new Exception("未找到对应的class地址");
		}
		// 3. 使用反射机制初始化,对象
		Class<?> forName = Class.forName(beanClass);
		return forName.newInstance();
	}

	// 读取配置文件信息
	public List<Element> readerXml() throws DocumentException {
		SAXReader saxReader = new SAXReader();
		if (StringUtils.isEmpty(xmlPath)) {
			new Exception("xml路径为空...");
		}
		Document read = saxReader.read(getClassXmlInputStream(xmlPath));
		// 获取根节点信息
		Element rootElement = read.getRootElement();
		// 获取子节点
		List<Element> elements = rootElement.elements();
		if (elements == null || elements.isEmpty()) {
			return null;
		}
		return elements;
	}

	// 使用beanid查找该Class地址
	public String findXmlByIDClass(List<Element> elements, String beanId) throws Exception {
		for (Element element : elements) {
			// 读取节点上是否有value
			String beanIdValue = element.attributeValue("id");
			if (beanIdValue == null) {
				throw new Exception("使用该beanId为查找到元素");
			}
			if (!beanIdValue.equals(beanId)) {
				continue;
			}
			// 获取Class地址属性
			String classPath = element.attributeValue("class");
			if (!StringUtils.isEmpty(classPath)) {
				return classPath;
			}
		}
		return null;
	}

	// 读取xml配置文件
	public InputStream getClassXmlInputStream(String xmlPath) {
		InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(xmlPath);
		return resourceAsStream;
	}

}

5、测试

  定义Test002类,价值spring.xml配置文件,通过getbean()方法获取实例化对象并输出到控制台。源码如下:

Test002.java

package com.njust.spring;


import com.njust.spring.entity.User;

public class Test002 {

	public static void main(String[] args) throws Exception {
		ChenClassPathXmlApplicationContext applicationContext = new ChenClassPathXmlApplicationContext("spring.xml");
		User user = (User) applicationContext.getBean("user");
		System.out.println(user);
	}

}

  通过控制台输出,我们发现程序成功的输出user基本信息。

Console

User{id=1, userName='userName'}

Process finished with exit code 0

总结

流程图

Created with Raphaël 2.2.0 开始 读取配置文件,获取子节点信息 使用beanId查找对应的class地址 使用反射机制实例化对象 结束

  有问题欢迎各位读者批评指正。

点个赞再走呗!欢迎留言哦!

发布了22 篇原创文章 · 获赞 4 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/qq_32510597/article/details/105281714