文章目录

  • 目标:
  • 实现:
      • 思路:
    • 一、具体开发流程
      • 1、加入依赖
      • 2、定义User实体类
      • 3、定义spring.xml
      • 4、定义容器类
      • 5、测试
  • 总结
    • 流程图

目标:

  类似原生的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;}@Overridepublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://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) {// 读取节点上是否有valueString 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地址 使用反射机制实例化对象 结束

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

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

手写XML版Spring容器相关推荐

  1. 解鞍卸甲——手写简易版Spring框架(终):使用三级缓存解决循环依赖问题

    什么是三级缓存 按照目前我们实现的 Spring 框架,是可以满足一个基本需求的,但如果你配置了A.B两个Bean对象互相依赖,那么立马会抛出 java.lang.StackOverflowError ...

  2. 手写简版spring --8--Aware感知容器对象Aware感知容器对象

    一.目标 目前已实现的 Spring 框架,在 Bean 操作上能提供出的能力,包括:Bean 对象的定义和注册,以及在操作 Bean 对象过程中执行的,BeanFactoryPostProcesso ...

  3. 手写简版spring --1--创建简单的Bean容器

    一.声明 这个系列是我自己的学习笔记,为了在学习的过程中巩固知识而记录的,好强迫自己用心拜读,而不是进收藏夹.本系列都是基于小缚哥的文章和代码的,想要深入了解,请移步小缚哥博客 二.spring-Be ...

  4. 手写简易版Spring框架(七):定义标记类型接口Aware,实现感知容器相关的信息

    文末有惊喜 目标 目前已实现的 Spring 框架,在 Bean 操作上能提供出的能力,包括:Bean 对象的定义和注册,以及在操作 Bean 对象过程中执行的,BeanFactoryPostProc ...

  5. 手写简版spring --10--容器事件和事件监听器

    一.降低耦合 解耦场景在互联网开发的设计中使用的也是非常频繁,如:这里需要一个注册完成事件推送消息.用户下单我会发送一个MQ.收到我的支付消息就可以发货了等等,都是依靠事件订阅和发布以及MQ消息这样的 ...

  6. 手写简版spring --9--对象作用域和FactoryBean

    一.目标 交给 Spring 管理的 Bean 对象,一定就是我们用类创建出来的 Bean 吗?创建出来的 Bean 就永远是单例的吗,没有可能是原型模式吗?在集合 Spring 框架下,我们使用的 ...

  7. 手写简版spring --2--实现Bean的定义、注册、获取

    一.目标 在上一章节我们初步依照 Spring Bean 容器的概念,实现了一个粗糙版本的代码实现.那么本章节我们需要结合已实现的 Spring Bean 容器进行功能完善,实现 Bean 容器关于 ...

  8. 手写简版spring --7--初始化方法和销毁方法

    一.目标 当我们的类创建的 Bean 对象,交给 Spring 容器管理以后,这个类对象就可以被赋予更多的使用能力.就像我们在上一章节已经给类对象添加了修改注册Bean定义未实例化前的属性信息修改和实 ...

  9. 手写简版spring --6--应用上下文(BeanPostProcessor 和 BeanFactoryPostProcessor)

    一.目标 如果你在自己的实际工作中开发过基于 Spring 的技术组件,或者学习过关于SpringBoot 中间件设计和开发等内容.那么你一定会继承或者实现了 Spring对外暴露的类或接口,在接口的 ...

最新文章

  1. 阿里云专家手把手教你重塑 IT 架构!
  2. DayDayUp:博主,在此,祝愿大家(十五种编程语言输出),2019年春节快乐!猪年诸事大吉!学要有所成,劳要有所获!
  3. 微软MSDN中文网络广播(Webcast)——Visual Studio 2010 ALM应用实践系列课程预告(2011)...
  4. ssh无密码公钥登陆
  5. java指定sql生成xml,用Java实现可保存状态的数据库生成XML树(8)-JSP教程,Java与XML...
  6. c语言事件结构体,C语言结构体史上最详细的讲解
  7. Java21天打卡Day7-循环
  8. boost基础——any(二)
  9. 【狂神MySQL笔记】初识Mysql
  10. baseline如何发布_baseline-简单的字符串基线。-Dan Gass
  11. 至今为止碰到的非常妖怪的计算机问题
  12. 川师c语言实验报告9,川师c语言实验报告十.doc
  13. 【如何快速的开发一个完整的iOS直播app】(原理篇)
  14. C语言代码绘制,利用数组输出 0-2Π之间的 sin 函数图像和 cos 函数图像,实验报告及代码。
  15. Gym - 100886I 2015-2016 Petrozavodsk Winter Training Camp, Saratov SU Contest I - Archaeological Res
  16. 用Python爬取28010条《隐秘的角落》评论,我发现了这些...
  17. word教程之word2007和2010版本查找和替换快捷键介绍
  18. 牛客小白月赛21(求三角形的外心模板)
  19. Unity踩坑:FindObjectsOfType can only be called from the main thread
  20. ORACLE ORA-01653: unable to extend table 的错误处理

热门文章

  1. react ant design pro typescript springboot activiti权限、工作流框架
  2. 彩铅学习第三课,平涂练习
  3. 一本通提高篇 树形动态规划
  4. python光学仿真之菲涅耳公式
  5. 股票基础知识—K线图基础知识
  6. 怎样解决KeyShot中的黑屏问题
  7. 数据结构与算法实验题7.2 连环计
  8. CCIE实验之DMV*N的单云双核双层HUB
  9. Python中正则表达式的妙用。
  10. 线性回归 非线性回归_线性回归的解释