思想

MyBatis中封装了SqlSession来执行具体的JDBC操作,在不使用MyBatis提供的动态代理机制的情况下,Dao层需要手动调用SqlSession来实现对数据库的CRUD,会造成代码的相对冗余和重复。
例如(以StudentDao为例,以下如此):

    public Student selectOne(int id) {
        return sqlSession.selectOne("selectOne", id);
    }

在使用MyBatis提供的动态代理机制后,就可以将Dao层接口化,java底层自动创建的代理对象将会继承指定的某个Dao类生成对应的子类,调用SqlSession,从而实现某个具体的功能点。
获取代理对象,并指定某个操作:

    StudentDao dao = SqlSessionUtil.getSqlSession().getMapper(StudentDao.class);
    dao.selectOne(id);

注意:
代理对象调用方法不需要传递方法的id,方法的id强制为方法名,底层通过反射技术将方法名和解析后的xml文件标签里的id进行匹配从而找到SQL。

代理对象实现原理

代理对象要想调用SqlSession找到对应的方法,需要知道SQL参数

  • SQL:
    • 在基于xml开发中SQL在StudentMapper.xml中,需要解析xml文件获取。
    • 在基于注解开发中SQL在注解上,需要解析注解获取。
  • 参数:
    • Service层传递

模拟getMapper()方法:

   public <T> T getMapper(Class clazz) {
        // 加载器用来加载类
        ClassLoader classLoader = clazz.getClassLoader();
        // 代理对象可以同时代理多个类,一般为一个
        Class[] classes = new Class[] {clazz};
        InvocationHandler handler = new InvocationHandler() {
            /**
             * 代理对象调用某个具体方法的途径
             * @param proxy 系统创建的代理对象
             * @param method 代理执行的具体方法
             * @param args 方法执行需要的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                method.invoke(proxy, args);
                return proxy;
            }
        };
        // 构建出继承自指定Dao的代理对象
        Object mapper = Proxy.newProxyInstance(classLoader, classes, handler);
        return (T) mapper;
    }