Mybatis学习--11.动态代理生成实现某个接口的对象
MyBatis中通过动态代理生成实现接口的对象
在mybatis中对javassist进行了二次封装,即可以在mybatis中使用javassist
经过我们的改造,我们的dao层的AccountDaoImpl类已经变成了以下模样
package com.deng.bank.dao.impl; import com.deng.bank.dao.AccountDao; import com.deng.bank.pojo.Account; import com.deng.bank.utils.SqlSessionUtil; import org.apache.ibatis.session.SqlSession; public class AccountDaoIm implements AccountDao { public Account select(String actno){ SqlSession sqlSession = SqlSessionUtil.getSqlSession(); Account act = (Account)sqlSession.selectOne("account.selectByActno", actno); return act; } public int update(Account act){ SqlSession sqlSession = SqlSessionUtil.getSqlSession(); int update = sqlSession.update("account.updateByActno", act); return update; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
* 可以发现,每个方法都有一行固定的代码,且其他代码也非常固定(CRUD)。那么我们能不能不编写该类,而是使用javassist帮我们动态生成呢,答案是可以的,并且在mybatis中已经实现了,为了加深理解,我们先手写底层逻辑
* 用户需要将接口作为参数传入
* 获得类池对象,并使用该对象动态生成要返回的类,以及接口,并让该类实现该接口
* 获取接口内的所有方法,并实现。具体过程
* 拼接方法:创建一个StringBuilder对象,先将方法的框架拼接出来
* 再拼接方法内容。那行重复的代码可以直接拼接。后面的代码需要通过sqlid来确定,因此我们还需要用户将SqlSession作为参数传入。
* 关键:由于SqlId是由用户编写的,可变性太大,不利于框架开发者开发,因此开发者规定:Mapper文件中的namespace必须为接口的全限定名,SqlId必须为方法名。否则无法使用该动态代理生成方法。
* 将类加入内存并实例化
* 最后返回该类
* ```java
package com.deng.bank.utils;
import com.deng.bank.pojo.Account;
import org.apache.ibatis.javassist.CannotCompileException;
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSession;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* author:dch
* this class is used to generate the object that implement the DAO's Interface
*/
public class GenerateDaoProxy {
public Object Generate(SqlSession sqlSession, Class AccountDao){
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass(AccountDao.getName() + "Proxy");
CtClass anInterface = pool.makeInterface(AccountDao.getName());
ctClass.addInterface(anInterface);
//implement the functions
Method[] methods = AccountDao.getDeclaredMethods();
Arrays.stream(methods).forEach(method -> {
StringBuilder methodCode = new StringBuilder();
//public void delete(int a,int b){...};
methodCode.append("public ");
methodCode.append(method.getReturnType().getName() + " ");
methodCode.append(method.getName() + " ");
methodCode.append("(");
Class<?>[] types = method.getParameterTypes();
for (int i = 0; i < types.length; i++) {
methodCode.append(types[i] + "arg" + i);
if(i != types.length - 1){
methodCode.append(",");
}
}
methodCode.append("){");
//SqlSession sqlSession = SqlSessionUtil.getSqlSession();
methodCode.append("org.apache.ibatis.session.SqlSession sqlSession = com.deng.bank.utils.SqlSessionUtil.getSqlSessioni();");
String SqlId = AccountDao.getName() + "." + method.getName();
SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(SqlId).getSqlCommandType();
if(sqlCommandType == SqlCommandType.DELETE){
}else if(sqlCommandType == SqlCommandType.INSERT){
}else if(sqlCommandType == SqlCommandType.SELECT){
methodCode.append("return sqlSession.selectOne(\""+SqlId+"\",arg0);");
}else if(sqlCommandType == SqlCommandType.UPDATE){
methodCode.append("return sqlSession.update(\""+SqlId+"\",arg0);");
}
methodCode.append("}");
try {
CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
ctClass.addMethod(ctMethod);
} catch (CannotCompileException e) {
e.printStackTrace();
}
});
//put the class to internal storage and instantiation
Object o = null;
try {
o = ctClass.toClass().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return o;
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 dch'blog!