本文简单模拟了mybatis的流程,用demo的形式呈现出来
pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tempus.cn</groupId>
<artifactId>mybatis</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- 读取xml文件 -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
</dependencies>
<build>
<finalName>mybatis</finalName>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
</properties>
</project>
UserMapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<mapper nameSpace="mybatis.mapper.UserMapper">
<select id="getUserById" resultType ="mybatis.entity.User">
select * from user where id = ?
</select>
</mapper>
mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<database>
<property name="driverClassName">com.mysql.jdbc.Driver</property>
<property name="url">jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8</property>
<property name="username">root</property>
<property name="password">123456</property>
</database>
UserMapper
package mybatis.mapper;
import mybatis.entity.User;
public interface UserMapper {
public User getUserById(String id);
}
实体类
User
package mybatis.entity;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String id;
private String username;
private String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
工具类
Function
package mybatis.mainfiles;
public class Function {
private String sqltype;
private String funcName;
private String sql;
private Object resultType;
private String parameterType;
public String getSqltype() {
return sqltype;
}
public void setSqltype(String sqltype) {
this.sqltype = sqltype;
}
public String getFuncName() {
return funcName;
}
public void setFuncName(String funcName) {
this.funcName = funcName;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public Object getResultType() {
return resultType;
}
public void setResultType(Object resultType) {
this.resultType = resultType;
}
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
}
MapperBean
package mybatis.mainfiles;
import java.util.ArrayList;
import java.util.List;
public class MapperBean {
private String interfaceName;
private List<Function> list = new ArrayList<>();
public String getInterfaceName() {
return interfaceName;
}
public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
}
public List<Function> getList() {
return list;
}
public void setList(List<Function> list) {
this.list = list;
}
}
执行器接口
package mybatis.mainfiles;
public interface Excutor {
public <T>T query(String statement,Object parameter);
}
解析工具类
MyConfiguration
package mybatis.mainfiles;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/*读取与解析配置信息,并返回处理后的Environment*/
public class MyConfiguration {
private static ClassLoader loader = ClassLoader.getSystemClassLoader();
//读取xml信息并处理
public Connection build(String resource){
try {
InputStream inputStream = loader.getResourceAsStream(resource);
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
Element root = document.getRootElement();
return evalDataSource(root);
} catch (Exception e) {
throw new RuntimeException("error ocurred when eval xml" + resource);
}
}
private Connection evalDataSource(Element node) throws ClassNotFoundException {
if(!node.getName().equals("database")){
throw new RuntimeException("root should be <database>");
}
String driverClassName = null;
String url = null;
String username = null;
String password = null;
//获取属性节点
for(Object item: node.elements("property")){
Element i = (Element)item;
String value = getValue(i);
String name = i.attributeValue("name");
if(name == null || value == null){
throw new RuntimeException("<database> should contain name and value");
}
switch(name){
case "url": url = value; break;
case "username": username = value; break;
case "password": password = value; break;
case "driverClassName": driverClassName = value; break;
default : throw new RuntimeException("<database> property unknow name");
}
}
Class.forName(driverClassName);
Connection conn = null;
try {
conn = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
//获取property属性的值,如果有value的值,则读取,如果没有,则读取内容
private String getValue(Element node) {
return node.hasContent() ? node.getText() : node.attributeValue("value");
}
@SuppressWarnings("rawtypes")
public MapperBean readMapper(String path){
MapperBean mapper = new MapperBean();
try {
InputStream inputStream = loader.getResourceAsStream(path);
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
Element root = document.getRootElement();
mapper.setInterfaceName(root.attributeValue("nameSpace").trim());//把mapper节点的nameSpace值存为接口名
List<Function> list = new ArrayList<>();//用来储存方法的list
for(Iterator rootIter = root.elementIterator();rootIter.hasNext();){//遍历根节点下面的所有子节点
Function func = new Function();//用来储存一条方法的信息
Element e = (Element)rootIter.next();
String sqltype = e.getName().trim();
String funcName = e.attributeValue("id").trim();
String sql = e.getText().trim();
String resultType = e.attributeValue("resultType").trim();
func.setFuncName(funcName);
func.setSqltype(sqltype);
Object newInstance = null;
try {
newInstance = Class.forName(resultType).newInstance();
} catch (Exception e1) {
e1.printStackTrace();
}
func.setResultType(newInstance);
func.setSql(sql);
list.add(func);
}
mapper.setList(list);
} catch (DocumentException e) {
e.printStackTrace();
}
return mapper;
}
}
执行器
package mybatis.mainfiles;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import mybatis.entity.User;
public class MyExcutor implements Excutor {
private MyConfiguration xmlMyconficuration = new MyConfiguration();
@Override
public <T> T query(String sql, Object parameter) {
Connection connection = getConnection();
ResultSet set = null;
PreparedStatement pre = null;
try {
pre = connection.prepareStatement(sql);
pre.setString(1, parameter.toString());
set = pre.executeQuery();
User u = new User();
// 遍历结果集
while (set.next()) {
u.setId(set.getString(1));
u.setPassword(set.getString(2));
u.setUsername(set.getString(3));
}
return (T)u;
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (set != null) {
set.close();
}
if (pre != null) {
pre.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
private Connection getConnection() {
try {
Connection connection = xmlMyconficuration.build("mybatis.xml");
return connection;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
代理对象
MyMapperProxy
package mybatis.mainfiles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
public class MyMapperProxy implements InvocationHandler{
private MyConfiguration myConfiguration;
private MySqlSession mySqlSession;
public MyMapperProxy(MyConfiguration myConfiguration, MySqlSession mySqlSession) {
this.myConfiguration = myConfiguration;
this.mySqlSession = mySqlSession;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MapperBean readMapper = myConfiguration.readMapper("UserMapping.xml");
//是否是xml对应的接口
if(!method.getDeclaringClass().getName().equals(readMapper.getInterfaceName())){
return null;
}
List<Function> list = readMapper.getList();
if(list != null || 0 != list.size()){
for(Function func: list){
//id是否和接口方法名一样
if(method.getName().equals(func.getFuncName())){
return mySqlSession.selectOne(func.getSql(), String.valueOf(args[0]));
}
}
}
return null;
}
}
MySqlSession
package mybatis.mainfiles;
import java.lang.reflect.Proxy;
public class MySqlSession {
private Excutor excutor = new MyExcutor();
private MyConfiguration myConfiguration = new MyConfiguration();
public <T>T selectOne (String statement,Object parameter){
return excutor.query(statement, parameter);
}
@SuppressWarnings("unchecked")
public <T>T getMapper (Class<T> clas){
return (T)Proxy.newProxyInstance(clas.getClassLoader(), new Class[]{clas}, new MyMapperProxy(myConfiguration,this));
}
}
Test
package mybatis.demo;
import mybatis.entity.User;
import mybatis.mainfiles.MySqlSession;
import mybatis.mapper.UserMapper;
public class Test {
public static void main(String[] args) {
MySqlSession sqlsession=new MySqlSession();
UserMapper mapper = sqlsession.getMapper(UserMapper.class);
User user = mapper.getUserById("1");
System.out.println(user.getId() + ":" + user.getUsername());
}
}