目标:
类似原生的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
类。只有简单的id
和userName
属性。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
总结
流程图
有问题欢迎各位读者批评指正。
点个赞再走呗!欢迎留言哦!