5.数据交换格式与 SpringIOC 底层实现

发布时间 2023-04-19 10:26:42作者: 城市幽灵

数据交换格式与 SpringIOC 底层实现

一、 课程目标

XML 和 JSON
Java 反射机制
手写 SpringIOC

二、 什么是数据交换格式

客户端与服务器常用数据交换格式xml、json、html

三、 数据交换格式用场景

移动端(安卓、IOS)通讯方式采用 http 协议+JSON 格式 走 restful 风格。
很多互联网项目都采用 Http 协议+JSON
因为 xml 比较重 WebService 服务采用 http+xml 格式 银行项目使用比较多
同学 们可以思考下?移动 端和 和 PC 端 端 服务器是 接口 是怎么设计的?
画图演示

四、 数据交换格式

4 .1JSON简单使用


4 .1. 1. 什么是 JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相比于 xml 这种数据交换格式来说,
因为解析 xml 比较的复杂,而且需要编写大段的代码,所以客户端和服务器的数据交换格式往往通过 JSON
来进行交换。
样例:

{
"sites": [
{
"name": "蚂蚁课堂",
"url": "www.itmayiedu.com"
},
{
"name": "每特教育",
"url": "http://meiteedu.com/"
}
]
}

JSON: :JavaScript 对象表示法(JavaScript Object Notation )。
JSON 的形式是用大括号“{}” 包围起来的项目列表,每一个项目间用逗号(, )分隔,而项目就是用冒号(:) )
明 分隔的属性名和属性值。这是典型的字典表示形式,也再次表明 javascript 里的对象就是字典结构。不
管多么复杂的对象,都可以用一句 JSON 代码来创建并赋值。在 JSON 中,名称 / 值对包括字段名称(在 值对包括字段名称(在
双引号中),后面写一个冒号,然后是值

4.1. 2 .JSON 格式的分类

JSON 有两种结构
json 简单说就是 javascript 中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结 中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结
构可以表示各种复杂的结构 构可以表示各种复杂的结构
1 、对象:对象在 js 中表示为“{}” 括起来的内容,数据结构为 {key :value,key :value,...}的键值对的 的键值对的
结构,在面向对象的语言中, 结构,在面向对象的语言中,key 为对象的属性,value 为对应的属性值,所以很容易理解,取值方法为
对象 对象.key 获取属性值,这个属性值的类型可以是 数字、字符串、数组、对象几种。
2 、数组:数组在 js 中是中括号“[]” 括起来的内容,数据结构为 ["java","javascript","vb",...],取值方 ,取值方
式和所有语言中一样,使用索引获取,字段值的类型可以是 式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种。
经过对象、数组 经过对象、数组 2 种结构就可以组合成复杂的数据结构了。

4 .1. 3. 常用 JSON 解析框架

fastjson(阿里)、gson(谷歌)、jackson(SpringMVC 自带)

4 .1.4. 使用 fastjson 解析 json

添加 jar fastjson-1.1.43 或引入 maven 依赖

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.43</version>
</dependency>

4 .1.5. 使用 fastjson api

// 把 JSON 文本 parse 为 JSONObject 或者JSONArray
public static final Object parse(String text); 
// 把 JSON 文本 parse 成JSONObject
public static final JSONObject parseObject(String text);
// 把 JSON 文本parse 为 JavaBean
public static final <T> T parseObject(String text, Class<T> clazz); 
// 把 JSON 文 本 parse 成JSONArray
public static final JSONArray parseArray(String text); 
//把 JSON 文本parse 成 JavaBean 集合
public static final <T> List<T> parseArray(String text, Class<T> clazz); 
// 将JavaBean序列化为JSON文本
public static final String toJSONString(Object object); 
// 将JavaBean 序列化为带格式的 JSON 文本
public static final String toJSONString(Object object, boolean prettyFormat); 
//将 JavaBean 转换为 JSONObject或者 JSONArray。
public static final Object toJSON(Object javaObject); 

4 .1.6. 解析 json

static String jsonStr = "{\"sites\":[{\"name\":\" 蚂蚁课堂\
",\"url\":\"www.itmayiedu.com\"},{\"name\":\" 每特教育\
",\"url\":\"http://meiteedu.com/\"}]}";
public static void main(String[] args) {
    JSONObject jsonObject = new JSONObject();
    // 将json 字符串转为jsonbject
    JSONObject jsonStrObject = jsonObject.parseObject(jsonStr);
    JSONArray jsonArray = jsonStrObject.getJSONArray("sites");
    for (Object object: jsonArray) {
        JSONObject stObject = (JSONObject) object;
        String name = stObject.getString("name");
        String url = stObject.getString("url");
        System.out.println(name + "---" + url);
    }
}

4.1.6. 组装 json

JSONObject jsonObject = new JSONObject();
JSONArray jsonArray = new JSONArray();
JSONObject stObject = new JSONObject();
stObject.put("name", " 蚂蚁课堂");
stObject.put("url", "http://www.itmayiedu.com");
jsonArray.add(stObject);
jsonObject.put("sites", jsonArray);
System.out.println(jsonObject.toJSONString());

4. 2 XML简单使用

4 .2.1 什么是 XML ?

它是可扩展标记语言(Extensible Markup Language,简称 XML),是一种标记语言。
XML 全称为可扩展的标记语言。主要用于描述数据和用作配置文件。
XML 文档在逻辑上主要由一下 5 个部分组成:
XML 声明:指明所用 XML 的版本、文档的编码、文档的独立性信息
文档类型声明:指出 XML 文档所用的 DTD
元素:由开始标签、元素内容和结束标签构成
注释:以结束,用于对文档中的内容起一个说明作用
处理指令:通过处理指令来通知其他应用程序来处理非 XML 格式的数据,格式为
XML 文档的根元素被称为文档元素,它和在其外部出现的处理指令、注释等作为文档实体的子节
点,根元素本身和其内部的子元素也是一棵树。

4.2.2 XML 样例?

<?xml version="1.0" encoding="UTF-8"?>
<students>
<student1 id="001">
< 微信公众号>@ 残缺的孤独</ 微信公众号>
< 学号>20140101</ 学号>
< 地址> 北京海淀区</ 地址>
< 座右铭> 要么强大,要么听话</ 座右铭>
</student1>
<student2 id="002">
< 新浪微博>@ 残缺的孤独</ 新浪微博>
< 学号>20140102</ 学号>
< 地址> 北京朝阳区</ 地址>
< 座右铭> 在哭泣中学会坚强</ 座右铭>
</student2>
</students>
作用

xml 文件头部要写的话,说明了 xml 的版本和编码,utf-8 一般是网络传输用的编码

4.2. 3 XML 解析方式?

Dom4j、Sax、Pull

4.2.3Dom4j 与 Sax 区别

dom4j 不适合大文件的解析,因为它是一下子将文件加载到内存中,所以有可能出现内存溢出,sax
是基于事件来对 xml 进行解析的,所以他可以解析大文件的 xml,也正是因为如此,所以 dom4j 可以对 xml
进行灵活的增删改查和导航,而 sax 没有这么强的灵活性,所以 sax 经常是用来解析大型 xml 文件,而要对
xml 文件进行一些灵活(crud)操作就用 dom4j。

4.2.4 使用 dom4j 解析 xml

解析 XML 过程是通过获取 Document 对象,然后继续获取各个节点以及属性等操作,因此获取 Document
对象是第一步,大体说来,有三种方式:
1.自己创建 Document 对象
Document document = DocumentHelper.createDocument();
Element root = document.addElement("students");
其中 students 是根节点,可以继续添加其他节点等操作。
2.自己创建 Document 对象
// 创建SAXReader 对象
SAXReader reader = new SAXReader();
// 读取文件 转换成Document
Document document = reader.read(new File("XXXX.xml"));
3.读取 XML 文本内容获取 Document 对象
String xmlStr = "<students>......</students>"; ;
Document document = DocumentHelper. parseText ( ( xmlStr 

4.2.5 解析 xml 代码

Xml 配置:

<?xml version="1.0" encoding="UTF-8"?>
<students>
<student1 id="001">
< 微信公众号>@ 残缺的孤独</ 微信公众号>
< 学号>20140101</ 学号>
< 地址> 北京海淀区</ 地址>
< 座右铭> 要么强大,要么听话</ 座右铭>
</student1>
<student2 id="002">
< 新浪微博>@ 残缺的孤独</ 新浪微博>
< 学号>20140102</ 学号>
< 地址> 北京朝阳区</ 地址>
< 座右铭> 在哭泣中学会坚强</ 座右铭>
</student2>
</students>

Java 代码

public static void main(String[] args) throws DocumentException {
    SAXReader saxReader = new SAXReader();
    Document read = saxReader.read(new File("E://work//spring-ioc//src//main//resources//stu.xml"));
    // 获取根节点
    Element rootElement = read.getRootElement();
    getNodes(rootElement);
}
static public void getNodes(Element rootElement) {
    System.out.println(" 当前节点名称:" + rootElement.getName());
    // 获取属性ID
    List < Attribute > attributes = rootElement.attributes();
    for (Attribute attribute: attributes) {
        System.out.println(" 属性:" + attribute.getName() + "---" +
            attribute.getText());
    }
    if (!rootElement.getTextTrim().equals("")) {
        System.out.println(rootElement.getName() + "--" +
            rootElement.getText());
    }
    // 使用迭代器遍历
    Iterator < Element > elementIterator = rootElement.elementIterator();
    while (elementIterator.hasNext()) {
        Element next = elementIterator.next();
        getNodes(next);
    }
}

注意:
this.getClass().getClassLoader().getResourceAsStream(xmlPath) 获取当前 项目路径 xml

4. 2 XML与JSON区别

Xml 是重量级数据交换格式,占宽带比较大。
JSON 是轻量级交换格式,xml 占宽带小。
所有很多互联网公司都会使用 json 作为数据交换格式
很多银行项目,大多数还是在使用 xml。

五、 Java 反射机制

5.1 什么是Java反射

就是正在运行,动态获取这个类的所有信息。

5.2 反射机制的作用

1,反编译:.class-->.java
2.通过反射机制访问 java 对象的属性,方法,构造方法等

5.3 反射机制的应用场景

Jdbc 加载驱动-----
Spring ioc
框架

5.4反射机制获取类有三种方法

// 第一种方式:
Classc1 = Class.forName("Employee");
// 第二种方式:
//java 中每个类型都有class 属性.
Classc2 = Employee.class;
// 第三种方式:
//java 语言中任何一个java 对象都有getClass 方法
Employeee = new Employee();
Classc3 = e.getClass(); //c3 是运行时类 (e 的运行时类是 Employee)

5.5反射创建对象的方式

Class <? > forName = Class.forName("com.itmayiedu.entity.User");
// 创建此Class 对象所表示的类的一个新实例 调用了User 的无参数构造方法.
Object newInstance = forName.newInstance();
//实例化有参构造函数
Class <? > forName = Class.forName("com.itmayiedu.entity.User");
Constructor <? > constructor = forName.getConstructor(String.class,
    String.class);
User newInstance = (User) constructor.newInstance("123", "123");

5.6 反射创建api

5.7 使用反射为类私有属性赋值

// 获取当前类class 地址
Class<?> forName = Class.forName("com.itmayiedu.entity.User");
// 使用反射实例化对象 无参数构造函数
Object newInstance = forName.newInstance();
// 获取当前类的 userId 字段
Field declaredField = forName.getDeclaredField("userId");
// 允许操作私有成员
declaredField.setAccessible(true);
// 设置值
declaredField.set(newInstance, "123");
User user = (User) newInstance;
System.out.println(user.getUserId());

六、 手写 SpringIOC 框架

6 .1什么是SpringIOC

什么是 SpringIOC,就是把每一个 bean(实体类)与 bean(实体了)之间的关系交给第三方容器进行管理。
Xml 配置:

<beans>
<bean id="user1" class="com.itmayiedu.entity.UserEntity">
<property name="userId" value="0001"></property>
<property name="userName" value=" 余胜军 "></property>
</bean>
<bean id="user2" class="com.itmayiedu.entity.UserEntity">
<property name="userId" value="0002"></property>
<property name="userName" value=" 张三 "></property>
</bean>
</beans>

Java 代码:

//1.读取springxml配置
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取bean对象
TestService testService = (TestService)
classPathXmlApplicationContext.getBean("testService");
System.out.println(testService.test());

6 .2什么是SpringIOC底层实现原理

1.读取 bean 的 XML 配置文件
2.使用 beanId 查找 bean 配置,并获取配置文件中 class 地址。
3.使用 Java 反射技术实例化对象
4.获取属性配置,使用反射技术进行赋值。
详细步骤
1.利用传入的参数获取 xml 文件的流,并且利用 dom4j 解析成 Document 对象
2.对于 Document 对象获取根元素对象<beans>后对下面的<bean>标签进行遍历,判断是否
有符合的 id.
3.如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据
属性值利用反射建立对象.
4.遍历<bean>标签下的 property 标签,并对属性赋值.注意,需要单独处理 int,float 类型的属
性.因为在 xml 配置中这些属性都是以字符串的形式来配置的,因此需要额外处理.
5.如果属性 property 标签有 ref 属性,说明某个属性的值是一个对象,那么根据 id(ref 属性的
值)去获取 ref 对应的对象,再给属性赋值.
6.返回建立的对象,如果没有对应的 id,或者<beans>下没有子标签都会返回 null

6 .3建立实体类

public class User {
private String userId;
private String userName;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}

6 .4 使用反射技术完成Java代码

import java.lang.reflect.Field;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.itmayiedu.entity.User;

public class ClassPathXmlApplicationContext {
    private String xmlPath;
    /**
     *
     * @param xmlPath
     * spring xml 配置路径
     */
    public ClassPathXmlApplicationContext(String xmlPath) {
        this.xmlPath = xmlPath;
    }
    public Object getBean(String beanId) throws Exception {
        // 解析xml器
        SAXReader saxReader = new SAXReader();
        Document read = null;
        try {
            // 从项目根目录路径下 读取
         read=saxReader.read(this.getClass().getClassLoader().getResourceAsStream(xmlPath));
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (read == null) {
            return null;
        }
        // 获取根节点资源
        Element root = read.getRootElement();
        List < Element > elements = root.elements();
        if (elements.size() <= 0) {
            return null;
        }
        Object oj = null;
        for (Element element: elements) {
            String id = element.attributeValue("id");
            if (StringUtils.isEmpty(id)) {
                return null;
            }
            if (!id.equals(beanId)) {
                continue;
                // throw new Exception(" 使用beanId:" + beanId + ", 未找到该bean");
            }
            // 获取实体bean class 地址
            String beanClass = element.attributeValue("class");
            // 使用反射实例化bean
            Class <? > forNameClass = Class.forName(beanClass);
            oj = forNameClass.newInstance();
            // 获取子类对象
            List < Element > attributes = element.elements();
            if (attributes.size() <= 0) {
                return null;
            }
            for (Element et: attributes) {
                // 使用反射技术为方法赋值
                String name = et.attributeValue("name");
                String value = et.attributeValue("value");
                Field field = forNameClass.getDeclaredField(name);
                field.setAccessible(true);
                field.set(oj, value);
            }
        }
        return oj;
        // 1. 使用beanId 查找配置文件中的bean 。
        // 2. 获取对应bean 中的classpath 配置
        // 3. 使用java 反射机制实体化对象
    }
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext applicationContext = new
        ClassPathXmlApplicationContext("applicationContext.xml");
        User bean = (User) applicationContext.getBean("user2");
        System.out.println(" 使用反射获取bean" + bean.getUserId() + "---" +
            bean.getUserName());
    }
}