在阅读一遍源码后, 决定根据自己的理解模拟一下mybatis
先对mybatis的整个流程进行梳理:
分析:
- 创建SqlSessionFactory; mybatis首先会去解析configuration.xml配置文件, 在解析这个配置文件时会对一些配置进行初始化, 例如数据源, mapper文件等; 这里要注意的时在解析mapper文件时, 对根据接口路径生成对应的MapperProxyFactory, 后面会需要通过MapperProxyFactory来创建代理类(采用JDK动态代理)
- 创建SqlSession; 将解析封装好的Configuration对象封装到SqlSession实例中, 因为我们是通过SqlSession中的相应select方法去查询数据, 而查询数据需要的sql相关信息,我们解析后封装在configuration中;
- 通过sqlSession的selectOne()方法去数据库查询; 相关操作委托给BaseExecutor和CachingExecutor处理器, 首先会调用CachingExecutor处理器进行处理, 在该处理器中会尝试通过二级缓存获取, 获取失败后再通过BaseExecutor处理器去数据库查询, 在去数据库查询之前会尝试通过一级缓存获取
- 通过session.getMapper()方法获取指定类型的接口实现类, 该实现类是通过MapperProxyFactory使用JDK动态代理进行实现, 对接口方法中的逻辑进行增强; 相关逻辑主要在MapperProxy中实现, 通过MapperProxyFactory对应的接口路径,以及方法名称可得到statementId, 根据statementId可以获取到MapperStatement, 而sql相关信息维护在MapperStatement中, 在获取MapperStatement后, 就可以进行数据查询, 以及结果封装
配置类:
Configuration类, 用于将解析configuration.xml中的信息进行封装
package core;
import org.apache.log4j.Logger;
import proxy.MapperProxyFactory;
import xml.XMLConfigBuilder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Configuration {
private static Logger logger = Logger.getLogger(Configuration.class);
private Map<String,String> properties;
private List<Mapper> mappers;
private Map<String, MapperStatement> mapperStatements;
private Connection connection;
private Map<Class, MapperProxyFactory> knownMappers;
public Map<Class, MapperProxyFactory> getKnownMappers() {
if (knownMappers == null){
knownMappers = new HashMap<Class, MapperProxyFactory>();
}
return knownMappers;
}
public void setKnownMappers(Map<Class, MapperProxyFactory> knownMappers) {
this.knownMappers = knownMappers;
}
public Connection getConnection() {
return connection;
}
public void initConnection(String driver, String url, String user, String pwd) {
logger.info("初始化连接....");
if(connection == null){
try {
Class.forName(driver);
connection = DriverManager.getConnection(url,user,pwd);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void setMapperStatements(Map<String, MapperStatement> mapperStatements) {
this.mapperStatements = mapperStatements;
}
public Map<String, MapperStatement> getMapperStatements() {
return mapperStatements;
}
public void addMapperStatement(String statementId, MapperStatement mapperStatement) {
if(mapperStatements == null){
mapperStatements = new HashMap<String, MapperStatement>();
}
mapperStatements.put(statementId,mapperStatement);
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public List<Mapper> getMappers() {
return mappers;
}
public void setMappers(List<Mapper> mappers) {
this.mappers = mappers;
}
}
BoundSql类, 将sql语句和参数,参数类型以及结果类型进行整合,便于后面执行sql
package core;
public class BoundSql {
private String sql;
private String parameterType;
private String resultType;
private MapperStatement mapperStatement;
public BoundSql(MapperStatement mapperStatement) {
this.mapperStatement = mapperStatement;
this.parameterType = mapperStatement.getParameterType();
this.resultType = mapperStatement.getResultType();
this.sql = mapperStatement.getSql();
}
public MapperStatement getMapperStatement() {
return mapperStatement;
}
public void setMapperStatement(MapperStatement mapperStatement) {
this.mapperStatement = mapperStatement;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
}
Mapper类, 用于封装configuration.xml中<mappers>的子节点数据
package core;
public class Mapper {
private String value;
private String type;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
MapperStatement类, 用于将解析mapper.xml中的信息进行封装
package core;
public class MapperStatement {
private String id;
private String parameterType;
private String resultType;
private String command;
private String sql;
public MapperStatement(String id, String parameterType, String resultType, String command, String sql) {
this.id = id;
this.parameterType = parameterType;
this.resultType = resultType;
this.command = command;
this.sql = sql;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
}
工厂类:
SqlSessionFactoryBuilder类, 根据解析后的Configuration实例创建SqlSessionFactory实例
package core;
import xml.XMLConfigBuilder;
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(String path){
XMLConfigBuilder parser = new XMLConfigBuilder(path);
return build(parser.parse());
}
public SqlSessionFactory build(Configuration configuration){
return new DefaultSqlSessionFactory(configuration);
}
public static void main(String[] args) {
new SqlSessionFactoryBuilder().build("configuration.xml");
}
}
DefaultSqlSessionFactory类, 用于创建SqlSession实例
package core;
import executor.BaseExecutor;
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
public SqlSession openSession() {
return new DefaultSqlSession(configuration);
}
}
MapperProxyFactory类, 用于创建mapper接口的实现类
package proxy;
import core.SqlSession;
import java.lang.reflect.Proxy;
public class MapperProxyFactory<T> {
private Class mapperInterface;
public MapperProxyFactory(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
protected Object newInstance(MapperProxy mapperProxy) {
return Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public Object newInstance(SqlSession sqlSession) {
final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface);
return newInstance(mapperProxy);
}
}
解析器类
XMLConfigBuilder类, 用于解析xml文件, 将解析到的信息封装到Configuration中
package xml;
import java.io.File;
import java.util.*;
import core.Configuration;
import core.Mapper;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class XMLConfigBuilder {
private static Logger logger = Logger.getLogger(XMLConfigBuilder.class);
private Document document;
private Configuration configuration;
public XMLConfigBuilder(String path) {
configuration = new Configuration();
SAXReader saxReader = new SAXReader();
try {
if(path == null){
logger.error("配置资源为空!");
}
this.document = saxReader.read(new File(this.getClass().getResource("/").getPath()+"//"+path));
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Configuration parse(){
parseConfiguration();
return configuration;
}
private void parseConfiguration(){
logger.info("正在解析配置文件. . .");
//解析<properties>节点
parseProperties(evalNode("environment"));
//解析<mappers>节点
parseMappers(evalNode("mappers"));
XMLConfigParser xmlConfigParser = new XMLConfigParser(configuration);
xmlConfigParser.parseProperties();
xmlConfigParser.parseMappers();
}
private void parseProperties(Element element){
//遍历<properties>的子节点进行解析
Map<String, String> properties = new HashMap<String, String>();
logger.info("正在解析<environment>标签");
for (Iterator<Element> childEle = element.elementIterator(); childEle.hasNext(); ) {
Element propertyEle = childEle.next();
String name = propertyEle.attribute("name").getValue();
String value = propertyEle.attribute("value").getValue();
properties.put(name,value);
}
configuration.setProperties(properties);
}
private void parseMappers(Element element){
//遍历<properties>的子节点进行解析
List<Mapper> mappers = new ArrayList<Mapper>();
logger.info("正在解析<mappers>标签");
for (Iterator<Element> childEle = element.elementIterator(); childEle.hasNext(); ) {
Mapper mapper = new Mapper();
Element mapperEle = childEle.next();
if(mapperEle.attributeValue("resource") != null){
mapper.setType("resource");
mapper.setValue(mapperEle.attributeValue("resource"));
}else if(mapperEle.attributeValue("url") != null){
mapper.setType("url");
mapper.setValue(mapperEle.attributeValue("url"));
}else if(mapperEle.attributeValue("class") != null){
mapper.setType("class");
mapper.setValue(mapperEle.attributeValue("class"));
}else if(mapperEle.attributeValue("package") != null){
mapper.setType("package");
mapper.setValue(mapperEle.attributeValue("package"));
}
mappers.add(mapper);
}
configuration.setMappers(mappers);
}
private Element evalNode(String eleName){
Element root = this.document.getRootElement();
return root.element(eleName);
}
}
XMLConfigParser类, 将解析后的数据进行处理, 实例化相关对象
package xml;
import core.Configuration;
import core.Mapper;
import core.MapperStatement;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import proxy.MapperProxyFactory;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class XMLConfigParser {
private Configuration configuration;
private SAXReader reader = new SAXReader();
public XMLConfigParser(Configuration configuration) {
this.configuration = configuration;
}
/**
* 加载连接
*/
public void parseProperties(){
Map<String, String> properties = configuration.getProperties();
String dirver = properties.get("driver");
String url = properties.get("url");
String user = properties.get("username");
String pwd = properties.get("password");
configuration.initConnection(dirver,url,user,pwd);
}
/**
* 解析mapper文件
*/
public void parseMappers(){
List<Mapper> mappers = configuration.getMappers();
Map<String, MapperStatement> mapperStatements = new HashMap<String, MapperStatement>();
for (Mapper mapper: mappers ) {
if(mapper.getType().equals("resource")){
try {
Document document =reader.read(new File(this.getClass().getResource("/").getPath()+"//"+mapper.getValue()));
Element root = document.getRootElement();
String namespace = root.attributeValue("namespace");
//循环解析子标签
for (Iterator<Element> childEle = root.elementIterator(); childEle.hasNext(); ) {
Element curdEle = childEle.next();
String id = curdEle.attributeValue("id");
String parameterType = curdEle.attributeValue("parameterType");
String resultType = curdEle.attributeValue("resultType");
String sql = (String) curdEle.getData();
String command = curdEle.getName();
MapperStatement mapperStatement = new MapperStatement(id, parameterType, resultType, command, sql);
mapperStatements.put(namespace+"."+id, mapperStatement);
}
configuration.getKnownMappers().put(Class.forName(namespace),new MapperProxyFactory(Class.forName(namespace)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
configuration.setMapperStatements(mapperStatements);
}
}
执行/增强类
BaseExecutor类, 用于执行sql, 以及结果解析封装
package executor;
import core.BoundSql;
import core.Configuration;
import ibatis.entity.User;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class BaseExecutor implements Executor {
private Configuration configuration;
public BaseExecutor(Configuration configuration) {
this.configuration = configuration;
}
public List<Object> query(String statementId, Object parameter) {
try {
BoundSql boundSql = new BoundSql(configuration.getMapperStatements().get(statementId));
PreparedStatement preparedStatement = configuration.getConnection().prepareStatement(boundSql.getSql());
if(boundSql.getParameterType().equals("int")){
preparedStatement.setInt(1,(Integer) parameter);
}else if(boundSql.getParameterType().equals("String")){
preparedStatement.setString(1,(String) parameter);
}
ResultSet resultSet = preparedStatement.executeQuery();
String resultType = boundSql.getResultType();
List<Object> results = new ArrayList();
while(resultSet.next()){
Class<?> resultClass = Class.forName(resultType); //获取结果类型Class对象
Object resultObj = resultClass.newInstance(); //实例化结果对象
Field[] declaredFields = resultClass.getDeclaredFields();
for (Field declaredField: declaredFields) {
//如果该属性是String类型
if(declaredField.getGenericType().toString().equals("class java.lang.String")){
Method method = resultClass.getMethod("set" + toUpperCatip(declaredField.getName()), String.class);
method.invoke(resultObj,resultSet.getString(declaredField.getName()));
}
//如果该属性是Integer类型
if(declaredField.getGenericType().toString().equals("class java.lang.Integer")){
Method method = resultClass.getMethod("set" + toUpperCatip(declaredField.getName()), Integer.class);
method.invoke(resultObj,resultSet.getInt(declaredField.getName()));
}
}
results.add(resultObj);
}
resultSet.close();
return results;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String toUpperCatip(String str){
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
MapperProxy类,用创建代理, 对接口方法进行实现, 根据接口路径以及方法名获取statementId, 调用sqlsession相关方法进行数据查询
package proxy;
import core.SqlSession;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MapperProxy implements InvocationHandler {
private SqlSession sqlSession;
private Class mapperInterface;
public MapperProxy(SqlSession sqlSession, Class mapperInterface) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return sqlSession.selectOne(mapperInterface.getName()+"."+method.getName(),args[0]);
}
}
测试类:
package ibatis.test;
import core.SqlSession;
import core.SqlSessionFactory;
import core.SqlSessionFactoryBuilder;
import ibatis.entity.Student;
import ibatis.entity.User;
import ibatis.mapper.StudentMapper;
import ibatis.mapper.UserMapper;
public class MybatisHelloWorld2 {
public static void main(String[] args) {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build("configuration.xml");
SqlSession session = sqlSessionFactory.openSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.getUserById(1);
System.out.println(user.toString());
System.out.println("=====================");
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
Student student = studentMapper.getStudentrById(10);
System.out.println(student.toString());
}
}
控制台输出:
完美运行!
相关文章: