最近在研究spring以及mybatis源码,这两款优秀框架的使用必然是从加载配置文件来加载配置的,闲话少说,先进入spring加载配置文件过程
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<bean id="hello" class="com.HelloEntity">
<!-- 配置该Bean需要注入的属性(是通过属性set方法来注入的) -->
<property name="info" value="Happy New Year!"/>
</bean>
</beans>
配置文件中并没有设置与其他框架整合,仅仅是注册一个HelloBeanEntity
使用方式贴一个简单代码
BeanFactory beanFactory= new ClassPathXmlApplicationContext("appclicationcontext.xml");
HelloEntity helloEntity=(HelloEntity)beanFactory.getBean("hello");
第一行代码 spring加载appclicationcontext.xml数据,解析出bean标签,将HelloEntity注册并初始化后
放入singleonObjects缓存中
第二行代码 spring在singleonObjects根据id取到第一步加载的对象
直接上spring加载xml中代码 spring将appclicationcontext.xml加载为inputstream之后
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
if(logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
其实spring还是用的javax.xml.parsers.DocumentBuilderFactory,采用sax方式读取xml并封装返回值document(w3c),
简单说一下xml解析基本方式,1 sax基于事件驱动机制,逐行读取,读到一个标签就处理,不占用内存,处理完就回不去了
2 dom将整个xml加载为一个dom树,类似前端html元素,可以修改dom树,操作期间数据都在内存
介绍一下代码中的entityResolver以及errorHandler
ErrorHandler
public class SimpleSaxErrorHandler implements ErrorHandler {
private final Log logger;
public SimpleSaxErrorHandler(Log logger) {
this.logger = logger;
}
public void warning(SAXParseException ex) throws SAXException {
this.logger.warn("Ignored XML validation warning", ex);
}
public void error(SAXParseException ex) throws SAXException {
throw ex;
}
public void fatalError(SAXParseException ex) throws SAXException {
throw ex;
}
}
其实就是在解析过程中按照错误log级别处理,spring中是error以上会直接向上抛异常
EntityResolver
在XML的验证段落里面提到过DTD的定位. EntityResolver可以帮助我们做这件事情. EntityResolver里面只有一个方法,叫做ResolveEntity(publicId, systemId). 每当Parser需要使用external文件的时候,就会调用这个方法. 我们可以在这个方法里面做一些预处理. 代码如下:
看一下spring实现的EntityResolver中解析会调用的方法
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if(systemId != null) {
if(systemId.endsWith(".dtd")) {
return this.dtdResolver.resolveEntity(publicId, systemId);
}
if(systemId.endsWith(".xsd")) {
return this.schemaResolver.resolveEntity(publicId, systemId);
}
}
return null;
}
Element root = doc.getDocumentElement();//获取根节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
spring中主要的4个标签,这边不继续说了,下边会单独开一篇,下面进入mybatis的解析
先来一个mybatis配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>H
<typeAlias alias="hello" type="com.HelloEntity"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="">
......
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/HelloMapper.xml"/>
</mappers>
</configuration>
代码
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSession session = sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
HelloDao helloDao = session.getMapper(HelloDao.class);//可以直接调sql了
下边进入mybaits xml解析
mybaits有自己封装几个类帮助解析,但是最后还是用的跟spring一模一样的解析方式
直接贴
mybatis的entityResolver以及errorHandler
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
try {
if(systemId != null) {
String e = systemId.toLowerCase(Locale.ENGLISH);
if(e.contains("mybatis-3-config.dtd") || e.contains("ibatis-3-config.dtd")) {
return this.getInputSource("org/apache/ibatis/builder/xml/mybatis-3-config.dtd", publicId, systemId);
}
if(e.contains("mybatis-3-mapper.dtd") || e.contains("ibatis-3-mapper.dtd")) {
return this.getInputSource("org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd", publicId, systemId);
}
}
return null;
} catch (Exception var4) {
throw new SAXException(var4.toString());
}
}
有木有感觉跟spring很像,都是针对配置文件的头部
errorhandler更是基本一样
new ErrorHandler() {
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
public void warning(SAXParseException exception) throws SAXException {
}
});
个人对于mybaits的理解就是这个框架将你在配置文件里的sql以及返回type加载到map里边,当你调用你写的mapper接口时
其实已经被动态代理,最后还是connection去执行sql,由于你配置了type,会直接反射返回的数据,完成orm映射
举例一个最简单的配置文件
<?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:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<bean id="hello" class="com.HelloEntity">
<!-- 配置该Bean需要注入的属性(是通过属性set方法来注入的) -->
<property name="info" value="Happy New Year!"/>
</bean>
</beans>
配置文件中并没有设置与其他框架整合,仅仅是注册一个HelloBeanEntity
使用方式贴一个简单代码
BeanFactory beanFactory= new ClassPathXmlApplicationContext("appclicationcontext.xml");
HelloEntity helloEntity=(HelloEntity)beanFactory.getBean("hello");
System.out.println(helloEntity.info);
仅仅三行代码,但是五脏俱全,简单来说,第一行代码 spring加载appclicationcontext.xml数据,解析出bean标签,将HelloEntity注册并初始化后
放入singleonObjects缓存中
第二行代码 spring在singleonObjects根据id取到第一步加载的对象
直接上spring加载xml中代码 spring将appclicationcontext.xml加载为inputstream之后
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
if(logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
其实spring还是用的javax.xml.parsers.DocumentBuilderFactory,采用sax方式读取xml并封装返回值document(w3c),
简单说一下xml解析基本方式,1 sax基于事件驱动机制,逐行读取,读到一个标签就处理,不占用内存,处理完就回不去了
2 dom将整个xml加载为一个dom树,类似前端html元素,可以修改dom树,操作期间数据都在内存
介绍一下代码中的entityResolver以及errorHandler
ErrorHandler
用于处理XML解析阶段所发生的警告和错误.里面有三个方法,warning(), error()和fatalError(). waring和error用于处理XML的validation(DTD或XSD)错误.这种错误并不影响XML的解析,你可以把这种错误产生的exception压下来,而不向上抛.这样XML的解析不会被终断. fatalError是XML结构错误,这种错误无法被压制,即使我的handler不抛,Parser会向外抛exception.
public class SimpleSaxErrorHandler implements ErrorHandler {
private final Log logger;
public SimpleSaxErrorHandler(Log logger) {
this.logger = logger;
}
public void warning(SAXParseException ex) throws SAXException {
this.logger.warn("Ignored XML validation warning", ex);
}
public void error(SAXParseException ex) throws SAXException {
throw ex;
}
public void fatalError(SAXParseException ex) throws SAXException {
throw ex;
}
}
其实就是在解析过程中按照错误log级别处理,spring中是error以上会直接向上抛异常
EntityResolver
在XML的验证段落里面提到过DTD的定位. EntityResolver可以帮助我们做这件事情. EntityResolver里面只有一个方法,叫做ResolveEntity(publicId, systemId). 每当Parser需要使用external文件的时候,就会调用这个方法. 我们可以在这个方法里面做一些预处理. 代码如下:
看一下spring实现的EntityResolver中解析会调用的方法
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if(systemId != null) {
if(systemId.endsWith(".dtd")) {
return this.dtdResolver.resolveEntity(publicId, systemId);
}
if(systemId.endsWith(".xsd")) {
return this.schemaResolver.resolveEntity(publicId, systemId);
}
}
return null;
}
是针对两种xml分别处理的
回到spring流程,目前是已经加载获得了document,解析来就是去读取document(代码精简了一下)Element root = doc.getDocumentElement();//获取根节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
spring中主要的4个标签,这边不继续说了,下边会单独开一篇,下面进入mybatis的解析
先来一个mybatis配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>H
<typeAlias alias="hello" type="com.HelloEntity"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="">
......
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/HelloMapper.xml"/>
</mappers>
</configuration>
代码
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSession session = sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
HelloDao helloDao = session.getMapper(HelloDao.class);//可以直接调sql了
下边进入mybaits xml解析
mybaits有自己封装几个类帮助解析,但是最后还是用的跟spring一模一样的解析方式
直接贴
mybatis的entityResolver以及errorHandler
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
try {
if(systemId != null) {
String e = systemId.toLowerCase(Locale.ENGLISH);
if(e.contains("mybatis-3-config.dtd") || e.contains("ibatis-3-config.dtd")) {
return this.getInputSource("org/apache/ibatis/builder/xml/mybatis-3-config.dtd", publicId, systemId);
}
if(e.contains("mybatis-3-mapper.dtd") || e.contains("ibatis-3-mapper.dtd")) {
return this.getInputSource("org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd", publicId, systemId);
}
}
return null;
} catch (Exception var4) {
throw new SAXException(var4.toString());
}
}
有木有感觉跟spring很像,都是针对配置文件的头部
errorhandler更是基本一样
new ErrorHandler() {
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
public void warning(SAXParseException exception) throws SAXException {
}
});
个人对于mybaits的理解就是这个框架将你在配置文件里的sql以及返回type加载到map里边,当你调用你写的mapper接口时
其实已经被动态代理,最后还是connection去执行sql,由于你配置了type,会直接反射返回的数据,完成orm映射