mybatis中的动态代理解析

2020-11-23  本文已影响0人  _FireFly_

动态代理的目的: 一个接口需要通过动态代理对象为自己产生一个匿名的实现类,平时我们都是自己实现这个接口,然后通过new这个接口的实现类来创建这个接口的对象,然后执行这个接口中的方法;这里不需要我们自己来实现这个接口,通过动态代理的方法,系统会为我们new一个实现这个接口的匿名对象,然后通过这个系统产生的匿名对象来执行原来接口中的方法

Student

package domain;
public class Student {

    private Integer sid;
    private String sname;
    private String ssex;
    private Integer sage;

    public Student() {
    }

    public Student(Integer sid, String sname, String ssex, Integer sage) {
        this.sid = sid;
        this.sname = sname;
        this.ssex = ssex;
        this.sage = sage;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getSsex() {
        return ssex;
    }

    public void setSsex(String ssex) {
        this.ssex = ssex;
    }

    public Integer getSage() {
        return sage;
    }

    public void setSage(Integer sage) {
        this.sage = sage;
    }
}

StudentDao

public interface StudentDao {

//    //属性
//    private SqlSession sqlSession = new SqlSessionFactory().openSession();
//
//    //dao中有一个具体的方法
//    //负责执行数据库的写操作
//    public void insert(Student student){
//        sqlSession.insert("sqlid",student);
//    }

    public void insert(Student student);//dao变成接口的时候 方法名字 必须与sqlid
}

StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.StudentDao">
    <insert id="insert">
      insert into student values(#{sid},#{sname},#{ssex},#{sage})
    </insert>
</mapper>

StudentService

public class StudentService {

    //基于框架
//    private StudentDao dao = MyUtil.getSqlSession().getMapper(StudentDao.class);
    //自己写的
    private StudentDao dao = MyUtil.getSqlSession().getMapper(StudentDao.class);


    //设计一个业务的方法 注册 新增方法
    public void insertStudent(Student student){
        //判断以下当前更新的人主键是否冲突
        //if(){}
        dao.insert(student);
    }
}

SqlSession(这里模仿Mybatis中的SqlSession)

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class SqlSession {

    //可以理解为 这个类的对象 是以前我们MyBatis提供的对象

    //预先将mapper.xml文件全部内容读取并解析的过程
    static{
        //读取mapper.xml文件内容
        //解析内容
        //      <mapper namespace="dao.StudentDao">
        //          <insert id="sqlid">
        //              insert into student values(#{sid},#{sname},#{ssex},#{sage})
        //          </insert>
        //      </mapper>

        //      mapper类型的对象(namespace属性 List<Insert对象> list<Update对象>)
        //      insert类型的对象(id属性 sql属性)
        //      update类型的对象(id属性 sql属性)
    }

    public void insert(String sqlid,Object obj){
        //应该做什么?????
        //原来的JDBC流程
        //1.导包
        //2.加载驱动
        //*3.获取连接(连接池方式管理)
        //*4.通过传递的sqlid找寻一条SQL语句(解析XML文件)
        //5.创建状态参数(预处理 优先加载SQL语句)
        //*6.SQL语句和提供的参数信息组合完整(分析SQL语句#{key},反射在obj对象中找value)
        //7.执行操作executeUpdate();
        //8.关闭
        System.out.println("我是SqlSession中的insert方法,我执行了好多好多");
    }

    //模仿Mybatis中的getMapper()方法
    public <T>T getMapper(Class clazz){
        //创建代理对象
        //  ClassLoader 需要被代理的类[] 做哪一件事情(方法)
        ClassLoader loader = clazz.getClassLoader();
        Class[] classes = new Class[]{clazz};
        InvocationHandler handler = new InvocationHandler() {
            //这个invoke方法相当于是代理对象的真正执行方法
            //Object proxy  :   这个对象是通过传入参数(Class clazz) 产生的匿名对象
            //Method method   :  这个是接口中的方法   public void insert(Student student);----->  insert
            //Object[] args   :  这个参数是接口中的参数 public void insert(Student student); -----> (Student student)
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("我是代理执行的方法");
                System.out.println("代理对象"+proxy.getClass().getName());
                System.out.println("代理对象代替真实对象做的方法"+method.getName());
                System.out.println("代理对象接收到真实对象的参数"+args[0]);
                //insert("sqlid",student);
                return proxy;
            }
        };
          //创建动态代理对象需要三个参数
          //这里我们通过动态代理机制来为 StudentDao接口来产生匿名对象,执行 StudentMapper.xml文件中的方法
         // 第一个参数为需要代理对象接口的类加载器
         //第二个参数为需要产生代理对象接口的反射
         //第三个参数为具体这个匿名对象执行的方法 这个方法需要解析  StudentMapper.xml文件,然后执行其中的方法
        Object obj = Proxy.newProxyInstance(loader,classes,handler);//代理对象(原来Dao接口的子类)
        //做一个造型
        T t = (T)obj;
        //造型以后的代理对象返回出去
        //代理对象是传递进来参数Class类型的子类对象
        return t;
    }

}

上一篇下一篇

猜你喜欢

热点阅读