首页 > 其他分享 >MapperProxyFactory(映射器代理工厂)的实现原理

MapperProxyFactory(映射器代理工厂)的实现原理

时间:2023-05-25 10:22:05浏览次数:42  
标签:映射器 helloDao 代理 接口 clazz 对象 MapperProxyFactory public

再次回顾Mybatis的基本用法

1、定义Mapper接口

2、在xml(或注解)中写sql

mybatis帮我们屏蔽了所有和数据库相关的操作,我们只需要给他提供参数、sql、标注返回值的类型即可。

通过mapper接口我们可以传递参数、获取返回值;通过xml或者注解我们可以提供需要执行的sql。那么问题来了,究竟是谁在干活?我们经常在service中注入的dao来自于哪里?

答案自然是————代理

代理
那些年我对代理的偏见
代理在我的印象中一直使用来增强对象的,通常这么用

XXXXXX在目标对象方法执行前,做一些事(如日志记录)XXXXXXXX

调用目标对象的方法
method.invoke(target, args)

XXXXXX在目标对象方法执行后,做一些事(如日志记录)XXXXXXXX
大概是这个流程。

但实际上,代理不仅仅可以增强被代理对象的功能,也可以“无中生有”————给它一个接口,它能还你一个实实在在的对象。

实战
在不看mybatis源码的基础上,实现一个功能。

定义一个Dao接口,接口中至少得有一个方法。

我们通过jdk代理获得代理对象,并在service中使用这个代理对象。

Service大概如下

public class HelloService {
private HelloDao helloDao;
 
    public HelloService(HelloDao helloDao) {
        this.helloDao = helloDao;
    }

    public void test() {
        helloDao.sayHello("小明同学");
    }

    public static void main(String[] args) {
        HelloService helloService = new HelloService(ProxyUtils.proxy(HelloDao.class, new MapperHandler(HelloDao.class)));
        helloService.test();
    }
}

补充上图用到的一些组件

接口

public interface HelloDao {
    @Select("select * from hello")
    void sayHello(String name);
    }

自定义的注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Select {
    String value();
}

代理工具类

public class ProxyUtils {
public static <T> T proxy(Class<T> clazz, InvocationHandler invocationHandler) {
    return (T)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
	}
}

InvocationHandler实现

public class MapperHandler implements InvocationHandler {
	private Class<?> clazz;
 
public MapperHandler(Class<?> helloDao) {
    this.clazz = helloDao;
}
 
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if(args != null) {
        for (Object arg : args) {
            System.out.println("通过代理拿到了参数:" + arg);
        }
    }
 
    for (Method declaredMethod : clazz.getDeclaredMethods()) {
        for (Parameter parameter : declaredMethod.getParameters()) {
            System.out.println("通过反射拿到了参数以及类型等:" + parameter.getName() + " , " + parameter.getType());
        }
        for (Annotation annotation : declaredMethod.getAnnotations()) {
            if(annotation instanceof Select) {
                Select select = (Select) annotation;
                String value = select.value();
                System.out.println("拿到了sql: " + value);
            }
        }
    }
    return "执行结果";
}

}

运行:

通过反射拿到了接口标注的所有信息,并且成功的生成了代理类。

总结一下如何通过代理实现“无中生有”。或者说通过接口直接生成代理对象,与通过类生成代理对象有何区别?

第一点,“无中生有”在invoke方法中不需要调用被代理对象的方法(因为压根没有被代理对象)

第二点,创建代理对象时,因为clazz是接口,所以newProxyInstance的第二个参数直接传递的是clazz本身,而非之前的 clazz.getInterfaces()

MapperProxyFactory
回头看Mybatis的代理工厂,似乎就很清晰了

似乎与我们的做法一致

mapperProxy其实就是InvocationHandler

至于MapperMethod是什么,以及代理对象如何执行sql的,后面总结。

如有错误,欢迎批评指正!

标签:映射器,helloDao,代理,接口,clazz,对象,MapperProxyFactory,public
From: https://www.cnblogs.com/jundong2177/p/17430366.html

相关文章

  • BT131-ASEMI代理KY原装双向可控硅BT131
    编辑:llBT131-ASEMI代理KY原装双向可控硅BT131型号:BT131品牌:韩景元\KY封装:TO-92特性:可控硅正向电流:1A反向耐压:600V触发电压:0.62~0.8V引脚数量:3芯片个数:1包装方式:3000pcs/盘浪涌电流:40A特点:单向可控硅工作温度:-40℃~150℃BT131应用范围:洗衣机、吸尘器、按摩器、固态......
  • 【Spring从成神到升仙系列 一】2023年再不会动态代理,就要被淘汰了
    ......
  • 域名配置动态代理后,为什么每次 ping 还是相同的 ip?
    当你配置了域名的动态代理后,ping命令所显示的IP地址不会随着代理服务器的变化而变化。这是因为ping命令使用了DNS缓存,它会将域名解析结果缓存到本地,直到缓存过期或者手动清除缓存之前,ping命令都会使用相同的IP地址进行测试。通常情况下,DNS缓存的过期时间是比较长的,可......
  • ASEMI代理长电可控硅MCR100-8特征,MCR100-8应用
    编辑-Z长电可控硅MCR100-8参数:型号:MCR100-8VDRM/VRRM:600VIT(RMS):0.8A结点温度Tj:-40~125℃储存温度Tstg:-55~150℃通态电压VTM:1.7V栅极触发电压VGT:0.8V正向或反向阻断电流峰值:10µA保持电流IH:5mA栅极触发电流IGT:15µA  MCR100-8封装规格:封装:TO-92总长度:19.2mm......
  • python嵌入HTTP代理代码示例
    以下是使用Python嵌入HTTP代理的示例代码:```pythonimporturllib.request#设置代理服务器地址和端口号proxy_handler=urllib.request.ProxyHandler({'http':'http://proxy.example.com:8080'})#创建opener对象opener=urllib.request.build_opener(proxy_handler)#使用opene......
  • JAVA代理
    java代理静态代理和动态代理简介优点缺点静态代理在不修改目标对象的基础上,通过扩展类对目标对象进行增强和扩展。静态代理对客户(测试类)隐藏了被代理类接口(目标类接口)的具体实现类,在一定程度上实现了解耦合,同时提高了安全性。静态代理类需要实现目标类(被代理类)的接......
  • 傻傻的npm run serve吗?还有其他方法换项目中的代理
    1.直接修改封装的axioshost使用浏览器跨域2.--------hostconfig.js--------module.exports={"target":"http://xxxxxx"};---------vue.config.js----------/*target:'thatmusthaveaemptyplaceholder',//changeOri......
  • 爬虫为什么会使用到代理ip?
    爬虫使用代理IP的主要目的是为了隐藏自己的真实IP地址,以避免被目标网站封禁或限制访问。如果一个爬虫频繁地向一个网站发送请求,而且每次请求的IP地址都相同,那么这个网站就有可能认为这是一种恶意行为,从而采取封禁或限制访问的措施。使用代理IP可以让爬虫在每次请求时使用不同的IP地......
  • MCR100-6-ASEMI代理长电原装单向可控硅MCR100-6
    编辑:llMCR100-6-ASEMI代理长电原装单向可控硅MCR100-6型号:MCR100-6品牌:长电\CJ封装:TO-92特性:可控硅正向电流:0.8A反向耐压:400V触发电压:0.62~0.8V引脚数量:3芯片个数:1包装方式:3000pcs/盘浪涌电流:40A特点:单向可控硅工作温度:-55℃~150℃MCR100-6应用范围:逆变焊机控制,相位控制应用,固态继......
  • 利用Putty建立SSH通道实现代理
    以前有介绍过MyEnTunnel来代理,但是MyEnTunnel不支持Win7,其实MyEnTunnel就是利用putty的,我们为何不自己使用putty来创建SSH通道来实现代理上网呢?用putty建立SSH通道其实也很简单。设置putty很简单,打开putty,找到左边的SSH,选择Tunnels,然后在Sourceport上填入你想要的端口号,然后Add一......