# mybatis-custom **Repository Path**: wuxi_zero/mybatis-custom ## Basic Information - **Project Name**: mybatis-custom - **Description**: 手写mybatis - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-04-23 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # mybatis-custom ### 技术活力来之分享,死于闭环。 ### 标题 手写mybatis,基于mybatis源码,以注解的方式手写mybatis。 ### 说明 选择以注解的方式来做: 1. 基于注解的方式相对简单,以xml的方式相对繁琐,需要自定义xml,和解析(推荐使用dom4j)。 2. 没有使用到mybatis的sqlSessionFactory模型,原因时间有限,这个只是优化而已。 3. 目前还是不能与spring相结合这个有待优化,具体是对jdbc和sqlSessionFactory模型相结合问题,后期有时间会处理一下。 4. 最后提醒一下,建立好后上面条件后,可以直接是用spring IOC就可以完成自己的mybatis了。很简单 ### 简介 1.1MyBatis基本介绍 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。 ### **1.3MyBatis源码分析 ** ### 1.3.1 入口 ``` public static void main(String[] args) { try { SqlSessionFactory sqlSessionFactory; Reader reader; String resource = "mybatis.xml"; // 加载一个流 reader = Resources.getResourceAsReader(resource); // 生成sqlSessionFactory工厂,反射xml初始化sql。 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //初始化sqlSession SqlSession session = sqlSessionFactory.openSession(); //代理testUserMapper TestUserMapper userMapper = session.getMapper(TestUserMapper.class); //获取代理方法,初始返回类型,调用jdbc获取返回值。 List users = userMapper.getAll("wuxi",27); for (TestUser user2 : users) { System.out.println(user2.toString()); } session.close(); } catch (IOException e) { e.printStackTrace(); } } ``` ### 1.3.2 XML文件 ``` ``` ### 1.3.3 接口 ``` @Select("select * from test_user where age=#{age} and user_name=#{userName}") @Results({ @Result(id=true,column="id",property="id"), @Result(column="user_name",property="userName"), @Result(column="age",property="age"), }) List getAll(@Param("userName") String accountName,@Param("age") Integer age); @Select("select * from test_user where user_name=#{userName}") TestUser getAccountByUserName(@Param("userName") String accountName); @Insert("insert into test_user (user_name,age) values (#{userName},#{age})") long insertAccount(TestUser account); ``` **### 1.3.4进入 源码** ### 1.3.4.1 首先读取xml ``` public static Reader getResourceAsReader(String resource) throws IOException { InputStreamReader reader; if (charset == null) { reader = new InputStreamReader(getResourceAsStream(resource)); } else { reader = new InputStreamReader(getResourceAsStream(resource), charset); } return reader; } ``` ### 1.3.4.2 创建sqlSessionFactory工厂 ``` /** * * 生成sqlSessionFactory工厂,反射xml初始化sql。 * sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); * */ public SqlSessionFactory build(Reader reader, String environment, Properties properties) { SqlSessionFactory var5; try { //读取xml XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties); //创建SqlSessionFactory var5 = this.build(parser.parse()); } catch (Exception var14) { throw ExceptionFactory.wrapException("Error building SqlSession.", var14); } finally { ErrorContext.instance().reset(); try { reader.close(); } catch (IOException var13) { ; } } return var5; } // 解析 private void mapperElement(XNode parent) throws Exception { ..... //反射 Class mapperInterface = Resources.classForName(mapperClass); } void parseStatement(Method method) { Class parameterTypeClass = this.getParameterType(method); LanguageDriver languageDriver = this.getLanguageDriver(method); SqlSource sqlSource = this.getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver); ...... } //方法上的注解类型 select update insert 等等 private Class chooseAnnotationType(Method method, Set> types) { Iterator var3 = types.iterator(); Class type; Annotation annotation; do { if (!var3.hasNext()) { return null; } type = (Class)var3.next(); annotation = method.getAnnotation(type); } while(annotation == null); return type; } //获取方法注解的value及 sql String[] strings = (String[])((String[])sqlProviderAnnotation.getClass().getMethod("value").invoke(sqlProviderAnnotation)); //sql预编译处理 public static String parse(String string, Properties variables) { PropertyParser.VariableTokenHandler handler = new PropertyParser.VariableTokenHandler(variables); GenericTokenParser parser = new GenericTokenParser("${", "}", handler); return parser.parse(string); } //解析com.enmonster.mapper.TestUserMapper接口方法参数类型 private Class getParameterType(Method method) { Class parameterType = null; Class[] parameterTypes = method.getParameterTypes(); Class[] var4 = parameterTypes; int var5 = parameterTypes.length; for(int var6 = 0; var6 < var5; ++var6) { Class currentParameterType = var4[var6]; if (!RowBounds.class.isAssignableFrom(currentParameterType) && !ResultHandler.class.isAssignableFrom(currentParameterType)) { if (parameterType == null) { parameterType = currentParameterType; } else { parameterType = ParamMap.class; } } } return parameterType; } //这个是后续手写mybatis一个很好的用的有个工具 //方法参数,类型判断 参数类型解析器 private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class declaringClass) { Class rawType = (Class)parameterizedType.getRawType(); Type[] typeArgs = parameterizedType.getActualTypeArguments(); Type[] args = new Type[typeArgs.length]; for(int i = 0; i < typeArgs.length; ++i) { if (typeArgs[i] instanceof TypeVariable) { //泛型 T args[i] = resolveTypeVar((TypeVariable)typeArgs[i], srcType, declaringClass); } else if (typeArgs[i] instanceof ParameterizedType) { //List Map args[i] = resolveParameterizedType((ParameterizedType)typeArgs[i], srcType, declaringClass); } else if (typeArgs[i] instanceof WildcardType) { // T[] 数组 args[i] = resolveWildcardType((WildcardType)typeArgs[i], srcType, declaringClass); } else { // class args[i] = typeArgs[i]; } } return new TypeParameterResolver.ParameterizedTypeImpl(rawType, (Type)null, args); } 1.到这里 sql 解析完成 2.参数类型已经解析 3. 创建 默认DefaultSqlSessionFactory public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); } ``` ### 1.3.4.3 初始化sqlsession ``` 其实很简单 private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; DefaultSqlSession var8; try { //xml 节点对象 Environment environment = this.configuration.getEnvironment(); //创建 TransactionFactory TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); //创建执行器 Executor executor = this.configuration.newExecutor(tx, execType); //创建好工厂 var8 = new DefaultSqlSession(this.configuration, executor, autoCommit); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; } ``` ### 1.3.4.4 获取代理对象(核心:动态代理) ``` /** * * 代理testUserMapper * TestUserMapper userMapper = session.getMapper(TestUserMapper.class); * */ public T getMapper(Class type, SqlSession sqlSession) { MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } else { try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception var5) { throw new BindingException("Error getting mapper instance. Cause: " + var5, var5); } } } //动态代理 protected T newInstance(MapperProxy mapperProxy) { return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); } public T newInstance(SqlSession sqlSession) { MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); } ``` ### 1.3.4.5 执行代理方法 ``` /** * * List users = userMapper.getAll("wuxi",27); * */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } if (this.isDefaultMethod(method)) { return this.invokeDefaultMethod(proxy, method, args); } } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } MapperMethod mapperMethod = this.cachedMapperMethod(method); return mapperMethod.execute(this.sqlSession, args); } ``` 剩下只有 通过sqlsession 使用jdbc ,反射获取方法类型。 打完收工。 ### **2.MyBatis手写 ** ### 2.1.1创建注解 ``` @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface WxSelect { String value(); } ``` > 类似这样的注解:WxSelect WxInsert WxR** esult WxResults WxParam > ### 2.1.2 自定义获取代理对象 ``` // 获取getMapper public static T getMapper(Class clas) throws IllegalArgumentException, InstantiationException, IllegalAccessException { return (T) Proxy.newProxyInstance(clas.getClassLoader(), new Class[] { clas },new MyInvocationHandler(clas)); } ``` ### 2.1.3代理类 ``` @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("使用动态代理接口方法开始..."+method.getName()); //初始化sql initSql(method); //解析WxParam注解 获取代理对象参数名 InterResolveCommon.wxParamResolve(method,modelOriginal,args); System.out.println(modelOriginal.toString()); return geResult(method); } ``` //初始化modelOriginal 执行的sql对象 ``` public void initSql(Method method) { Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations){ Class ann = annotation.annotationType(); if(WxSelect.class.equals(ann)){ InterResolveCommon.wxSelectResolve(method,modelOriginal); }else if(WxInsert.class.equals(ann)){ InterResolveCommon.wxInsertResolve(method,modelOriginal); }else if(WxResults.class.equals(ann)){ InterResolveCommon.wxResultsResolve(method,resultMap); }else if(WxResult.class.equals(ann)){ InterResolveCommon.wxResultResolve(method,resultMap); } } } ``` //执行jdbc ``` public Object geResult(Method method) throws Throwable { Object obj = new Object(); switch (modelOriginal.getType()){ case SELECT: obj = new SelectExecutor().executor(modelOriginal, method , resultMap); break; case INSERT: obj = new InsertExecutor().executor(modelOriginal, method , resultMap); break; case DELETE: break; case UPDATE: break; default: } return obj; } ```