文章目录

  • 目标:
  • 实现:
      • 思路:
    • 一、具体开发流程
      • 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. nginx限制请求之四:目录进行IP限制
  2. 45种可以拿到Webshell的程序
  3. git只合并某一个分支的某个commit
  4. C#并行编程中的Parallel.Invoke
  5. ubuntu下qt的常见错误
  6. dataframe读取列表中对应的列
  7. 自定义异常并抛出,捕获
  8. jumpserver开源堡垒机部署安装
  9. k8s 配置dashboard
  10. Java程序员如何高效学习,才能加快成为架构师的步伐
  11. 190303每日一句
  12. Linux安装搜狗输入法
  13. USB转串口RS232驱动程序
  14. [机器学习笔记] 常用的分类与预测算法
  15. 笔记本dns服务器怎么修改,笔记本电脑DNS怎么设置
  16. Simon‘s writting 全网最全笔记
  17. Android 设置APP桌面图标
  18. 请收下这 72 个炫酷的 CSS 技巧
  19. 取消和卸载Office 2010默认安装的微软拼音输入法的方法
  20. python爬取王者皮肤_Python爬取王者荣耀所有英雄以及高清大图

热门文章

  1. 【招聘内推】软告招聘大数据架构师
  2. 华为防火墙常见问题总结
  3. Java开发大型互联网高并发架构实战之原理概念分析
  4. 为什么我复制文件比你快
  5. 如何实现百度翻译接口——不用申请API接口密钥
  6. ASCII码中的控制字符
  7. 循环神经网络(RNN)的原理及实现
  8. php小红针有副作用吗,可以喝的玻尿酸—小红针
  9. java 注释 see_java注释
  10. 2015-2016-1 学期《软件工程》学生名单-- PS:教材使用《构建之法》第二版 --邹欣著...