创一东莞网站建设,专业h5网站建设教程,营销策划方案网站,西宁做网站制作的公司哪家好引言
最近刚写完毕设#xff0c;闲来无事#xff0c;看到网上有一个手撸Mybatis的教程#xff0c;于是想自己实现一个简易版的Mybatis。 本专栏的源码#xff1a;https://gitee.com/dhi-chen-xiaoyang/yang-mybatis。
创建简单的映射器代理工厂
在使用mybatis的时候闲来无事看到网上有一个手撸Mybatis的教程于是想自己实现一个简易版的Mybatis。 本专栏的源码https://gitee.com/dhi-chen-xiaoyang/yang-mybatis。
创建简单的映射器代理工厂
在使用mybatis的时候我们一般只需要定义mapper的接口并添加相应的Mapper注解然后实现对应的xml文件即可而不需要对mapper接口进行具体的实现。其实本质上这些mapper接口是有实现的但不是我们手动通过implement来实现而是通过代理的方式进行实现。因此对于Mybatis的手撸首先要关注的就是如何对mapper进行代理。 首先我们定义一个MapperProxy该类实现InvocationHandler接口通过实现该接口实现动态代理。这里有两个属性——sqlSession和mapperInterface其中sqlSession是用来模拟执行sql语句的。
package com.yang.mybatis.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;public class MapperProxyT implements InvocationHandler {private MapString, Object sqlSession ;private ClassT mapperInterface;public MapperProxy(MapString, Object sqlSession, ClassT mapperInterface) {this.sqlSession sqlSession;this.mapperInterface mapperInterface;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);}String key this.mapperInterface.getName() . method.getName();return sqlSession.get(key);}
}
当我们在执行mapper的某个方法时最终会进入到invoke方法并通过sqlSession来获取模拟值。 接着我们定义MapperProxyFactory每一个mapper都有一个MapperProxyFactory与之相对应然后newInstance方法接收模拟的sql结果并通过Proxy.newProxyInstance创建动态代理对象。
package com.yang.mybatis.proxy;import java.lang.reflect.Proxy;
import java.util.Map;public class MapperProxyFactory T {private final ClassT mapperInterface;public MapperProxyFactory(ClassT mapperInterface) {this.mapperInterface mapperInterface;}public T newInstance(MapString, Object sqlSession) {MapperProxyT mapperProxy new MapperProxy(sqlSession, mapperInterface);return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),new Class[]{mapperInterface},mapperProxy);}
}
最后我们先创建一个IUserMapper类
package com.yang.mybatis.test;public interface IUserMapper {String queryUserName(Integer id);Integer queryUserAge(Integer id);
}
然后创建对应的测试方法
package com.yang.mybatis.test;import com.yang.mybatis.proxy.MapperProxyFactory;import java.util.HashMap;
import java.util.Map;public class Main {public static void main(String[] args) {MapperProxyFactoryIUserMapper userDaoMapperProxyFactory new MapperProxyFactory(IUserMapper.class);MapString, Object sqlSession new HashMap();sqlSession.put(com.yang.mybatis.test.IUserMapper.queryUserName, 模拟查询用户名);sqlSession.put(com.yang.mybatis.test.IUserMapper.queryUserAge, 1);IUserMapper iUserMapper userDaoMapperProxyFactory.newInstance(sqlSession);System.out.println(iUserMapper.queryUserAge(1));System.out.println(iUserMapper.queryUserName(1));}
}
运行结果如下
实现映射器的注册和使用
像上述的这种方法我们每次要获取一个Mapper就要new一个对应的MapperProxyFactory这样不太方便。一般情况下mapper是放在同一个包下的那么我们可以通过扫描包来初始化MapperProxyFactory。至于上一节的sqlSession因为我们目前是模拟数据所以在初始化过程中把这些模拟数据要随便mock住就行。 因为要扫描包获取包下的Class类我们先添加hutool-all以便通过其提供的ClassScanner获取包 dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.8.12/version/dependency然后我们修改MapperProxyFactory
package com.yang.mybatis.proxy;import cn.hutool.core.lang.ClassScanner;import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class MapperProxyFactory {private MapClass, MapperProxy mapperProxyMap new HashMap();public MapperProxyFactory(String packageName) {// 扫描包ClassScanner scanner new ClassScanner(packageName);SetClass? mapperTypes scanner.scan();for (Class? mapperType : mapperTypes) {if (!mapperType.isInterface()) {// 只对接口进行处理continue;}MapString, String mockSqlSession mockSqlSession(mapperType);MapperProxy mapperProxy new MapperProxy(mockSqlSession, mapperType);mapperProxyMap.put(mapperType, mapperProxy);}}public Object newInstance(Class mapperType) {MapperProxy mapperProxy mapperProxyMap.get(mapperType);return Proxy.newProxyInstance(mapperType.getClassLoader(),new Class[]{mapperType},mapperProxy);}private MapString, String mockSqlSession(Class mapperType) {MapString, String sqlSession new HashMap();for (Method method : mapperType.getMethods()) {String methodName method.getName();String key mapperType.getName() . methodName;sqlSession.put(key, key);}return sqlSession;}
}最后进行测试 public static void main(String[] args) {MapperProxyFactory mapperProxyFactory new MapperProxyFactory(com.yang.mybatis.test);IUserMapper iUserMapper (IUserMapper) mapperProxyFactory.newInstance(IUserMapper.class);System.out.println(iUserMapper.queryUserName(1));}测试结果如下