模拟myBatis源码的类结构
自己手动实现MyBatis源码:
第一步, 生命一个SqlSession, SqlSession两大主要组件, Configuration, Executor.,
其中Configuraion保存了所有配置信息如: Mapper,DataSource, Trancation等,
这次 v1.0版只编写最简单的Mapper信息
模拟SqlSession代码:
public class AutoSqlSession {
private AutoConfiguration configuration;
private AutoExecutor executor;
public AutoSqlSession(AutoConfiguration configuration, AutoExecutor executor) {
this.configuration = configuration;
this.executor = executor;
}
//返回Mapper
public <T> T GetMapper(Class clazz) {
return (T) this.configuration.getMapper(clazz,this);
}
//直接查询
public <T> T SelectOne(String stateMent) {
return this.executor.query(stateMent);
}
}
AutoConfiguration:
包含XMLParser静态类, 用来模拟保存Configuraion中的Mapper信息,
包含getMapper, 用来返回用户IMapper的代理.
代码:
public class AutoConfiguration {
//用来返回代理后的用户Mapper接口
public <T> T getMapper(Class<T> clazz, AutoSqlSession session) {
AutoMapperProxy proxy = new AutoMapperProxy(session);
return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{clazz}, proxy);
}
//模拟存储Mapper.xml中的用户SQL配置信息
public static class XMLParser {
static Map mapSqls = new HashMap<>();
static {
mapSqls.put("com.gupaoedu.mybatis.Auto.TestMapper.selectByPrimaryKey", "select *from User where id=?");
}
static String GetStatemenet(String strKey) {
return String.valueOf(mapSqls.get(strKey));
}
}
}
SqlSession中所有于数据库的交互全部由Executor类执行, 模拟创建Executor执行器类
// 定义接口IExecutor
public interface IExecutor {
<T> T query(String strStateMent);
}
//定义IExecutor 的实现类
public class AutoExecutor implements IExecutor {
@Override
//此处使用最原始的JDBC连接数据库
public <T> T query(String strStateMent) {
Connection connection = null;
PreparedStatement preparedStatement = null;
UserBean test = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://x.x.x.x:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC", "x", "x");
preparedStatement = connection.prepareStatement(strStateMent);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
test = new UserBean();
test.setId(rs.getInt(1));
test.setName(rs.getString(2));
test.setAge(rs.getInt(3));
test.setSex(rs.getBoolean(4));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (null != connection) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return (T)test;
}
}
SqlSession使用getMapper返回用户接口的代理,代理类如下:
public class AutoMapperProxy implements InvocationHandler {
private AutoSqlSession session;
public AutoMapperProxy(AutoSqlSession session) {
this.session = session;
}
//注意用户接口的调用在此处被代理为sqlSession.SelectOne方法,
//SelelectOne方法最终由 Executor.query去执行.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ((method.getDeclaringClass().getName() + "." + method.getName()).equals("com.gupaoedu.mybatis.Auto.TestMapper.selectByPrimaryKey")) {
String strSql = AutoConfiguration.XMLParser.GetStatemenet("com.gupaoedu.mybatis.Auto.TestMapper.selectByPrimaryKey");
strSql= strSql.replace("?", args[0].toString());
return session.SelectOne(strSql);
} else {
return method.invoke(this, args);
}
}
}
模拟用户调用:
创建Bean:
public class UserBean {
private int id;
private String name;
private int age;
private boolean sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
创建用户Mapper接口
public interface TestMapper {
UserBean selectByPrimaryKey(Integer userId);
}
测试代码:
public class AutoBatisTest {
public static void main(String[] args) {
AutoSqlSession session =new AutoSqlSession(new AutoConfiguration(),new AutoExecutor());
TestMapper mapper = session.GetMapper(TestMapper.class);
//此处注意:用户接口mapper 没有实现类,接口方法调用被悄悄代理为用MapperProxy实例去请求数据库.
UserBean bean = mapper.selectByPrimaryKey(1);
System.out.println(bean.getName());
}
}