文章目录
动态代理机制
传统的MyBatis提供的API
传入的Statement ID参数无法检查错误
Mapper接口
使用Mapper接口,MyBatis 将配置文件中的每一个<mapper> 元素抽象为一个 Mapper 接口,而这个接口中声明的方法和<mapper> 元素中的<select|update|delete|insert> 子元素相对应
左右接口与id是一一对应的。
静态代理与动态代理
区分关键:程序运行阶段这三个实体是否存在
左面是目标实体,右面是代理实体,上面是接口。
下面两个实体都是去实现上面接口的
代理实体可以对真是实体做扩展
静态代理
一个交作业的接口
两个实现类,学生与班长
班长有学生作为参数
测试类通过实例化班长与学生并赋值,通过调用班长的属性来实现看作业批改的方法
项目结构
Master.java 班长类
package com.mybatis.demo;
//代理类
public class Master implements Submitted{
private Student student;
//实现抽象方法
@Override
public void submitHomework() {
student.submitHomework();
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
Student.java 学生类
package com.mybatis.demo;
//被代理类
public class Student implements Submitted{
private String name;
//实现接口的方法
@Override
public void submitHomework() {
System.out.println(name+"交作业");
}
//get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
需要实现的接口
package com.mybatis.demo;
public interface Submitted {
//代理类与被代理类都需要实现的接口
public void submitHomework();
}
Test.java 测试类
package com.mybatis.demo;
public class Test {
public static void main(String[] args) {
Master master=new Master();
Student student=new Student();
student.setName("九爷");
master.setStudent(student);
fun(master);
}
//参数是接口,只要实现了接口,具体对象是谁无所谓
public static void fun(Submitted sub) {
sub.submitHomework();
}
}
左上方是代理类与代理类需要实现的接口
最下方的是一个class,需要我们去定义
动态代理
项目结构
MyInvocationHandler.java
package com.mybatis.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler<T> implements InvocationHandler {
//被代理对象的类型,接口的类型,通用的T类型
T obj;
//重写此方法
//动态代理的核心
//代理类中,每个方法被调用时候都会执行此方法
//参数1:动态代理对象
//参数2:正在执行的方法
//参数3:是参数2的传入的实际参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通过反射执行代理类的方法
//参数1:需要被执行的方法,参数2:实际参数
Object result = method.invoke(obj, args);
//可以对代理的那个方法进行扩展
System.out.println("这是方法的扩展");
return null;
}
//封装出现代理类对象的方法
public T createProxySubject() {
//生成代理实例
//参数1:类加载器
//参数2:class数组,参数类需要实现的接口类型
//参数3:InvocationHandler类型
return (T) Proxy.newProxyInstance(Student.class.getClassLoader(),
new Class[] {
Submitted.class},
this);
}
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
Student.java 被代理类
package com.mybatis.demo;
//被代理类
public class Student implements Submitted{
private String name;
//实现接口的方法
@Override
public void submitHomework() {
System.out.println(name+"交作业");
}
//get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Submitted.java 需要实现的接口类
package com.mybatis.demo;
public interface Submitted {
//代理类与被代理类都需要实现的接口
public void submitHomework();
}
Test.java 测试类
package com.mybatis.demo;
public class Test {
public static void main(String[] args) {
//动态代理
Student s=new Student();
s.setName("张三");
//动态生成代理对象,(模拟SqlSession中的GetMapper方法的实现)
MyInvocationHandler<Student> invo=new MyInvocationHandler<>();
invo.setObj(s);
Submitted sub=invo.createProxySubject();
fun(sub);
}
//参数是接口,只要实现了接口,具体对象是谁无所谓
public static void fun(Submitted sub) {
sub.submitHomework();
}
}