IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 手敲简易版Spring框架 - IOC与DI -> 正文阅读

[Java知识库]手敲简易版Spring框架 - IOC与DI

Spring 是目前 javaEE 开发中的主流框架,可以说 spring 让 java 开发人员迎来了一个“春天”,

Spring框架是Spring家族下一个JAVAEE企业开发的一栈式轻量级框架

?从 Spring 架构图可以看出,spring 最核心的是 Core Container ,而在核心容器中核心的,是 Core 和 Bean ,也就是 IOC 控制反转和 DI 依赖注入

Spring 的这两个组件是怎么工作的呢,

在我们使用 spring 时,会设置它的配置文件,在里面配置 bean 标签,然后使用 property?标签依赖注入,这里使用到的逻辑也很简单,就是

  1. 解析这个 xml 文件,获取对应标签的值,
  2. 使用反射来创建对象,调用 set 方法注入
  3. 将对象存入 map 中,键名为 beanid值
  4. 公开一个 getBean 方法,返回Bean

理解它的工作原理之后,我们来自己手写一个类似的容器


项目准备

beans.xml —— spring 配置文件,用于生成 Bean 和依赖注入

<?xml version="1.0" encoding="UTF-8" ?>
<beans>
    <bean id="user" class="com.dao.User">
        <property name="username" value="TOM"/>
        <property name="password" value="123456"/>
    </bean>
</beans>

User.java

package com.dao;

public class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

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

现在我们就要编写解析 XML 的 SpringAppLicattionContext 类和启动容器的 app 类

解析 XML 是这个容器最重要也是最核心的功能,与之一样重要的就是使用反射来创建对象

package com;

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

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * 一些声明信息
 *
 * @author 谢柯
 * @date: 2022/9/15 23:42
 * @description: 类spring IOC容器
 * @since JDK 1.8
 */
public class SpringApplicationContext {
    private String path;
    private HashMap<String,Object> mapBean=new HashMap<String, Object>();
    private HashMap<String,String> mapElement=new HashMap<String, String>();


    public SpringApplicationContext(String path) throws DocumentException, FileNotFoundException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        this.path = path;
        this.xml();
    }

    public void xml() throws FileNotFoundException, DocumentException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {

//        文件输入流
        InputStream stream = ClassLoader.getSystemResourceAsStream(this.path);

//        new DOM4j的核心对象,SAXReader
        SAXReader saxReader = new SAXReader();

//        通过SAXReader对象的read()方法得到Document对象。该方法需要输入流,该输入流指向要解析的文件
        Document read = saxReader.read(stream);

//        用Document对对象的getRootElement()方法,获取根节点
        Element rootElement = read.getRootElement();

//        用根节点的elements(节点名)方法,获取子节点对象集
        List<Element> beans = rootElement.elements("bean");

//        遍历集合,获得每一个节点对象
        for (Element bean : beans) {

//            获取要创建bean的id名,全类名
            String id = bean.attributeValue("id");
            String _class = bean.attributeValue("class");

//            获取子节点
            List<Element> property = bean.elements("property");

//            遍历子节点标签
            for (Element element : property) {

//                获取子节点标签的属性值
                String name = element.attributeValue("name");

                String value = element.attributeValue("value");

//                将遍历出来的值暂存到map中,这是依赖注入的值
                mapElement.put(name,value);
            }

//            获取字节码文件对象
            Class<?> aClass = Class.forName(_class);

//            直接创建对象
            Object o = aClass.newInstance();

            Set<String> set = mapElement.keySet();

//            执行对象的set方法,注入值
            for (String name : set) {

//                将属性名第一个字母大写
                String MethodName="set"+name.substring(0,1).toUpperCase()+name.substring(1);
                String value = mapElement.get(name);

//                获取set方法
                Method method = aClass.getMethod(MethodName, String.class);

                method.invoke(o,value);
            }

//            加入map
            mapBean.put(id,o);
        }
    }

//    获取Bean,如果传入class的话,可以直接返回指定类型的一个对象
    public Object getBean(String BreanName){

        Object o = mapBean.get(BreanName);
        System.out.println(o.toString());
        return o;
    }

    

}

解析 XML 常见的有 JAXP,JDOM,DOM4J,我这里使用DOM4J

DOM4J的解析流程为:

?1 - 创建DOM4J的核心对象,SAXReader
?2 - 通过SAXReader对象的read()方法得到Document对象。该方法需要输入流指向要解析的文件
?3 - ?用Document对对象的getRootElement()方法,获取根节点
?4 - 用根节点的elements(子节点名)方法,获取子节点对象集
?5 - 遍历集合,获得每一个节点对象,并对其处理
? ? 获取属性信息 —— 节点对象 . attributeValue(属性)
? ? 获取文本内容?—— 节点对象 .?getText()
? ? 获取下级标签 —— 节点对象 . element(标签名)

另外在编写上述代码时遇到了几个问题,

1)定义成员变量

?private HashMap<String,Object> mapBean=new HashMap<String, Object>();

private HashMap<String,Object> mapBean

的区别

如果使用 new 来创建,那么是创建了一个实例对象,该对象在堆内存拥有内存空间,变量指向该内存空间

如果只是定义一个变量,那么该变量默认值为 null ,无法进行任何操作

2)在创建文件输入流(FileInputStream)时,不论使用相对还是绝对路径,都读不到 xml,我创建的是一个 maven 项目,实在让我纳闷,最后输入流使用了??

ClassLoader.getSystemResourceAsStream(path);

容器启动类 App.java

package com;

import com.itheima.domain.User;
import com.itheima.service.impl.UserServiceImpl;
import org.dom4j.DocumentException;

import java.io.FileNotFoundException;
import java.lang.reflect.InvocationTargetException;

public class App {
    public static void main(String[] args) throws DocumentException, FileNotFoundException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {

//        获取解析容器
        SpringApplicationContext springApplicationContext = new SpringApplicationContext("beans.xml");

//        取出对应Bean,
       User user = (User)springApplicationContext.getBean("user");

//        输出Bean
        System.out.println(user);

    }
}

运行该启动类后,可以在控制台看到

?说明我们的项目已经成功创建了 User 的实例对象并返回,到此,学习结束

后言

“公道时间唯白发,贵人头上不曾饶”

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:12:55  更:2022-09-21 00:18:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 8:50:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码