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

一、什么是数据交换格式?

数据交换格式也叫报文,客户端与服务器常用数据交换格式xml(重量级占宽带比较大,传输重效率不高,所以不流行)、json(轻量级占宽带比较小,传输效率比xml高)、html
浏览器与服务器进行通讯使用html进行渲染。
服务化(提供接口):把一些功能提供成接口进行通讯。
链家租房、微信项目都是采用分布式、分模块开发的。
一些网站多终端兼容:PC、手机、平板。
1.PC端(电脑端):入口只有一个,网站。
2.移动端(APP):Android、IOS、移动Web(H5)、微信开发、支付宝开发等,入口很广。
bootstrap+h5可以自适应PC端和移动端,微信、支付宝开发里面嵌套的是H5页面。
当多终端开发需求时,可以理解成都是对数据库进行操作,为了减少代码重用,就有了服务器端接口的概念,为多个终端提供接口API即可,多个终端调用服务端接口时一般需要提供个source声明是何种终端调用,接口一般都是通过http+json进行传输。

二、数据交换格式应用场景

移动端(Android、IOS)通讯方式采用http协议+JSON格式,走restful风格。
很多互联网项目都采用Http协议+JSON
因为xml比较重,Webservice服务采用http+xml格式,银行保险项目使用较多。

三、数据交换格式

1、json简单理解
  1. json简介
    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,相比于xml这种数据交换格式来说,因为解析xml比较的复杂,而且需要编写大段的代码,所以客户端和服务器的数据交换格式往往通过JSON来进行交换。
    JSON:JavaScript 对象表示法(JavaScript Object Notation)。
    JSON的形式是用大括号“{}”包围起来的项目列表,每一个项目间用逗号(,)分隔,而项目就是用冒号(:)分隔的属性名和属性值。这是典型的字典表示形式,也再次表明javascript里的对象就是字典结构。不管多么复杂的对象,都可以用一句JSON代码来创建并赋值。在JSON中,名称 / 值对包括字段名称(在双引号中),后面写一个冒号,然后是值
    注意:json与jsonp区别?json是做数据格式传输的,jsonp是跨域请求时使用到的 ,浏览器有一个机制,不在同一域名下会有跨域问题,但是jsonp有一个缺点:是get请求。jsonp在公司网关接口搭建时会使用到。
       跨域问题只在浏览器中产生,如ajax请求一般使用json作为数据交换格式,不使用xml作为数据交换格式,所以xml不会产生跨域问题。
  2. JSON格式的分类
    JSON有两种结构:
    json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构
    1、对象:对象在js中表示为“{}”括起来的内容,数据结构为 {key:value,key:value,…}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是 数字、字符串、数组、对象几种。
    2、数组:数组在js中是中括号“[]”括起来的内容,数据结构为 [“java”,“javascript”,“vb”,…],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种。
    经过对象、数组2种结构就可以组合成复杂的数据结构了。
  3. 常用JSON解析框架:
    fastjson(阿里):web服务器端开发用的比较多、gson(谷歌):安卓开发用的多、jackson(SpringMVC自带)
  4. 解析、组装JSON的代码实现
    1. 使用阿里的fastjson解析json
      package chauncy.dataswitching.json;
      
      import com.alibaba.fastjson.JSONArray;
      import com.alibaba.fastjson.JSONObject;
      
      /**
       * @classDesc: 功能描述:(fastjson 解析)
       * @author: ChauncyWang
       * @verssion: v1.0
       */
      public class JsonAnalysis {
      	static String JSONSTR = "{\"user\":[{\"name\":\"小红\",\"sex\":\"女\"},{\"name\":\"小黑\",\"sex\":\"男\"}]}";
      
      	public static void main(String[] args) {
      		//1.将json字符串转换成jsonObject
      		JSONObject jsonObject = new JSONObject();
      		//json对象
      		JSONObject parseObject = jsonObject.parseObject(JSONSTR);
      		//获取json数组对象
      		JSONArray jsonArray = parseObject.getJSONArray("user");
      		for (Object object : jsonArray) {
      			JSONObject jo=(JSONObject) object;
      			//不要使用强转String的方法,因为fastjsonAPI中有getString方法
      			String name=jo.getString("name");
      			String sex=jo.getString("sex");
      			System.out.println(name+"---------"+sex);
      		}
      	}
      }
      
    2. 使用阿里的fastjson组装json
      package chauncy.dataswitching.json;
      
      import com.alibaba.fastjson.JSONArray;
      import com.alibaba.fastjson.JSONObject;
      
      /**
       * @classDesc: 功能描述:(组装json)
       * @author: ChauncyWang
       * @verssion: v1.0
       */
      public class JsonAssemble {
      	public static void main(String[] args) {
      		JSONObject jsonObject = new JSONObject();
      		JSONArray jsonArray = new JSONArray();
      		JSONObject bean1=new JSONObject();
      		bean1.put("name", "小红");
      		bean1.put("sex", "女");
      		jsonArray.add(bean1);
      		JSONObject bean2=new JSONObject();
      		bean2.put("name", "小黑");
      		bean2.put("sex", "男");
      		jsonArray.add(bean2);
      		jsonObject.put("user", jsonArray);
      		System.out.println(jsonObject.toJSONString());
      		
      	}
      }
      
2、XML简单理解
  1. XML定义
    它是可扩展标记语言(Extensible Markup Language,简称XML),是一种标记语言。
    XML 全称为可扩展的标记语言。主要用于描述数据和用作配置文件
    XML 文档在逻辑上主要由一下 5 个部分组成
    1、XML 声明:指明所用 XML 的版本、文档的编码、文档的独立性信息
    2、文档类型声明:指出 XML 文档所用的 DTD
    3、元素:由开始标签、元素内容和结束标签构成
    4、注释:以结束,用于对文档中的内容起一个说明作用
    5、处理指令:通过处理指令来通知其他应用程序来处理非 XML 格式的数据,格式为
      XML 文档的根元素被称为文档元素,它和在其外部出现的处理指令、注释等作为文档实体的子节点,根元素本身和其内部的子元素也是一棵树。
    XML结构类似于生活中的树,有根节点有子节点
  2. XML解析方式
    Dom4j(小文件)、Sax(大文件)、Pull等
    Dom4j与Sax区别:dom4j不适合大文件的解析,因为它是一下子将文件加载到内存中,所以有可能出现内存溢出,sax是基于事件来对xml进行解析的,所以他可以解析大文件的xml,也正是因为如此,所以dom4j可以对xml进行灵活的增删改查和导航,而sax没有这么强的灵活性,所以sax经常是用来解析大型xml文件,而要对xml文件进行一些灵活(crud)操作就用dom4j。
  3. 解析XML的代码实现:
    1. 创建user.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <user>
          <user1 id="01">
              <名字>小红</名字>
              <性别></性别>
          </user1>
          <user2 id="02">
              <名字>小黑</名字>
              <性别></性别>
          </user2>
      </user>  
      
    2. 创建解析xml的java类XmlAnalysis.java
      package chauncy.dataswitching.xml;
      
      import java.io.File;
      import java.util.Iterator;
      import java.util.List;
      
      import org.dom4j.Attribute;
      import org.dom4j.Document;
      import org.dom4j.DocumentException;
      import org.dom4j.Element;
      import org.dom4j.io.SAXReader;
      
      /**
       * @classDesc: 功能描述(使用xml进行解析)
       * @author: ChauncyWang
       * @version: 1.0
       */
      public class XmlAnalysis {
      	static String FILENAME = "{系统中XML绝对路劲}\\src\\main\\resources\\user.xml";
      
      	public static void main(String[] args) throws DocumentException {
      		// 获取xml解析器
      		SAXReader saxReader = new SAXReader();
      		Document read = saxReader.read(new File(FILENAME));
      		// 拿到根节点,只要拿到根节点子节点也会一并拿到
      		Element rootElement = read.getRootElement();
      		getNodes(rootElement);
      	}
      
      	static public void getNodes(Element rootElement) {
      		System.out.println("节点名称:" + rootElement.getName());
      		// 拿到节点属性
      		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);
      		}
      	}
      }
      

四、Java反射机制

  1. 什么是Java反射?
    就是正在运行,动态获取这个类的所有信息
  2. 反射机制的作用:
    1.反编译:.class–>java
    2.通过反射机制访问java对象的属性、方法、构造方法等
  3. 反射机制的应用场景:
    Jdbc加载驱动、SpringIOC实现、框架(Hibernate)、注解的底层实现等。
    每个驱动地址jar包不一样所以需要用反射区加载jdbc驱动。
    Hibernate框架实体类必须有无参构造方法,因为底层使用反射forName.newInstance(),不声明的话这句话会报错。
  4. 使用反射技术和new哪个效率高?
    使用new效率高,因为反射需要读取class地址之后再执行一些列步骤
    注意:除了new创建对象,还可以使用反射机制创建对象,使用反射机制创建对象的话,可以使用该类有参或者无参构造函数创建对象,可以只获取当前类的属性、方法,也可以获取当前类+父类的属性、方法,具体实现差异体现在代码上。
        可以通过反射机制在不同包下的类访问该类的私有成员变量。
  5. 反射机制获取类的三种方法:
    //第一种方式(根据类的路径创建):  
    Class c1 = Class.forName("com.chauncy.entity.User");  
    //第二种方式(直接通过类名.class创建):  
    //java中每个类都有class 属性.  
    Class c2 = User.class;  
    //第三种方式(对象的运行时类):  
    //java语言中任何一个java对象都有getClass 方法  
    User  u = new User();  
    Class c3 =  u.getClass(); //c3是运行时类 (u的运行时类是User)  	
    
  6. 反射创建对象的方式:
    1. 使用无参构造函数
      Class<?> forName = Class.forName("chauncy.reflect.entity.UserEntity");
      // newInstance使用无参构造函数创建对象,等同于new 
      Object newInstance = forName.newInstance(); 
      
    2. 使用有参构造函数
      Class<?> forName = Class.forName("chauncy.reflect.entity.UserEntity");
      //使用有参构造函数创建对象
      Constructor<?> constructor = forName.getConstructor(String.class);
      Object newInstance = constructor.newInstance("123");	
      UserEntity user=(UserEntity) newInstance;
      
  7. 反射创建api:
    getDeclaredMethods []   获取该类的所有方法
    getReturnType()   获取该类的返回值
    getParameterTypes()   获取传入参数
    getDeclaredFields()   获取该类的所有字段
    setAccessible   允许访问私有成员
  8. 使用反射机制访问私有属性:
    //可以使用反射机制访问到私有属性
    Field declaredFields = forName.getDeclaredField("userId");
    Object obj = forName.newInstance();
    //允许访问私有成员属性
    declaredFields.setAccessible(true);
    declaredFields.set(obj, "123");
    UserEntity user=(UserEntity) obj;
    System.out.println(user.getUserId());
    
  9. 反射机制完整应用代码:
    1. 创建需要反射的类UserEntity.java
      package chauncy.reflect.entity;
      
      /**
       * @classDesc: 功能描述(用户实体类)
       * @author: ChauncyWang
       * @version: 1.0
       */
      public class UserEntity {
      
      	private String userId;
      	private String userName;
      
      	public UserEntity() {
      		System.out.println("使用反射机制执行无参构造函数");
      	}
      
      	public UserEntity(String userId) {
      		System.out.println("使用反射机制执行有参构造函数--userId:" + userId);
      	}
      
      	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;
      	}
      
      }
      
    2. 创建反射类ReflexMechanismApplication.java动态获取类UserEntity.java的信息
      package chauncy.reflect;
      
      import java.lang.reflect.Constructor;
      import java.lang.reflect.Field;
      import java.lang.reflect.InvocationTargetException;
      import java.lang.reflect.Method;
      
      import chauncy.reflect.entity.UserEntity;
      
      /**
       * @classDesc: 功能描述(使用反射机制,调用类的无参、有参构造方法创建对象,使用反射获取该类的所有属性、方法(包含父类与不包含父类),使用反射机制访问不同包下类的私有成员变量)
       * @author: ChauncyWang
       * @version: 1.0
       */
      public class ReflexMechanismApplication {
      	public static void main(String[] args)
      			throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException, SecurityException {
      		// 1.除了new创建对象,还可以使用反射机制创建对象。
      		// UserEntity userEntity = new UserEntity();
      		// 2.forName() 必须传入class类的完整路径。
      		// 返回值就是对应类的字节码文件
      		Class<?> forName = Class.forName("chauncy.reflect.entity.UserEntity");
      		/*
      		 * // 3.newInstance使用无参构造函数创建对象,等同于new 
      		 * Object newInstance = forName.newInstance(); 
      		 * UserEntity user = (UserEntity) newInstance;
      		 * System.out.println("user:" + user); 
      		 * user.setUserId("123");
      		 * System.out.println(user.getUserId()); 
      		 * // 使用反射技术和new哪个效率高?使用new效率高,因为反射需要读取class地址之后再执行一些列步骤 
      		 * // 为什么有一些框架需要声明类的无参构造方法,如Hibernate框架实体类必须有无参构造方法,因为底层使用反射forName.newInstance(),不声明的话这句话会报错。
      		 */
      		
      		
      		/*//使用有参构造函数创建对象
      		Constructor<?> constructor = forName.getConstructor(String.class);
      		Object newInstance = constructor.newInstance("123");	
      		UserEntity user=(UserEntity) newInstance;*/
      		
      		
      		
      		/*//使用反射获取该类的所有方法(不包含父类)
      		Method[] declaredMethods = forName.getDeclaredMethods();
      		for (Method method : declaredMethods) {
      			System.out.println(method.getName()+"---------"+method.getReturnType());
      		}*/
      		
      		/*//使用反射获取该类的所有成员属性(不包含父类)
      		Field[] declaredFields = forName.getDeclaredFields();
      		for (Field field : declaredFields) {
      			System.out.println(field.getName());
      		}*/
      		
      		
      		/*//使用反射获取该类的所有方法(包含父类)
      		Method[] declaredMethods = forName.getMethods();
      		for (Method method : declaredMethods) {
      			System.out.println(method.getName()+"---------"+method.getReturnType());
      		}
      		//Object类下有哪些方法?
      		//wait---------void
      		//wait---------void
      		//wait---------void
      		//equals---------boolean
      		//toString---------class java.lang.String
      		//hashCode---------int
      		//getClass---------class java.lang.Class
      		//notify---------void
      		//notifyAll---------void
      		 */		
      		
      		
      		//可以使用反射机制访问到私有属性
      		Field declaredFields = forName.getDeclaredField("userId");
      		Object obj = forName.newInstance();
      		//允许访问私有成员属性
      		declaredFields.setAccessible(true);
      		declaredFields.set(obj, "123");
      		UserEntity user=(UserEntity) obj;
      		System.out.println(user.getUserId());
      	}
      }
      

五、SpringIOC底层实现

  1. 什么是SpringIOC
    SpringIOC就是把每一个bean(实体类)与bean(实体类)之间的关系都交给第三方容器(Spring)进行管理
    使用Spring的时候,对象不需要new。
    Spring原理:反射+dom4j
  2. Spring的加载过程/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,或者下没有子标签都会返回null。
  3. 模拟SpringIOC底层实现代码:
    1. 创建模拟Spring的配置文件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:aop="http://www.springframework.org/schema/aop"
      	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
      	xsi:schemaLocation="    
           http://www.springframework.org/schema/beans     
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    
           http://www.springframework.org/schema/tx     
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd    
           http://www.springframework.org/schema/aop     
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd    
           http://www.springframework.org/schema/context    
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">
      
      	<bean id="user1" class="chauncy.reflect.entity.UserEntity">
      		<property name="userId" value="0002"></property>
      		<property name="userName" value="张三"></property>
      	</bean>
      	<bean id="user2" class="chauncy.reflect.entity.UserEntity">
      		<property name="userId" value="0002"></property>
      		<property name="userName" value="张三"></property>
      	</bean>
      </beans>   
      
    2. 创建反射类ClassPathXmlApplicationContext.java解析Spring配置文件
      package chauncy.springioc;
      
      import java.lang.reflect.Field;
      import java.util.List;
      
      import javax.swing.text.StyledEditorKit.ForegroundAction;
      
      import org.dom4j.Document;
      import org.dom4j.DocumentException;
      import org.dom4j.Element;
      import org.dom4j.io.SAXReader;
      
      import chauncy.reflect.entity.UserEntity;
      
      /**
       * @classDesc: 功能描述(Spring加载过程/SpringIOC底层代码实现)
       * @author: ChauncyWang
       * @version: 1.0
       */
      public class ClassPathXmlApplicationContext {
      	private String xmlPath;
      
      	public ClassPathXmlApplicationContext(String xmlPath) {
      		this.xmlPath = xmlPath;
      	}
      
      	public Object getBean(String beanId) throws DocumentException, ClassNotFoundException, NoSuchFieldException,
      			SecurityException, InstantiationException, IllegalAccessException {
      		// 1.读取xml配置文件
      		// 获取XML解析器
      		SAXReader saxReader = new SAXReader();
      		// 获取当前项目路径
      		Document read = saxReader.read(this.getClass().getClassLoader().getResourceAsStream(xmlPath));
      		// 获取根节点对象
      		Element rootElement = read.getRootElement();
      		List<Element> elements = rootElement.elements();
      		Object obj = null;
      		for (Element sonEle : elements) {
      			String sonBeanId = sonEle.attributeValue("id");
      			if (!sonBeanId.equals(beanId)) {
      				continue;
      			}
      			// 2.获取到每个bean的配置 获取class地址
      			String beanClassPath = sonEle.attributeValue("class");
      			// 3.拿到class地址进行反射实例化对象,使用反射api为私有属性赋值
      			Class<?> forName = Class.forName(beanClassPath);
      			obj = forName.newInstance();
      			// 拿到类的成员变量
      			List<Element> grandSonElement = sonEle.elements();
      			for (Element element : grandSonElement) {
      				String name = element.attributeValue("name");
      				String value = element.attributeValue("value");
      				// 使用反射api为私有属性赋值
      				Field declaredField = forName.getDeclaredField(name);
      				// 允许往私有成员赋值
      				declaredField.setAccessible(true);
      				declaredField.set(obj, value);
      			}
      
      		}
      		return obj;
      	}
      
      	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException,
      			InstantiationException, IllegalAccessException, DocumentException {
      		ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
      		Object bean = application.getBean("user1");
      		UserEntity user = (UserEntity) bean;
      		System.out.println(user.getUserId() + "----" + user.getUserName());
      	}
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值