├── .gitignore ├── LICENSE ├── README.md ├── pom.xml ├── sql └── person.sql └── src └── main ├── java └── com │ └── mt │ ├── main │ ├── Entry.java │ ├── common │ │ └── SEX.java │ ├── dao │ │ └── PersonDao.java │ ├── domain │ │ └── Person.java │ ├── plugin │ │ └── ExecutorLogPlugin.java │ └── typehandler │ │ └── SexTypeHandler.java │ └── mybatis │ ├── configuration │ ├── MtConfiguration.java │ └── MtDataSource.java │ ├── executor │ ├── ExecutorType.java │ ├── MtExecutor.java │ └── MtSimpleExecutor.java │ ├── mapper │ ├── MapperData.java │ ├── MapperRegistory.java │ └── MtMapperProxy.java │ ├── parameter │ └── ParameterHandler.java │ ├── plugin │ ├── MtInterceptor.java │ ├── MtInterceptorChain.java │ ├── MtInvocation.java │ └── MtPlugin.java │ ├── result │ └── ResultHandler.java │ ├── session │ ├── MtSqlSession.java │ ├── MtSqlSessionFactory.java │ └── MtSqlSessionFactoryBuilder.java │ ├── statement │ └── StatementHandler.java │ └── typehandler │ ├── MtTypeHandler.java │ └── MtTypeHandlerRegistory.java └── resources ├── mybatis-config.properties └── mybatis-mapper.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 DearBelinda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 手写Mybatis框架 2 | 3 | #### 项目介绍 4 | Mybatis的工作原理核心流程都能在代码中体现出来,代码简单但又不简单。 5 | 6 | #### 软件架构 7 | Mybaits核心原理以及工作流程梳理 8 | 9 | 10 | #### 安装教程 11 | 12 | 1. 拉取代码 13 | 2. 设置Mybatis配置信息 14 | 3. pom依赖下载 15 | 4. 运行入口文件 16 | 5. 查看结果 17 | 18 | #### 参与贡献 19 | 20 | 1. Fork 本项目 21 | 2. 新建 Feat_xxx 分支 22 | 3. 提交代码 23 | 4. 新建 Pull Request 24 | 25 | #### 代码说明 26 | 可以转发,可以分享,可以自由发挥,但,不可以用作商业用途! -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.mt 8 | grand-mybatis 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 1.8 13 | UTF-8 14 | 15 | 16 | 17 | 18 | 19 | org.mybatis 20 | mybatis 21 | 3.4.2 22 | 23 | 24 | 25 | mysql 26 | mysql-connector-java 27 | 8.0.11 28 | 29 | 30 | com.alibaba 31 | fastjson 32 | 1.1.35 33 | 34 | 35 | 36 | org.slf4j 37 | slf4j-api 38 | 1.7.21 39 | 40 | 41 | ch.qos.logback 42 | logback-core 43 | 1.1.7 44 | 45 | 46 | ch.qos.logback 47 | logback-classic 48 | 1.1.7 49 | 50 | 51 | 52 | 53 | 54 | 55 | src/main/resources 56 | 57 | 58 | 59 | src/main/java 60 | 61 | **/*.java 62 | 63 | 64 | 65 | 66 | 67 | org.mybatis.generator 68 | mybatis-generator-maven-plugin 69 | 1.3.3 70 | 71 | ${project.basedir}/src/main/resources/generator/generatorConfig.xml 72 | true 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-compiler-plugin 78 | 3.1 79 | 80 | ${java.version} 81 | ${java.version} 82 | ${java.encoding} 83 | 84 | lib 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /sql/person.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : local_db_mysql 5 | Source Server Version : 80011 6 | Source Host : localhost:3306 7 | Source Database : test 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 80011 11 | File Encoding : 65001 12 | 13 | Date: 2018-06-21 17:31:32 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for person 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `person`; 22 | CREATE TABLE `person` ( 23 | `id` bigint(20) NOT NULL AUTO_INCREMENT, 24 | `age` int(11) DEFAULT NULL, 25 | `name` varchar(255) DEFAULT NULL, 26 | `sex` tinyint(4) DEFAULT '1' COMMENT '男:1 女 0;', 27 | PRIMARY KEY (`id`) 28 | ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 29 | -------------------------------------------------------------------------------- /src/main/java/com/mt/main/Entry.java: -------------------------------------------------------------------------------- 1 | package com.mt.main; 2 | 3 | import com.mt.main.dao.PersonDao; 4 | import com.mt.main.domain.Person; 5 | import com.mt.mybatis.configuration.MtConfiguration; 6 | import com.mt.mybatis.session.MtSqlSession; 7 | import com.mt.mybatis.session.MtSqlSessionFactory; 8 | import com.mt.mybatis.session.MtSqlSessionFactoryBuilder; 9 | 10 | /** 11 | *

入口

12 | * 13 | * @author grand 2018/6/20 14 | * @version V1.0 15 | * @modificationHistory=========================逻辑或功能性重大变更记录 16 | * @modify by user: {修改人} 17 | * @modify by reason:{方法名}:{原因} 18 | */ 19 | public class Entry { 20 | 21 | public static void main(String[] args) { 22 | MtConfiguration configuration = new MtConfiguration("mybatis-config.properties"); 23 | MtSqlSessionFactoryBuilder sqlSessionFactoryBuilder = new MtSqlSessionFactoryBuilder(configuration); 24 | MtSqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(); 25 | MtSqlSession sqlSession = sqlSessionFactory.openSession(); 26 | PersonDao personDao = sqlSession.getMapper(PersonDao.class); 27 | Person person = personDao.queryPersonById(1l); 28 | System.out.println(person); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/mt/main/common/SEX.java: -------------------------------------------------------------------------------- 1 | package com.mt.main.common; 2 | 3 | /** 4 | *

性别枚举类型

5 | * 6 | * @author grand 2018/6/21 7 | * @version V1.0 8 | * @modificationHistory=========================逻辑或功能性重大变更记录 9 | * @modify by user: {修改人} 10 | * @modify by reason:{方法名}:{原因} 11 | */ 12 | public enum SEX { 13 | MALE("男",1), 14 | FEMALE("女",0); 15 | 16 | SEX(String sexName, Integer sexType){ 17 | this.sexName = sexName; 18 | this.sexType = sexType; 19 | } 20 | 21 | private String sexName; 22 | private Integer sexType; 23 | 24 | public String getSexName() { 25 | return sexName; 26 | } 27 | 28 | public void setSexName(String sexName) { 29 | this.sexName = sexName; 30 | } 31 | 32 | public Integer getSexType() { 33 | return sexType; 34 | } 35 | 36 | public void setSexType(Integer sexType) { 37 | this.sexType = sexType; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "SEX{" + 43 | "sexName='" + sexName + '\'' + 44 | ", sexType=" + sexType + 45 | '}'; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/mt/main/dao/PersonDao.java: -------------------------------------------------------------------------------- 1 | package com.mt.main.dao; 2 | 3 | import com.mt.main.domain.Person; 4 | 5 | /** 6 | *

7 | * 8 | * @author grand 2018/6/20 9 | * @version V1.0 10 | * @modificationHistory=========================逻辑或功能性重大变更记录 11 | * @modify by user: {修改人} 12 | * @modify by reason:{方法名}:{原因} 13 | */ 14 | public interface PersonDao { 15 | 16 | Person queryPersonById(Long id); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mt/main/domain/Person.java: -------------------------------------------------------------------------------- 1 | package com.mt.main.domain; 2 | 3 | import com.mt.main.common.SEX; 4 | 5 | /** 6 | *

person 实体

7 | * 8 | * @author grand 2018/6/20 9 | * @version V1.0 10 | * @modificationHistory=========================逻辑或功能性重大变更记录 11 | * @modify by user: {修改人} 12 | * @modify by reason:{方法名}:{原因} 13 | */ 14 | public class Person { 15 | private String name; 16 | private Long id; 17 | private Integer age; 18 | private SEX sex; 19 | 20 | public SEX getSex() { 21 | return sex; 22 | } 23 | 24 | public void setSex(SEX sex) { 25 | this.sex = sex; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | public Long getId() { 37 | return id; 38 | } 39 | 40 | public void setId(Long id) { 41 | this.id = id; 42 | } 43 | 44 | public Integer getAge() { 45 | return age; 46 | } 47 | 48 | public void setAge(Integer age) { 49 | this.age = age; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "Person{" + 55 | "name='" + name + '\'' + 56 | ", id=" + id + 57 | ", age=" + age + 58 | ", sex=" + sex + 59 | '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/mt/main/plugin/ExecutorLogPlugin.java: -------------------------------------------------------------------------------- 1 | package com.mt.main.plugin; 2 | 3 | import com.mt.mybatis.mapper.MapperData; 4 | import com.mt.mybatis.plugin.MtInterceptor; 5 | import com.mt.mybatis.plugin.MtInvocation; 6 | import com.mt.mybatis.plugin.MtPlugin; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | *

执行日志输出插件

12 | * 13 | * @author grand 2018/6/21 14 | * @version V1.0 15 | * @modificationHistory=========================逻辑或功能性重大变更记录 16 | * @modify by user: {修改人} 17 | * @modify by reason:{方法名}:{原因} 18 | */ 19 | public class ExecutorLogPlugin implements MtInterceptor { 20 | private final Logger logger = LoggerFactory.getLogger(ExecutorLogPlugin.class); 21 | 22 | 23 | @Override 24 | public Object intercept(MtInvocation invocation) throws Throwable { 25 | MapperData mapperData = (MapperData)invocation.getArgs()[0]; 26 | Object[] parameter = (Object[])invocation.getArgs()[1]; 27 | logger.info("ExecutorLogPlugin is in processing...."); 28 | logger.info("mapperData is :"+ mapperData); 29 | for (int i=0;i性别类型转换器

17 | * 18 | * @author grand 2018/6/21 19 | * @version V1.0 20 | * @modificationHistory=========================逻辑或功能性重大变更记录 21 | * @modify by user: {修改人} 22 | * @modify by reason:{方法名}:{原因} 23 | */ 24 | public class SexTypeHandler implements MtTypeHandler { 25 | private static final Logger logger = LoggerFactory.getLogger(SexTypeHandler.class); 26 | 27 | 28 | @Override 29 | public void setParameter(PreparedStatement var1, int var2, SEX var3, JdbcType var4) throws SQLException { 30 | 31 | } 32 | 33 | @Override 34 | public SEX getResult(ResultSet var1, String var2) throws SQLException { 35 | logger.info("SexTypeHandler is in processing..."); 36 | if(SEX.MALE.getSexType().equals(var1.getInt(var2))){ 37 | return SEX.MALE; 38 | }else{ 39 | return SEX.FEMALE; 40 | } 41 | } 42 | 43 | @Override 44 | public SEX getResult(ResultSet var1, int var2) throws SQLException { 45 | return null; 46 | } 47 | 48 | @Override 49 | public Type getJavaType() { 50 | return ((ParameterizedType)this.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/configuration/MtConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.configuration; 2 | 3 | import com.mt.mybatis.executor.ExecutorType; 4 | import com.mt.mybatis.executor.MtExecutor; 5 | import com.mt.mybatis.executor.MtSimpleExecutor; 6 | import com.mt.mybatis.mapper.MapperRegistory; 7 | import com.mt.mybatis.plugin.MtInterceptor; 8 | import com.mt.mybatis.plugin.MtInterceptorChain; 9 | import com.mt.mybatis.typehandler.MtTypeHandler; 10 | import com.mt.mybatis.typehandler.MtTypeHandlerRegistory; 11 | 12 | import java.io.*; 13 | import java.util.Properties; 14 | 15 | /** 16 | *

Mybatsi配置类,读取解析配置文件信息

17 | * 18 | * @author grand 2018/6/20 19 | * @version V1.0 20 | * @modificationHistory=========================逻辑或功能性重大变更记录 21 | * @modify by user: {修改人} 22 | * @modify by reason:{方法名}:{原因} 23 | */ 24 | public class MtConfiguration { 25 | private Properties configProperties = new Properties(); 26 | private String configLocation; 27 | private MtDataSource dataSource; 28 | private Properties mapperProperties = new Properties(); 29 | private MapperRegistory mapperRegistory = new MapperRegistory(); 30 | private MtInterceptorChain interceptorChain = new MtInterceptorChain(); 31 | private MtTypeHandlerRegistory typeHandlerRegistory = new MtTypeHandlerRegistory(); 32 | 33 | 34 | public MtConfiguration(String configLocation){ 35 | this.configLocation = configLocation; 36 | init(); 37 | } 38 | 39 | private void init(){ 40 | try { 41 | //记载配置文件,这里使用properties代替xml解析 42 | loadConfigProperties(); 43 | //初始化数据源信息 44 | initDataSource(); 45 | //解析并加载mapper文件 46 | loadMapperRegistory(); 47 | //解析加载plugin 48 | initPluginChain(); 49 | //解析加载typeHandler 50 | initTypeHandler(); 51 | } catch (ClassNotFoundException e) { 52 | e.printStackTrace(); 53 | } catch (IllegalAccessException e) { 54 | e.printStackTrace(); 55 | } catch (InstantiationException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | 60 | public void loadConfigProperties(){ 61 | if(this.configLocation==null){ 62 | throw new RuntimeException("Mybatis's configLocation is not null!"); 63 | } 64 | try { 65 | InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(configLocation); 66 | this.configProperties.load(inputStream); 67 | } catch (FileNotFoundException e) { 68 | e.printStackTrace(); 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | public void loadMapperRegistory(){ 75 | this.scan(); 76 | if(mapperProperties == null){ 77 | throw new RuntimeException("Mybatis's mapperLocation is not null!"); 78 | } 79 | try { 80 | mapperRegistory.doLoadMethodSqlMapping(mapperProperties); 81 | } catch (ClassNotFoundException e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | 86 | public void scan(){ 87 | try { 88 | String mapperLocation = configProperties.getProperty("mapperLocation"); 89 | InputStream is = this.getClass().getClassLoader().getResourceAsStream(mapperLocation); 90 | this.mapperProperties.load(is); 91 | } catch (FileNotFoundException e) { 92 | e.printStackTrace(); 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | 98 | public void initDataSource(){ 99 | this.dataSource = new MtDataSource(configProperties.getProperty("jdbc.url"),configProperties.getProperty("jdbc.driver"), 100 | configProperties.getProperty("jdbc.userName"),configProperties.getProperty("jdbc.passWord")); 101 | } 102 | 103 | public void initPluginChain() throws ClassNotFoundException, IllegalAccessException, InstantiationException { 104 | String pluginStr = configProperties.getProperty("plugin"); 105 | String[] pluginArray = pluginStr.split(","); 106 | for (String plugin:pluginArray){ 107 | Class clazz = this.getClass().getClassLoader().loadClass(plugin); 108 | if(clazz!=null){ 109 | Object o = clazz.newInstance(); 110 | this.interceptorChain.addInterceptor((MtInterceptor)clazz.newInstance()); 111 | } 112 | } 113 | } 114 | 115 | public MtExecutor newExecutor(ExecutorType type){ 116 | MtExecutor executor = null; 117 | 118 | if(ExecutorType.SIMPLE==type){ 119 | executor = new MtSimpleExecutor(this); 120 | } 121 | 122 | return (MtExecutor)this.interceptorChain.pluginAll(executor); 123 | } 124 | 125 | public void initTypeHandler() throws ClassNotFoundException, IllegalAccessException, InstantiationException { 126 | String typeHandlerStr = configProperties.getProperty("typeHandler"); 127 | String[] typeHandlerArray = typeHandlerStr.split(","); 128 | for (String typeHandler:typeHandlerArray){ 129 | Class clazz = this.getClass().getClassLoader().loadClass(typeHandler); 130 | if(clazz!=null){ 131 | Object o = clazz.newInstance(); 132 | this.typeHandlerRegistory.regist((MtTypeHandler) clazz.newInstance()); 133 | } 134 | } 135 | } 136 | 137 | public Properties getMapperProperties() { 138 | return mapperProperties; 139 | } 140 | 141 | public void setMapperProperties(Properties mapperProperties) { 142 | this.mapperProperties = mapperProperties; 143 | } 144 | 145 | public Properties getConfigProperties() { 146 | return configProperties; 147 | } 148 | 149 | public void setConfigProperties(Properties configProperties) { 150 | this.configProperties = configProperties; 151 | } 152 | 153 | public MtDataSource getDataSource() { 154 | return dataSource; 155 | } 156 | 157 | public String getConfigLocation() { 158 | return configLocation; 159 | } 160 | 161 | public void setConfigLocation(String configLocation) { 162 | this.configLocation = configLocation; 163 | } 164 | 165 | public void setDataSource(MtDataSource dataSource) { 166 | this.dataSource = dataSource; 167 | } 168 | 169 | public MapperRegistory getMapperRegistory() { 170 | return mapperRegistory; 171 | } 172 | 173 | public void setMapperRegistory(MapperRegistory mapperRegistory) { 174 | this.mapperRegistory = mapperRegistory; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/configuration/MtDataSource.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.configuration; 2 | 3 | /** 4 | *

DataSource,记录数据库连接信息

5 | * 6 | * @author grand 2018/6/20 7 | * @version V1.0 8 | * @modificationHistory=========================逻辑或功能性重大变更记录 9 | * @modify by user: {修改人} 10 | * @modify by reason:{方法名}:{原因} 11 | */ 12 | public class MtDataSource { 13 | 14 | private String url; 15 | private String driver; 16 | private String userName; 17 | private String passWord; 18 | 19 | public MtDataSource(String url, String driver, String userName, String passWord) { 20 | this.url = url; 21 | this.driver = driver; 22 | this.userName = userName; 23 | this.passWord = passWord; 24 | } 25 | 26 | public String getUrl() { 27 | return url; 28 | } 29 | 30 | public void setUrl(String url) { 31 | this.url = url; 32 | } 33 | 34 | public String getDriver() { 35 | return driver; 36 | } 37 | 38 | public void setDriver(String driver) { 39 | this.driver = driver; 40 | } 41 | 42 | public String getUserName() { 43 | return userName; 44 | } 45 | 46 | public void setUserName(String userName) { 47 | this.userName = userName; 48 | } 49 | 50 | public String getPassWord() { 51 | return passWord; 52 | } 53 | 54 | public void setPassWord(String passWord) { 55 | this.passWord = passWord; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/executor/ExecutorType.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.executor; 2 | 3 | /** 4 | *

executor 类型

5 | * 6 | * @author grand 2018/6/21 7 | * @version V1.0 8 | * @modificationHistory=========================逻辑或功能性重大变更记录 9 | * @modify by user: {修改人} 10 | * @modify by reason:{方法名}:{原因} 11 | */ 12 | public enum ExecutorType { 13 | SIMPLE, 14 | REUSE, 15 | BATCH; 16 | 17 | private ExecutorType() { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/executor/MtExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.executor; 2 | 3 | import com.mt.mybatis.mapper.MapperData; 4 | 5 | /** 6 | *

Executor,sql执行的顶层接口

7 | * 8 | * @author grand 2018/6/20 9 | * @version V1.0 10 | * @modificationHistory=========================逻辑或功能性重大变更记录 11 | * @modify by user: {修改人} 12 | * @modify by reason:{方法名}:{原因} 13 | */ 14 | public interface MtExecutor { 15 | 16 | T query(MapperData mapperData, Object parameter) throws Exception; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/executor/MtSimpleExecutor.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.executor; 2 | 3 | import com.mt.mybatis.configuration.MtConfiguration; 4 | import com.mt.mybatis.mapper.MapperData; 5 | import com.mt.mybatis.statement.StatementHandler; 6 | 7 | /** 8 | *

SimpleExecutor,执行器类的一种简单实现

9 | * 10 | * @author grand 2018/6/20 11 | * @version V1.0 12 | * @modificationHistory=========================逻辑或功能性重大变更记录 13 | * @modify by user: {修改人} 14 | * @modify by reason:{方法名}:{原因} 15 | */ 16 | public class MtSimpleExecutor implements MtExecutor { 17 | private MtConfiguration configuation; 18 | 19 | public MtSimpleExecutor(MtConfiguration configuation){ 20 | this.configuation = configuation; 21 | } 22 | 23 | @Override 24 | public T query(MapperData mapperData, Object parameter) throws Exception { 25 | StatementHandler statementHandler = new StatementHandler(configuation); 26 | return statementHandler.query(mapperData,parameter); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/mapper/MapperData.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.mapper; 2 | 3 | /** 4 | *

模拟mapper.xml解析后的简单封装

5 | * 6 | * @author grand 2018/6/20 7 | * @version V1.0 8 | * @modificationHistory=========================逻辑或功能性重大变更记录 9 | * @modify by user: {修改人} 10 | * @modify by reason:{方法名}:{原因} 11 | */ 12 | public class MapperData { 13 | private String sql; 14 | private Class type; 15 | 16 | public MapperData(String sql, Class type) { 17 | this.sql = sql; 18 | this.type = type; 19 | } 20 | 21 | public String getSql() { 22 | return sql; 23 | } 24 | 25 | public void setSql(String sql) { 26 | this.sql = sql; 27 | } 28 | 29 | public Class getType() { 30 | return type; 31 | } 32 | 33 | public void setType(Class type) { 34 | this.type = type; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "MapperData{" + 40 | "sql='" + sql + '\'' + 41 | ", resultType=" + type + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/mapper/MapperRegistory.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.mapper; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.Enumeration; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.Properties; 10 | 11 | /** 12 | *

MapperRegistory,DAO方法与SQL的映射关系

13 | * 14 | * @author grand 2018/6/20 15 | * @version V1.0 16 | * @modificationHistory=========================逻辑或功能性重大变更记录 17 | * @modify by user: {修改人} 18 | * @modify by reason:{方法名}:{原因} 19 | */ 20 | public class MapperRegistory { 21 | private Logger logger = LoggerFactory.getLogger(MapperRegistory.class); 22 | private Map methodSqlMapping = new HashMap<>(); 23 | 24 | public void doLoadMethodSqlMapping(Properties mapperProperties) throws ClassNotFoundException { 25 | Enumeration propertyNames = mapperProperties.propertyNames(); 26 | while(propertyNames.hasMoreElements()){ 27 | String key = (String)propertyNames.nextElement(); 28 | String value = mapperProperties.getProperty(key); 29 | String sql = value.substring(0,value.indexOf("#")); 30 | String t = value.substring(value.indexOf("#")+1,value.length()); 31 | Class type = this.getClass().getClassLoader().loadClass(t); 32 | this.methodSqlMapping.put(key,new MapperData(sql,type)); 33 | logger.info("In loading methodSqlMapping------sql: "+sql+" and type: "+type); 34 | } 35 | } 36 | 37 | public Map getMethodSqlMapping() { 38 | return methodSqlMapping; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/mapper/MtMapperProxy.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.mapper; 2 | 3 | import com.mt.mybatis.session.MtSqlSession; 4 | 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | *

MapperProxy,模拟mybatis的mapper代理对象

10 | * 11 | * @author grand 2018/6/20 12 | * @version V1.0 13 | * @modificationHistory=========================逻辑或功能性重大变更记录 14 | * @modify by user: {修改人} 15 | * @modify by reason:{方法名}:{原因} 16 | */ 17 | public class MtMapperProxy implements InvocationHandler { 18 | private MtSqlSession mtSqlSession; 19 | private Class mapperInterface; 20 | 21 | public MtMapperProxy(MtSqlSession mtSqlSession, Class mapperInterface) { 22 | this.mtSqlSession = mtSqlSession; 23 | this.mapperInterface = mapperInterface; 24 | } 25 | 26 | @Override 27 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 28 | MapperData mapperData = this.mtSqlSession.getConfiguration().getMapperRegistory().getMethodSqlMapping().get(mapperInterface.getName()+"."+method.getName()); 29 | if(mapperData!=null){ 30 | return this.mtSqlSession.selectOne(mapperData,args); 31 | } 32 | return method.invoke(proxy,args); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/parameter/ParameterHandler.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.parameter; 2 | 3 | import java.sql.PreparedStatement; 4 | import java.sql.SQLException; 5 | 6 | /** 7 | *

ParameterHandler,参数处理器

8 | * 9 | * @author grand 2018/6/20 10 | * @version V1.0 11 | * @modificationHistory=========================逻辑或功能性重大变更记录 12 | * @modify by user: {修改人} 13 | * @modify by reason:{方法名}:{原因} 14 | */ 15 | public class ParameterHandler { 16 | private PreparedStatement psmt; 17 | 18 | public ParameterHandler(PreparedStatement statement){ 19 | this.psmt = statement; 20 | } 21 | 22 | public void setParameters(Object parameter){ 23 | try{ 24 | Object[] parameters = (Object[])parameter; 25 | for (int i = 0;i拦截器顶级接口

5 | * 6 | * @author grand 2018/6/20 7 | * @version V1.0 8 | * @modificationHistory=========================逻辑或功能性重大变更记录 9 | * @modify by user: {修改人} 10 | * @modify by reason:{方法名}:{原因} 11 | */ 12 | public interface MtInterceptor { 13 | 14 | Object intercept(MtInvocation var1) throws Throwable; 15 | 16 | Object plugin(Object var1); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/plugin/MtInterceptorChain.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.plugin; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | /** 8 | *

拦截器链,这里规定只对executor方法进行拦截增强

9 | * 10 | * @author grand 2018/6/20 11 | * @version V1.0 12 | * @modificationHistory=========================逻辑或功能性重大变更记录 13 | * @modify by user: {修改人} 14 | * @modify by reason:{方法名}:{原因} 15 | */ 16 | public class MtInterceptorChain { 17 | private List interceptors = new ArrayList(); 18 | 19 | public void addInterceptor(MtInterceptor interceptor) { 20 | this.interceptors.add(interceptor); 21 | } 22 | 23 | public List getInterceptors() { 24 | return Collections.unmodifiableList(this.interceptors); 25 | } 26 | 27 | public Object pluginAll(Object target){ 28 | for(MtInterceptor var1 : interceptors){ 29 | target = var1.plugin(target); 30 | } 31 | return target; 32 | } 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/plugin/MtInvocation.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.plugin; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | 6 | /** 7 | *

Invocation

8 | * 9 | * @author grand 2018/6/20 10 | * @version V1.0 11 | * @modificationHistory=========================逻辑或功能性重大变更记录 12 | * @modify by user: {修改人} 13 | * @modify by reason:{方法名}:{原因} 14 | */ 15 | public class MtInvocation { 16 | 17 | private Object target; 18 | private Method method; 19 | private Object[] args; 20 | 21 | public MtInvocation(Object target, Method method, Object[] args) { 22 | this.target = target; 23 | this.method = method; 24 | this.args = args; 25 | } 26 | 27 | public Object proceed() throws InvocationTargetException, IllegalAccessException { 28 | return this.method.invoke(this.target, this.args); 29 | } 30 | 31 | public Object getTarget() { 32 | return target; 33 | } 34 | 35 | public void setTarget(Object target) { 36 | this.target = target; 37 | } 38 | 39 | public Method getMethod() { 40 | return method; 41 | } 42 | 43 | public void setMethod(Method method) { 44 | this.method = method; 45 | } 46 | 47 | public Object[] getArgs() { 48 | return args; 49 | } 50 | 51 | public void setArgs(Object[] args) { 52 | this.args = args; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/plugin/MtPlugin.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.plugin; 2 | 3 | import com.mt.mybatis.executor.MtExecutor; 4 | 5 | import java.lang.reflect.InvocationHandler; 6 | import java.lang.reflect.Method; 7 | import java.lang.reflect.Proxy; 8 | 9 | /** 10 | *

Plugin 代理实现类

11 | * 12 | * @author grand 2018/6/21 13 | * @version V1.0 14 | * @modificationHistory=========================逻辑或功能性重大变更记录 15 | * @modify by user: {修改人} 16 | * @modify by reason:{方法名}:{原因} 17 | */ 18 | public class MtPlugin implements InvocationHandler { 19 | private Object target; 20 | private MtInterceptor interceptor; 21 | 22 | public MtPlugin(Object target, MtInterceptor interceptor) { 23 | this.target = target; 24 | this.interceptor = interceptor; 25 | } 26 | 27 | @Override 28 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 29 | return this.interceptor.intercept(new MtInvocation(target,method,args)); 30 | } 31 | 32 | public static Object wrap(Object target,MtInterceptor interceptor){ 33 | return Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{MtExecutor.class},new MtPlugin(target,interceptor)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/result/ResultHandler.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.result; 2 | 3 | import com.mt.main.common.SEX; 4 | import com.mt.mybatis.typehandler.MtTypeHandler; 5 | import com.mt.mybatis.typehandler.MtTypeHandlerRegistory; 6 | import org.apache.ibatis.reflection.factory.DefaultObjectFactory; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.lang.reflect.Method; 13 | import java.sql.ResultSet; 14 | import java.sql.SQLException; 15 | 16 | /** 17 | *

模拟Mybatis查询结果到pojo对象的封装

18 | * 19 | * @author grand 2018/6/20 20 | * @version V1.0 21 | * @modificationHistory=========================逻辑或功能性重大变更记录 22 | * @modify by user: {修改人} 23 | * @modify by reason:{方法名}:{原因} 24 | */ 25 | public class ResultHandler { 26 | private Logger logger = LoggerFactory.getLogger(ResultHandler.class); 27 | 28 | private Class type; 29 | private ResultSet resultSet; 30 | 31 | public ResultHandler(Class type, ResultSet resultSet){ 32 | this.type = type; 33 | this.resultSet = resultSet; 34 | } 35 | 36 | public E handle() { 37 | try{ 38 | Object resultObject = new DefaultObjectFactory().create(type); 39 | if(resultSet.next()){ 40 | for(Field field:resultObject.getClass().getDeclaredFields()){ 41 | setValue(resultObject,field,resultSet); 42 | } 43 | } 44 | return (E) resultObject; 45 | } catch (IllegalAccessException e) { 46 | logger.error("IllegalAccessException happen when processing in ResultHandler:"+e); 47 | } catch (SQLException e) { 48 | logger.error("SQLException happen when processing in ResultHandler:"+e); 49 | } catch (NoSuchMethodException e) { 50 | logger.error("NoSuchMethodException happen when processing in ResultHandler:"+e); 51 | } catch (InvocationTargetException e) { 52 | logger.error("InvocationTargetException happen when processing in ResultHandler:"+e); 53 | }finally { 54 | try { 55 | if(resultSet!=null){ 56 | resultSet.close(); 57 | } 58 | } catch (SQLException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | return null; 63 | } 64 | 65 | public void setValue( Object resultObject,Field field,ResultSet resultSet) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, SQLException { 66 | Method method = type.getMethod("set"+upperCapital(field.getName()),field.getType()); 67 | method.invoke(resultObject,getResult(field,resultSet)); 68 | } 69 | 70 | public Object getResult(Field field, ResultSet rs) throws SQLException { 71 | Class type = field.getType(); 72 | if(Integer.class == type){ 73 | return rs.getInt(field.getName()); 74 | }else if(String.class == type){ 75 | return rs.getString(field.getName()); 76 | }else if(Long.class == type){ 77 | return rs.getLong(field.getName()); 78 | }else if(SEX.class == type){ 79 | MtTypeHandler typeHandler = MtTypeHandlerRegistory.TYPE_HANDLER_MAP.get(type); 80 | return typeHandler.getResult(resultSet,field.getName()); 81 | }else{ 82 | return rs.getString(field.getName()); 83 | } 84 | } 85 | 86 | private String upperCapital(String name) { 87 | String first = name.substring(0, 1); 88 | String tail = name.substring(1); 89 | return first.toUpperCase() + tail; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/session/MtSqlSession.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.session; 2 | 3 | import com.mt.mybatis.configuration.MtConfiguration; 4 | import com.mt.mybatis.executor.MtExecutor; 5 | import com.mt.mybatis.mapper.MapperData; 6 | import com.mt.mybatis.mapper.MtMapperProxy; 7 | 8 | import java.lang.reflect.Proxy; 9 | 10 | /** 11 | *

SqlSession,模拟Mybatis的会话

12 | * 13 | * @author grand 2018/6/20 14 | * @version V1.0 15 | * @modificationHistory=========================逻辑或功能性重大变更记录 16 | * @modify by user: {修改人} 17 | * @modify by reason:{方法名}:{原因} 18 | */ 19 | public class MtSqlSession { 20 | private MtConfiguration configuration; 21 | private MtExecutor executor; 22 | 23 | public MtSqlSession(MtConfiguration configuration, MtExecutor executor) { 24 | this.configuration = configuration; 25 | this.executor = executor; 26 | } 27 | 28 | public T getMapper(Class clazz){ 29 | return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),new Class[]{clazz},new MtMapperProxy(this,clazz)); 30 | } 31 | 32 | public T selectOne(MapperData mapperData, Object parameter) throws Exception { 33 | return executor.query(mapperData, parameter); 34 | } 35 | 36 | public MtConfiguration getConfiguration() { 37 | return configuration; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/session/MtSqlSessionFactory.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.session; 2 | 3 | import com.mt.mybatis.configuration.MtConfiguration; 4 | import com.mt.mybatis.executor.ExecutorType; 5 | import com.mt.mybatis.executor.MtExecutor; 6 | 7 | /** 8 | *

SqlSessionFactory,会话工厂

9 | * 10 | * @author grand 2018/6/20 11 | * @version V1.0 12 | * @modificationHistory=========================逻辑或功能性重大变更记录 13 | * @modify by user: {修改人} 14 | * @modify by reason:{方法名}:{原因} 15 | */ 16 | public class MtSqlSessionFactory { 17 | private MtConfiguration configuration; 18 | 19 | public MtSqlSessionFactory(MtConfiguration configuration) { 20 | this.configuration = configuration; 21 | } 22 | 23 | public MtSqlSession openSession() { 24 | return openSessionFromDataSource(ExecutorType.SIMPLE); 25 | } 26 | 27 | private MtSqlSession openSessionFromDataSource(ExecutorType execType) { 28 | MtExecutor executor = this.configuration.newExecutor(execType); 29 | MtSqlSession sqlSession = new MtSqlSession(configuration, executor); 30 | return sqlSession; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/session/MtSqlSessionFactoryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.session; 2 | 3 | import com.mt.mybatis.configuration.MtConfiguration; 4 | 5 | /** 6 | *

SqlSessionFactoryBuilder

7 | * 8 | * @author grand 2018/6/21 9 | * @version V1.0 10 | * @modificationHistory=========================逻辑或功能性重大变更记录 11 | * @modify by user: {修改人} 12 | * @modify by reason:{方法名}:{原因} 13 | */ 14 | public class MtSqlSessionFactoryBuilder { 15 | private MtConfiguration configuation; 16 | 17 | public MtSqlSessionFactoryBuilder(MtConfiguration configuation){ 18 | this.configuation = configuation; 19 | } 20 | 21 | public MtSqlSessionFactory build(){ 22 | return new MtSqlSessionFactory(configuation); 23 | } 24 | 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/statement/StatementHandler.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.statement; 2 | 3 | import com.mt.mybatis.configuration.MtConfiguration; 4 | import com.mt.mybatis.configuration.MtDataSource; 5 | import com.mt.mybatis.mapper.MapperData; 6 | import com.mt.mybatis.parameter.ParameterHandler; 7 | import com.mt.mybatis.result.ResultHandler; 8 | 9 | import java.sql.*; 10 | 11 | /** 12 | *

StatementHandler,语句集处理

13 | * 14 | * @author grand 2018/6/20 15 | * @version V1.0 16 | * @modificationHistory=========================逻辑或功能性重大变更记录 17 | * @modify by user: {修改人} 18 | * @modify by reason:{方法名}:{原因} 19 | */ 20 | public class StatementHandler { 21 | private MtConfiguration configuation; 22 | 23 | public StatementHandler(MtConfiguration configuation){ 24 | this.configuation = configuation; 25 | } 26 | 27 | public E query(MapperData mapperData, Object parameter){ 28 | Connection conn = null; 29 | PreparedStatement preparedStatement = null; 30 | try { 31 | conn = getConnection(); 32 | preparedStatement = conn.prepareStatement(mapperData.getSql()); 33 | ParameterHandler parameterHandler = new ParameterHandler(preparedStatement); 34 | parameterHandler.setParameters(parameter); 35 | preparedStatement.execute(); 36 | ResultHandler resultHandler = new ResultHandler(mapperData.getType(),preparedStatement.getResultSet()); 37 | return (E) resultHandler.handle(); 38 | } catch (SQLException e) { 39 | e.printStackTrace(); 40 | } catch (ClassNotFoundException e) { 41 | e.printStackTrace(); 42 | }finally { 43 | try { 44 | if(preparedStatement!=null){ 45 | preparedStatement.close(); 46 | } 47 | if(conn!=null){ 48 | conn.close(); 49 | } 50 | } catch (SQLException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | return null; 55 | } 56 | 57 | private Connection getConnection() throws SQLException, ClassNotFoundException { 58 | MtDataSource dataSource = configuation.getDataSource(); 59 | Class.forName(dataSource.getDriver()); 60 | return DriverManager.getConnection(dataSource.getUrl(),dataSource.getUserName(),dataSource.getPassWord()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/typehandler/MtTypeHandler.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.typehandler; 2 | 3 | import org.apache.ibatis.type.JdbcType; 4 | 5 | import java.lang.reflect.Type; 6 | import java.sql.PreparedStatement; 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | 10 | /** 11 | *

TypeHandler,顶层类型处理器接口,用于定义类型处理的行为

12 | * 13 | * @author grand 2018/6/21 14 | * @version V1.0 15 | * @modificationHistory=========================逻辑或功能性重大变更记录 16 | * @modify by user: {修改人} 17 | * @modify by reason:{方法名}:{原因} 18 | */ 19 | public interface MtTypeHandler { 20 | void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException; 21 | 22 | T getResult(ResultSet var1, String var2) throws SQLException; 23 | 24 | T getResult(ResultSet var1, int var2) throws SQLException; 25 | 26 | Type getJavaType(); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mt/mybatis/typehandler/MtTypeHandlerRegistory.java: -------------------------------------------------------------------------------- 1 | package com.mt.mybatis.typehandler; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.Map; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | /** 8 | *

TypeHandlerRegistory

9 | * 10 | * @author grand 2018/6/21 11 | * @version V1.0 12 | * @modificationHistory=========================逻辑或功能性重大变更记录 13 | * @modify by user: {修改人} 14 | * @modify by reason:{方法名}:{原因} 15 | */ 16 | public class MtTypeHandlerRegistory { 17 | public static Map TYPE_HANDLER_MAP = new ConcurrentHashMap(); 18 | 19 | public void regist(MtTypeHandler typeHandler) throws IllegalAccessException, InstantiationException { 20 | TYPE_HANDLER_MAP.put(typeHandler.getJavaType(),typeHandler); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/mybatis-config.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DearBelinda/handwritten_mybatis_framework/d7991849597b6ff4a874415fccb4ca1829b298dc/src/main/resources/mybatis-config.properties -------------------------------------------------------------------------------- /src/main/resources/mybatis-mapper.properties: -------------------------------------------------------------------------------- 1 | com.mt.main.dao.PersonDao.queryPersonById=select * from person where id = ?#com.mt.main.domain.Person --------------------------------------------------------------------------------