java架构学习——6. 数据交换格式与SpringIOC底层实现

本篇博文主要包含:

  • JSON简单使用,Java对象、json字符串对象和json对象互转
  • XML简单使用,Dom4j解析XML
  • XML与JSON区别
  • Java反射机制
  • 反射机制获取类的方法
    -Class.class
    -Class.forName()
    -.getClass()
  • 利用反射给私有属性赋值
  • 利用反射手写springIOC原理:dom4j+反射机制

一、数据交换格式

  1. JSON简单使用
    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相比于xml这种数据交换格式来说,因为解析xml比较的复杂,而且需要编写大段的代码,所以客户端和服务器的数据交换格式往往通过JSON来进行交换。
    常用JSON解析框架:
    fastjson(阿里)、gson(谷歌)、jackson(SpringMVC自带)

以下案例使用fastjson解析json:
1.1 添加jar fastjson-1.1.43 或引入maven依赖

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

1.2 将json字符串转化为json对象

public static void jsonStrToJsonObject() {
		String jsonStr = "{\"sites\":[{\"name\":\"三多\",\"url\":\"不抛弃\"},{\"name\":\"史今\",\"url\":\"不放弃\"}]}";
		JSONObject jsonObject = new JSONObject();
		// 将json字符串转为jsonbject
		JSONObject jsonStrObject = jsonObject.parseObject(jsonStr);
		//将数组转化为json数组
		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);
		}
	}

运行结果:
在这里插入图片描述

1.3 将json字符串转化为java对象
User和Item类

class Item {
	private String itemId;
	private String itemName;

	public String getItemId() {

		return itemId;
	}

	public void setItemId(String itemId) {

		this.itemId = itemId;
	}

	public String getItemName() {

		return itemName;
	}

	public void setItemName(String itemName) {

		this.itemName = itemName;
	}

	@Override
	public String toString() {
		return "Item [itemId=" + itemId + ", itemName=" + itemName + "]";
	}
}

class User {
	private String id;
	private String name;
	private List<Item> items;

	public String getId() {

		return id;
	}

	public void setId(String id) {

		this.id = id;
	}

	public String getName() {

		return name;
	}

	public void setName(String name) {

		this.name = name;
	}

	public List<Item> getItems() {

		return items;
	}

	public void setItems(List<Item> items) {

		this.items = items;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", items=" + items + "]";
	}
}

将json字符串转化为对象的方法:

	public static void jsonStrToObject() {
		String jsonStr = "{\"name\":\"不抛弃,不放弃\",\"id\":\"0\",\"items\":[{\"itemName\":\"三多\",\"itemId\":\"1\"},{\"itemName\":\"史今\",\"itemId\":\"2\"}]}";
		//使用java反射机制 对应生成对象
		User user = new JSONObject().parseObject(jsonStr, User.class);
		System.out.println("user:" + user.toString());
	}

运行结果:
在这里插入图片描述
1.4 Json api封装json

public static void toJsonObject() {
		JSONObject root = new JSONObject();
		root.put("id", "1");
		root.put("name", "成才");
		//定义一个json数组
		JSONArray arrayList = new JSONArray();
		JSONObject object1 = new JSONObject();
		object1.put("itemId", "2");
		object1.put("itemName", "醒悟");
		JSONObject object2 = new JSONObject();
		object2.put("itemId", "3");
		object2.put("itemName", "成长");
		arrayList.add(object1); 
		arrayList.add(object2);
		root.put("items", arrayList);
		System.out.println(root.toJSONString());
	}

运行结果:
在这里插入图片描述
1.5 将对象转换成json字符串

public static void ObjectToJsonObjectStr() {
		User user = new User();
		user.setId("1");
		user.setName("六一");
		List<Item> items =new ArrayList<Item>();
		Item item1 = new Item();
		item1.setItemId("2");
		item1.setItemName("坚韧");
		Item item2 = new Item();
		item2.setItemId("3");
		item2.setItemName("优秀");
		items.add(item1);
		items.add(item2);
		user.setItems(items);
		System.out.println(new JSONObject().toJSONString(user));
	}

运行结果:
在这里插入图片描述

  1. XML简单使用
    XML 全称为可扩展的标记语言。它是一种重量级的数据交换格式。XML 文档的根元素被称为文档元素,它和在其外部出现的处理指令、注释等作为文档实体的子节点,根元素本身和其内部的子元素也是一棵树。

XML 文档在逻辑上主要由一下 5 个部分组成:

  • XML 声明:指明所用 XML 的版本、文档的编码、文档的独立性信息
  • 文档类型声明:指出 XML 文档所用的 DTD
  • 元素:由开始标签、元素内容和结束标签构成
  • 注释:以结束,用于对文档中的内容起一个说明作用
  • 处理指令:通过处理指令来通知其他应用程序来处理非 XML 格式的数据。

XML解析方式有:Dom4j、Sax、Pull

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

  1. 以下案例使用dom4j解析xml
    3.1 引入maven依赖
		<dependency>
			<groupId>org.dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>2.0.0</version>
		</dependency>

3.2 stu.xml配置(本次放在项目根目录下)

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

3.3 解析代码

public class Dom4jDemo {
	public static void main(String[] args) throws DocumentException {
		SAXReader saxReader = new SAXReader();
		//读取xml配置文件
		Document read = saxReader.read(new File("C:\\ww\\workSpace\\zbm\\zbm\\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) 可以获取当前项目路径。

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

二、Java反射机制

  1. 什么是Java反射
    就是正在运行,动态获取这个类的所有信息。
  2. 反射机制的作用
    通过反射机制访问java对象的属性,方法,构造方法等。
  3. 反射机制的应用场景
    Jdbc 加载驱动
    Spring ioc
    框架
  4. 禁止使用反射机制初始化?
    将构造函数为私有化
  5. 反射机制获取类有三种方法
    1)Class.class 的形式会使 JVM 将使用类装载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回 Class 对象。

代码演示:
ReflectUser类

public class ReflectUser {
	
	private String name;
	
	private String addr;

	public ReflectUser() {
		System.out.println("调用无参函数了,哈哈哈。。。。");
	}
	
	public ReflectUser(String name, String addr) {
		super();
		System.out.println("调用有参函数了,咦咦咦.....");
		this.name = name;
		this.addr = addr;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}
	
	public String say(String str) {
		return str;
	}
	
	@Override
	public String toString() {
		return "ReflectUser [name=" + name + ", addr=" + addr + "]";
	}

2)Class.forName() 的形式会装入类并做类的静态初始化,返回 Class 对象。

forNameDemo()方法:

static void forNameDemo() throws ClassNotFoundException, InstantiationException, IllegalAccessException, 
				NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//创建此Class 对象所表示的类的一个新实例
		Class<?> forName = Class.forName("wmq.fly.reflection.ReflectUser");
		
		//调用了User的无参数构造方法.
		ReflectUser reflectUser = (ReflectUser) forName.newInstance();
		reflectUser.setName("铁军");
		reflectUser.setAddr("七连");
		System.out.println(reflectUser.toString());
		
		//调用了User的有参数构造方法.
		Constructor<?> constructor = forName.getConstructor(String.class,String.class);
		ReflectUser reflectUser2 = (ReflectUser) constructor.newInstance("小宁","七连");
		System.out.println(reflectUser2.toString());
	}

运行结果:
在这里插入图片描述
3).getClass() 的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的 Class 对象。
代码演示:

static void getClassDemo() throws NoSuchMethodException, SecurityException, IllegalAccessException, 
					IllegalArgumentException, InvocationTargetException {
		ReflectUser reflectUser = new ReflectUser();
		//调用了User的无参数构造方法.
		Class user = reflectUser.getClass();
		Method method = user.getMethod("say", String.class);
		Object invoke = method.invoke(reflectUser, "老刘");
		System.out.println(invoke);
	}

运行结果:
在这里插入图片描述

静态属性初始化是在加载类的时候初始化,而非静态属性初始化是 new 类实例对象的时候初始化。他们三种情况在生成 Class 对象的时候都会先判断内存中是否已经加载此类。

  1. 利用反射给私有属性赋值

代码演示:

static void assignmentValueToPrivate() throws ClassNotFoundException, InstantiationException, 
									IllegalAccessException, NoSuchFieldException, SecurityException {
		//创建此Class 对象所表示的类的一个新实例
		Class<?> forName = Class.forName("wmq.fly.reflection.ReflectUser");
		//获取当前类的所有属性
		Field[] fields = forName.getDeclaredFields();
		System.out.println("属性:");
		for(Field field : fields ) {
			System.out.println(field.getName());
		}
		
		//获取当前类的所有属性
		Method[] methods = forName.getDeclaredMethods();
		System.out.println("方法:");
		for(Method method : methods ) {
			System.out.println(method.getName());
		}
		
		//使用java的反射机制给私有属性赋值
		Object newInstance = forName.newInstance();
		Field fieldName = forName.getDeclaredField("name");
		//允许反射操作私有属性
		fieldName.setAccessible(true);
		fieldName.set(newInstance,"一乐");
		
		Field fieldAdrr = forName.getDeclaredField("addr");
		//允许反射操作私有属性
		fieldAdrr.setAccessible(true);
		fieldAdrr.set(newInstance,"下榕树");
		ReflectUser reflectUser = (ReflectUser)newInstance;
		System.out.println(reflectUser.toString());
	}
	

运行结果:
在这里插入图片描述

三、利用反射手写springIOC
实现原理

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

代码实现:
1.引入jar包

		<dependency>
			<groupId>org.dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>2.0.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>

2.applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<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:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-3.2.xsd
	
	http://www.springframework.org/schema/tx 
	http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
	
	http://www.springframework.org/schema/mvc 
	http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
	
	http://www.springframework.org/schema/task 
    http://www.springframework.org/schema/task/spring-task.xsd
     ">
     
	<bean id="reflectUser" class="wmq.fly.reflection.ReflectUser">
		<property name="name" value="二和"></property>
		<property name="addr" value="下榕树"></property>
	</bean>	
</beans>

3.解析applicationContext.xml实现springIOC:

public class ClassPathXmlApplicationContext {
	private String pathXml = null;

	public ClassPathXmlApplicationContext(String pathXml) {
		this.pathXml = pathXml;
	}

	public Object getBean(String beanId) throws Exception {
		if (StringUtils.isEmpty(beanId)) {
			throw new Exception("beanId is null");
		}
		//解析xml
		SAXReader saxReader = new SAXReader();
		//this.getClass().getClassLoader().getResource(pathXml)表示获取resource下的xml路径
		Document read = saxReader.read(this.getClass().getClassLoader().getResource(pathXml));
		// 获取到根节点
		Element rootElement = read.getRootElement();
		// 根节点下所有的子节点
		List<Element> elements = rootElement.elements();
		for (Element element : elements) {
			// 获取到节点上的属性
			String id = element.attributeValue("id");
			if (StringUtils.isEmpty(id)) {
				continue;
			}
			if (!id.equals(beanId)) {
				continue;
			}
			// 使用java反射机制初始化对象
			String beanClass = element.attributeValue("class");
			Class<?> forName = Class.forName(beanClass);
			Object newInstance = forName.newInstance();
			List<Element> propertyElementList = element.elements();
			//使用java的反射机制给私有属性赋值
			for (Element el : propertyElementList) {
				String name = el.attributeValue("name");
				String value = el.attributeValue("value");
				Field declaredField = forName.getDeclaredField(name);
				declaredField.setAccessible(true);
				declaredField.set(newInstance, value);
			}
			return newInstance;
		}
		return null;
	}

	public static void main(String[] args) throws Exception {
		ClassPathXmlApplicationContext classPath = new ClassPathXmlApplicationContext("applicationContext.xml");
		ReflectUser reflectUser = (ReflectUser) classPath.getBean("reflectUser");
		System.out.println(reflectUser.getName()+ "---" + reflectUser.getAddr());
	}
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值