自定义持久层框架 -- 功能优化

一、自定义持久层框架问题分析

  1. Dao层在使用自定义持久层框架的时候,存在代码重复,整个操作的过程模板重复(加载配置文件;创建SqlSessionFactory;生产SqlSession)
  2. statementId 存在硬编码问题

二、解决思路

  1. 将Dao层实现类删除,保留Dao层接口
  2. 使用JDK动态代理去生成一个Dao层接口的代理类
  3. 接口传参的时候获取不到配置文件的 namespace 以及 selectId,所以 statementId 如果想在代理类的invoke方法中定义出statementId,那么必须对配置文件中的 namespace 以及 selectId 有一个严格规范的规约:namespace 必须为接口全限定;selectId 必须和 Dao 层接口中的方法名一样。

三、代码编写

  1. Dao层
public interface IUserDao {

    //查询所有用户
    List<User> findAll() throws Exception;

    //根据条件进行用户查询
    User findByCondition(User user) throws Exception;
}
  1. UserMapper.xml 注意里面的 namespace 和 select标签id
<mapper namespace="com.wujun.dao.IUserDao">

    <select id="findAll" resultType="com.wujun.pojo.User">
        select * from user
    </select>

    <select id="findByCondition" resultType="com.wujun.pojo.User" parameterType="com.wujun.pojo.User">
        select * from user where id = #{id} and username = #{username}
    </select>
</mapper>
  1. SqlSession接口中加一个接口<T> T getMapper(Class<?> clazz);
  2. DefaultSqlSession中实现getMapper接口
@Override
public <T> T getMapper(Class<?> clazz) {

    // 使用JDK动态代理来为Dao接口生成代理对象
    Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 获取statementId(基于严格规约:接口全限定名 + 接口名)
            String methodName = method.getName();// 方法名
            String declaringClassName = method.getDeclaringClass().getName();// 接口的全限定名
            String statementId = declaringClassName + "." + methodName;

            // 获取被调用方法的返回值类型
            Type genericReturnType = method.getGenericReturnType();
            // 判断是否进行了 泛型类型参数化
            if (genericReturnType instanceof ParameterizedType) {
                return selectList(statementId, args);
            } else {
                return selectOne(statementId, args);
            }
        }
    });

    return (T) proxyInstance;
 }
  1. 重写测试类
public class IPersistenceTest {

    @Test
    public void test() throws Exception {
        InputStream resourceAsSteam = Resources.getResourceAsSteam("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuild().build(resourceAsSteam);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        User user = new User();
        user.setId(1L);
        user.setUsername("吴俊1");
//        User sqlResult = sqlSession.selectOne("com.wujun.dao.IUserDao.findByCondition", user);
//        System.out.println(JSON.toJSONString(sqlResult));

        IUserDao userDao = sqlSession.getMapper(IUserDao.class);
        User user1 = userDao.findByCondition(user);
        System.out.println("findByCondition result:" + JSON.toJSONString(user1));

        List<User> all = userDao.findAll();
        for (User user2 : all) {
            System.out.println("findAll result:" + JSON.toJSONString(user2));
        }
    }


}
  1. 返回结果
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.dom4j.io.SAXContentHandler (file:/D:/repository/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar) to method com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$LocatorProxy.getEncoding()
WARNING: Please consider reporting this to the maintainers of org.dom4j.io.SAXContentHandler
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
log4j:WARN No appenders could be found for logger (com.mchange.v2.log.MLog).
log4j:WARN Please initialize the log4j system properly.
findByCondition result:{"id":1,"username":"吴俊1"}
findAll result:{"id":1,"username":"吴俊1"}
findAll result:{"id":2,"username":"吴俊2"}
findAll result:{"id":3,"username":"吴俊3"}

Process finished with exit code 0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容