在开始动态代理的原理讲解以前,我们先看一下集成mybatis以后dao层不使用动态代理以及使用动态代理的两种实现方式,通过对比我们自己实现dao层接口以及mybatis动态代理可以更加直观的展现出mybatis动态代理替我们所做的工作,有利于我们理解动态代理的过程,讲解完以后我们再进行动态代理的原理解析,此讲解基于mybatis的环境已经搭建完成,并且已经实现了基本的用户类编写以及用户类的Dao接口的声明,下面是Dao层的接口代码
public interface UserDao {
/*
查询所有用户信息
*/
List<User> findAll();
/**
* 保存用户
* @param user
*/
void save(User user);
/**
* 更新用户
* @return
*/
void update(User user);
/**
* 删除用户
*/
void delete(Integer userId);
/**
* 查找一个用户
* @param userId
* @return
*/
User findOne(Integer userId);
/**
* 根据名字模糊查询
* @param name
* @return
*/
List<User> findByName(String name);
/**
* 根据组合对象进行模糊查询
* @param vo
* @return
*/
List<User> findByQueryVo(QueryVo vo);
}
一、Mybatis dao层两种实现方式的对比
1.dao层不使用动态代理
dao层不使用动态代理的话,就需要我们自己实现dao层的接口,为了简便起见,我只是实现了Dao接口中的findAll方法,以此方法为例子来展现我们自己实现Dao的方式的情况,让我们来看代码:
public class UserDaoImpl implements UserDao{
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory){
this.factory = factory;
}
public List<User> findAll() {
//1.获取sqlSession对象
SqlSession sqlSession = factory.openSession();
//2.调用selectList方法
List<User> list = sqlSession.selectList("com.example.dao.UserDao.findAll");
//3.关闭流
sqlSession.close();
return list;
}
public void save(User user) {
}
public void update(User user) {
}
public void delete(Integer userId) {
}
public User findOne(Integer userId) {
return null;
}
public List<User> findByName(String name) {
return null;
}
public List<User> findByQueryVo(QueryVo vo) {
return null;
}
这里的关键代码 List<User> list = sqlSession.selectList("com.example.dao.UserDao.findAll"),需要我们自己手动调用SqlSession里面的方法,基于动态代理的方式最后的目标也是成功的调用到这里。
注意:如果是添加,更新或者删除操作的话需要在方法中增加事务的提交。
2.dao层使用Mybatis的动态代理
使用动态代理的话Dao层的接口声明完成以后只需要在使用的时候通过SqlSession对象的getMapper方法获取对应Dao接口的代理对象,关键代码如下:
//3.获取SqlSession对象
SqlSession session = factory.openSession();
//4.获取dao的代理对象
UserDao mapper = session.getMapper(UserDao.class);
//5.执行查询所有的方法
List<User> list = mapper.findAll();
获取到dao层的代理对象以后通过代理对象调用查询方法就可以实现查询所有用户列表的功能。
二、Mybatis动态代理实现方式的原理解析
动态代理中最重要的类:SqlSession、MapperProxy、MapperMethod,下面开始从入口方法到调用结束的过程分析。
1.调用方法的开始: //4.获取dao的代理对象
UserDao mapper = session.getMapper(UserDao.class); 因为SqlSesseion为接口,所以我们通过Debug方式发现这里使用的实现类为DefaultSqlSession。
2.找到DeaultSqlSession中的getMapper方法,发现这里没有做其他的动作,只是将工作继续抛到了Configuration类中,Configuration为类不是接口,可以直接进入该类的getMapper方法中
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
3. 找到Configuration类的getMapper方法,这里也是将工作继续交到MapperRegistry的getMapper的方法中,所以我们继续向下进行。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}