需求分析
- 执行sql
- 对结果集进行友好封装
- 使用简单
- 性能优化
代码设计
代码架构
代码执行流程
代码精剪
初始化
@Component
public class MybatisInit implements ApplicationContextAware{
@Value("${mybatis.mapperPackage}")
private String mapperPackage;
@PostConstruct
public void init() throws BeansException {
String packagePath = getPackagePath(mapperPackage);
String path = getClass().getClassLoader().getResource(packagePath).getPath();
File file = new File(path);
File[] files = file.listFiles();
ClassLoader classLoader = this.getClass().getClassLoader();
for (File child : files) {
try {
String filePath = child.getAbsolutePath();
String externalName = filePath.substring(filePath.lastIndexOf('/') + 1,filePath.length() - 6);
externalName = mapperPackage + "." + externalName;
Class<?> aClass = classLoader.loadClass(externalName);
MapperRegistry.addMapper(aClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@PreDestroy
private void destroy(){
ConnectFactory.destroy();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
String[] beanNames = applicationContext.getBeanNamesForAnnotation(Controller.class);
for (String beanName : beanNames) {
Object bean = applicationContext.getBean(beanName);
Field[] declaredFields = bean.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
Mapper resource = declaredField.getDeclaredAnnotation(Mapper.class);
if (resource != null){
try {
declaredField.setAccessible(true);
declaredField.set(bean,createService(declaredField.getType()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
public static <T, P> T createService(Class<T> interfaceClass) {
return (T) Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class<?>[]{interfaceClass},
new MapperProxy<T>(interfaceClass,new DefaultSqlSession()));
}
private String getPackagePath(String packageName) {
return packageName == null ? null : packageName.replace('.', '/');
}
}
MapperRegistry
public class MapperRegistry {
private static final Map<String, SqlBind> knownMappers = new HashMap<>();
public static <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
Method[] methods = type.getDeclaredMethods();
for (Method method : methods) {
String key = getKey(type.getName(), method.getName());
Select annotation = method.getAnnotation(Select.class);
try {
Type genericReturnType = method.getGenericReturnType();
String typeName = genericReturnType.getTypeName();
String className = null;
if (typeName.contains("<") && typeName.contains(">")){
className = typeName.substring(typeName.indexOf("<") + 1,typeName.indexOf(">"));
}
knownMappers.put(key,new SqlBind(annotation.sql().toLowerCase(),method.getParameterTypes(),method.getReturnType(),className));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private static <T> String getKey(String className, String methodName) {
return className + "#" + methodName;
}
public static <T> SqlBind<T> getMapper(Method method){
return knownMappers.get(getKey(method.getDeclaringClass().getName(), method.getName()));
}
}
MapperProxy
public class MapperProxy<T> implements InvocationHandler, Serializable {
private Class<T> aClass;
private SqlSession session;
public MapperProxy(Class<T> aClass, SqlSession session) {
this.aClass = aClass;
this.session = session;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args){
SqlBind<T> sqlBind = MapperRegistry.getMapper(method);
List<Object> execute = session.select(sqlBind.getReturnType(), sqlBind.getGenericClassName(), args, sqlBind.getSql());
if(sqlBind.getReturnType().getName().equals("java.util.ArrayList")){
return execute;
}
if (execute.size() > 0 && sqlBind.getGenericClassName() == null){
return execute.get(0);
}
return null;
}
}
示例
依赖
<dependency>
<groupId>com.yutian</groupId>
<artifactId>simple-mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
备注:包扫描com.yutian
配置
resources下创建配置文件mybatis.properties,内容如下
jdbc.url=
jdbc.user=
jdbc.password=
创建mapper接口
public interface MapperDemo {
/**
*
* @return 返回值
*/
@Select(sql = "SELECT name name,age age,gender gender from student where name = ?")
Student demo(String name);
}
调用
@Mapper
private MapperDemo mapperDemo;
@RequestMapping("/test2")
public Student test(String name){
Student demo = mapperDemo.demo(name);
return demo;
}
调用结果
性能优化
实现了一级缓存,对于同一个sqlSession的同一sql,同一参数,同一返回值进行了本地缓存。
代码地址
https://github.com/yutian1999/simple-mybatis