首先在此声明,本人是通过学习湖畔微风《深入浅出mybatis》基础之上对代码进行总结。
《深入浅出mybatis》 http://blog.csdn.net/hupanfeng/article/details/9068003
1、mybatis解析配置文件
SqlSessionFactoryBuilder类是mybatis的入口,在创建SqlSeesionFactory时会解析配置文件,将文件中的信息保存在Configuration对象中。
其中的类XmlConfigureBulider类其中,调用XPathParser类的parse方法,获得configuration根节点并调用parseConfiguration方法,XPathParser为解析xml的核心类
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
parseConfiguration方法相当于1个中转站,它获得configuration下不同的子节点,并调用相应的方法去解析
private void parseConfiguration(XNode root) {
try {
propertiesElement(root.evalNode("properties")); //issue #117 read properties first
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
settingsElement(root.evalNode("settings"));
environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory issue #631
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);
}
}
上述两个方法中都用到了evalNode方法返回Xnode类,其中evaluate方法获得目标结节点,并创建XNode 类
public XNode evalNode(Object root, String expression) {
Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
if (node == null) {
return null;
}
return new XNode(this, node, variables);
}
Xnode中的构造方法,解析了节点属性和所有子节点
构造方法:
</pre><pre name="code" class="java"> public XNode(XPathParser xpathParser, Node node, Properties variables) {
this.xpathParser = xpathParser;
this.node = node;
this.name = node.getNodeName();
this.variables = variables;
this.attributes = parseAttributes(node);
this.body = parseBody(node);
}
解析属性:
private Properties parseAttributes(Node n) {
Properties attributes = new Properties();
NamedNodeMap attributeNodes = n.getAttributes();
if (attributeNodes != null) {
for (int i = 0; i < attributeNodes.getLength(); i++) {
Node attribute = attributeNodes.item(i);
String value = PropertyParser.parse(attribute.getNodeValue(), variables);
attributes.put(attribute.getNodeName(), value);
}
}
return attributes;
}
获得所有子节点:
private String parseBody(Node node) {
String data = getBodyData(node);
if (data == null) {
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
data = getBodyData(child);
if (data != null) break;
}
}
return data;
}
总结:(1)通过学习源代码了解解析流程
(2)学习1下解析XML程序设计的思路。mybatis设计解析xml符合开闭原则,如果以后配置文件要在configuration节点下增加新的子节点,只需增加相应的解析方法,其它地方基本不用修改。如果已存在的子节点中内容有修改,只需修改不同子节点相应的方法,不会对其它解析节点方法产生影响。
2、SqlSession对数据库的操作
在《mybatis深入浅出》中所说SqlSession对数据库的操作以下:
SqlSession session= sqlSessionFactory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
UserDto user = new UserDto();
user.setUsername("iMybatis");
List<UserDto> users = userDao.queryUsers(user);
其中session.getMapper(UserDao.class)获得的是UserDao的代理对象
先获得创建代理对象的工厂类
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null)
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
在工厂类中,创建代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
代理类中,履行完目标方法后,会将method存入cacheMapperMethod供以后调用。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
总结:(1)熟习流程
(2)代码其实不难,主要是通过学习源码温习1下jdk动态代理、反射等相干基础知识。