首先,我们先模仿正常的项目,创建一个Dao层
package com.dxh.dao; import com.dxh.pojo.User; import java.util.List; public interface IUserDao { //查询所有用户 public List<User> findAll() throws Exception; //根据条件进行查询 public User findByCondition(User user) throws Exception; } package com.dxh.dao; import com.dxh.io.Resource; import com.dxh.pojo.User; import com.dxh.sqlSession.SqlSession; import com.dxh.sqlSession.SqlSessionFacetory; import com.dxh.sqlSession.SqlSessionFacetoryBuild; import java.io.InputStream; import java.util.List; public class IUserDaoImpl implements IUserDao { @Override public List<User> findAll() throws Exception { InputStream resourceAsStream = Resource.getResourceAsStream("sqlMapConfig.xml"); SqlSessionFacetory sqlSessionFacetory = new SqlSessionFacetoryBuild().build(resourceAsStream); SqlSession sqlSession = sqlSessionFacetory.openSession(); List<User> userList = sqlSession.selectList("user.selectList"); return userList; } @Override public User findByCondition(User user) throws Exception { InputStream resourceAsStream = Resource.getResourceAsStream("sqlMapConfig.xml"); SqlSessionFacetory sqlSessionFacetory = new SqlSessionFacetoryBuild().build(resourceAsStream); SqlSession sqlSession = sqlSessionFacetory.openSession(); User user2 = sqlSession.selectOne("user.selectOne",user); return user2; } } 问题分析:
很明显存在代码重复的问题,他们的前三句话都一样(加载配置文件、创建SqlSessionFacetory、生产SqlSeesion)
InputStream resourceAsStream = Resource.getResourceAsStream("sqlMapConfig.xml"); SqlSessionFacetory sqlSessionFacetory = new SqlSessionFacetoryBuild().build(resourceAsStream); SqlSession sqlSession = sqlSessionFacetory.openSession();
statementId存在硬编码问题
List<User> userList = sqlSession.selectList("user.selectList"); User user2 = sqlSession.selectOne("user.selectOne",user); 解决思路:使用代理模式生成Dao层代理实现类。
在SqlSession接口中增加一个方法并实现:
//为Dao接口生产代理实现类 public <T> T getMapper(Class<?> mapperClass); @Override public <T> T getMapper(Class<?> mapperClass) { //使用JDK动态代理来为Dao接口生成代理对象,并返回 Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }); return (T) o; }我们使用Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法来生产代理对象。一会我们再来实现invoke方法。
那么此时我们如果再想执行方法应该这样做:
IUserDao iUserDao = sqlSession.getMapper(IUserDao.class); List<User> all = iUserDao.findAll();通过sqlSession.getMapper()方法获得代理对象
通过代理对象调用findAll()方法
执行invoke方法
我们来看看invoke方法:
Object proxy :当前代理对象的引用
Method method :当前被调用方法的引用
比如我们当前的代理对象iUserDao调用的是findAll()方法,而method就是findAll方法的引用
Object[] args : 传递的参数,比如我们想要根据条件查询
编写invoke()方法:
我们要首先明确一点,不论如何封装,底层都还是执行JDBC代码,那么我们就要根据不同情况 调用selectList或者selectOne。
此时就有一个疑问了:selectList和selectOne都需要一个参数——statementId,而此时我们是拿不到statementId的。
但是我们可以根据method对象得到方法名,和方法所在类的全类名。
因此我们需要规范下statementId的组成:
statementId = namespace.id = 方法所在类的全类名.方法名
修改UserMapper.xml