Mybatis 启动流程
@Before
public void init() throws IOException {
String resouce = "mybatis-config.xml";
/**
* 读取 mybatis文件,返回的是 InputStream流
*/
InputStream inputStream = Resources.getResourceAsStream(resouce);
/**
* 使用 SqlSessionFactoryBuilder 来构建出一个 SqlSessionFactory来.
*/
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession();
}
- 通过Resouces提供的getResourceAsStream,加载mybatis-config.xml 文件,从下面的源码中可以看到,不仅可以读取转为InputStream,还可以返回Reader,Properties
/**
* A class to simplify access to resources through the classloader.
*
* @author Clinton Begin
*/
public class Resources {
private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
/*
* Returns a resource on the classpath as a Stream object
*
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static InputStream getResourceAsStream(String resource) throws IOException {
return getResourceAsStream(null, resource);
}
/*
* Returns a resource on the classpath as a Stream object
*
* @param loader The classloader used to fetch the resource
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
throw new IOException("Could not find resource " + resource);
}
return in;
}
/*
* Returns a resource on the classpath as a Properties object
*
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static Properties getResourceAsProperties(String resource) throws IOException {
Properties props = new Properties();
InputStream in = getResourceAsStream(resource);
props.load(in);
in.close();
return props;
}
/*
* Returns a resource on the classpath as a Properties object
*
* @param loader The classloader used to fetch the resource
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static Properties getResourceAsProperties(ClassLoader loader, String resource) throws IOException {
Properties props = new Properties();
InputStream in = getResourceAsStream(loader, resource);
props.load(in);
in.close();
return props;
}
/*
* Returns a resource on the classpath as a Reader object
*
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static Reader getResourceAsReader(String resource) throws IOException {
Reader reader;
if (charset == null) {
reader = new InputStreamReader(getResourceAsStream(resource));
} else {
reader = new InputStreamReader(getResourceAsStream(resource), charset);
}
return reader;
}
/*
* Returns a resource on the classpath as a Reader object
*
* @param loader The classloader used to fetch the resource
* @param resource The resource to find
* @return The resource
* @throws java.io.IOException If the resource cannot be found or read
*/
public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException {
Reader reader;
if (charset == null) {
reader = new InputStreamReader(getResourceAsStream(loader, resource));
} else {
reader = new InputStreamReader(getResourceAsStream(loader, resource), charset);
}
return reader;
}
}
- new SqlSessionFactoryBuilder().build() 读取文件流,并解析,其中提供了包含Reader和InputStream的重载方法,于Resources中提供的方法相对应。
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
// 这次我使用的是该方法,传入的是inputStream.
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//new XMLConfigBuilder()构造方法,
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 重点:使用XMLConfigBuilder的parse方法,去解析xml配置文件
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
- 使用XMLConfigBuilder构造方法构建对象,
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
//XMLMapperEntityResolver mybatis的实体解析器
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
// 解析xml 配置文件,返回一个configuration对象,从这儿可以看出,加载的配置内容都是存放在Configuration对象中。
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// parser.evalNode("/configuration")
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
// 这部分是解析xml文件中的每个节点配置,之后单独再分析
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
4.创建XPathParser解析器来解析Xml文件。
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}
// 给属性赋值,获取xpath对象
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
// 获取XpathFactory 类实例
XPathFactory factory = XPathFactory.newInstance();
// 使用factory创建XPathImpl对象
this.xpath = factory.newXPath();
}
//使用Document解析器,返回Document对象
private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
// 创建DocumentBuilderFactoryImpl 实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(validation);
factory.setNamespaceAware(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(true);
// 使用工厂创建DocumentBuilder,再使用build去解析xml文件流
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(entityResolver);
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
}
});
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
通过实现类DocumentBuilderImpl 解析文件流
public Document parse(InputSource is) throws SAXException, IOException {
if (is == null) {
throw new IllegalArgumentException(
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
"jaxp-null-input-source", null));
}
if (fSchemaValidator != null) {
if (fSchemaValidationManager != null) {
fSchemaValidationManager.reset();
fUnparsedEntityHandler.reset();
}
resetSchemaValidator();
}
// 采用DomParser 解析器解析xml文件
domParser.parse(is);
Document doc = domParser.getDocument();
domParser.dropDocumentReferences();
return doc;