MyBatis核心源码解析(二)
在MyBatis核心源码解析(一)中,我们对MyBatis的第一种调用源码做了深度分析,现在我们就开始介绍第二种情况
import com.User;
import com.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args){
/* ClassPathXmlApplicationContext applicationContext =new ClassPathXmlApplicationContext("spring-config.xml");
UserMapper userMapper= (UserMapper) applicationContext.getBean("userMapper");
userMapper.findUserById(1);*/
try {
InputStream inputStream= Resources.getResourceAsStream("mybatis.xml");
// 创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
// 根据sqlSessionFactory获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 这里采用了两种方式,一种是通过接口的方式,另外一种是直接使用sqlSession对象调用对应的方法
List<User> users= sqlSession.selectList("findUserById",2);
for (User user : users) {
System.out.println("Age : "+user.getAge()+"; Name : "+user.getName()+
"; Id : "+user.getId());
}
System.out.println("---------------------------");
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
List<User> list = userMapper.findUserById(1);
for (User user : list) {
System.out.println("Age : "+user.getAge()+"; Name : "+user.getName()+
"; Id : "+user.getId());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
我们关注这段代码 UserMapperuserMapper=sqlSession.getMapper
(UserMapper.class);然后我们进行调试
进入源码
这里我们看到有一个类叫MapperProxyFactory,从名字我们都可以看出来,这里会帮我们创建代理类来帮我们实现我们要做的事情,我们继续调试
可以看到这里获取了我们想要的类型接口,注意下面的代码return mapperProxyFactory.newInstance(sqlSession);
这里就不用我再强调了吧,这就是通过代理的手段根据接口类型来创建这个类。
好了,现在我们Mybatis已经实现了我们想要的东西,现在继续调试
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
先做一个判断,判断是不是Object类,明显不是,然后对到最后一行代码,
mapperMethod.execute(sqlSession, args);然后回调到这里
再调用
最终我们看到了熟悉的方法
sqlSession.selectList(command.getName(), param);
后面就不再描述了,在上个章节已经做了详细分析了,最后我们回顾下整个流程,就是Mybatis为我们创建了一个代理类,这个代理类帮我们去调用sqlsession类的方法,而sqlsession会调用执行器,最终回到JDBC底层代码操作数据库。