mybatis之动态代理的应用

在前文(https://www.cnblogs.com/NYfor2018/p/9093472.html)我们知道了,Mybatis的使用需要用到Mapper映射文件,一个是映射接口,另一个是映射XML文件(此处不详谈映射文件XML),在应用中我们可以感觉到,映射接口似乎对接着XML文件中的实现命令,可是我们在运行程序是时候调用的往往是Mapper接口,而不是一个包含逻辑的实现类。很显然Mapper产生了代理类。

首先,什么是代理模式?代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。(取自百度百科:https://baike.baidu.com/item/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F/8374046?fr=aladdin

举个栗子,如图:

我们租房的时候一般是去找中介,而不是直接去找包租婆。放在代理模式这里来说,就是,我们在访问真实的对象的时候,往往不是直接去访问真实对象,而是通过代理对象,来对真实对象进行访问。

为什么要使用代理模式?通过代理,一方面可以控制如何访问真正的服务对象,提供额外的服务。另外一方面有机会通过重写一些类来满足特定的需要。就像是,有时候租客反映的一些问题,中介可以直接解决而不需要麻烦到包租婆。

一般来说,动态代理分为两种:一种是JDK反射机制提供的代理;另一种是CGLB代理。在JDK提供的代理,我们必须要提供接口;而在CGLIB中则不需要提供接口。

在学习动态代理之前,先了解一下反射的基础。

反射简单应用

import java.lang.reflect.Method;
public class ReflectService { public void sayHello(String name) { System.out.println("hello"+name); } public static void main(String[] args) throws Exception, IllegalAccessException, ClassNotFoundException { //通过反射创建ReflectService对象 Object service = Class.forName(ReflectService.class.getName()).newInstance(); //获取服务方法 Method method = service.getClass().getMethod("sayHello", String.class); //反射调用方法 method.invoke(service, "zhangsan");
}
}

 

①   先根据类名,来创建实例对象,所以就找了ReflectService类的类名。

②   然后再根据实例对象来找回它的方法,参数是方法名及其参数。

③   利用反射机制来调用ReflectService类的sayHello方法。

JDK动态代理

 

JDK的动态代理,是由JDK的java.lang.reflect.*包提供支持的,我们需要完成以下步骤:

① 编写服务类和接口,服务类是真正的服务提供者,而JDK代理中接口是必要的。

② 编写代理类,提供绑定和代理方法。

首先,先编写动态代理的接口

public interface HelloService {

         public void sayHello(String name);

}

接着,写一个这个接口的实现类

public class HelloServiceImpl implements HelloService{

         @Override
public void sayHello(String name) {
System.out.println("hello "+name);
}
}

然后,写一个代理类,提供真实对象的绑定和代理方法。代理类的要求是实现InvocationHandler接口的代理方法,当一个对象被绑定后,执行其方法的时候就会进入到代理方法里。

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

public class HelloServiceProxy implements InvocationHandler{

         /**

          * 真实的服务对象

          */

         private Object target;

         /**

          *

          * @param target

          * @return 绑定委托对象并返回一个代理类

          */

         public Object bind(Object target) {

                   this.target = target;

                   //取得代理对象

                   //public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException

                   //loader服务对象的类加载器,interfaces是加载服务对象的接口,h是执行这个代理类的方法的执行者

                   return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

         }

         @Override

         /**

          * 通过代理对象调用方法首先进入这个方法

          * invoke方法的参数分别是:proxy是代理对象,method是被调用的方法,args是方法的参数

          */

         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                   System.err.println("#########我是JDK动态代理##########");

                   Object result = null;

                   //反射方法前调用

                   System.err.println("我准备说hello");

                   result = method.invoke(target, args);

                   //反射方法后调用

                   System.err.println("我说过hello了");

                   return result;

         }

}

最后,编写一个测试类:

public class HelloServiceMain {

         public static void main(String[] args) {

                   HelloServiceProxy HelloHandler = new HelloServiceProxy();

                   HelloService proxy = (HelloService)HelloHandler.bind(new HelloServiceImpl());

                   proxy.sayHello("张三");

         }

}

运行出来的结果是:

整个过程可以这样理解:

先创建一个代理类对象a,然后用代理类对象绑定真正提供服务对象b,返回一个接口b+,再用这个接口b+来进行服务。

如果我们把proxy.sayHello(“张三”);注释掉:

我们会发现控制台什么东西都没有输出。

所以我们可以知道,代理类的invoke方法,只有在代理的真正提供服务的对象被调用的时候,才会起作用。

所以这时候我们可以这样理解:

挑选的人相当于访问者,相亲交流平台相当于代理,被挑选的人相当于真正提供服务的对象。当挑选的人在向相亲交流平台要求得到被挑选的人的信息,实际上,提供信息的人不是平台,是被挑选的人。挑选的人在对被挑选的人打招呼,而不是对相亲交流平台打招呼。而且,相亲交流平台不只是为一个独特的挑选的人提供被挑选的人的信息,只要有忍看上被挑选的人,相亲交流平台就可以提供ta的信息。

 

CGLIB动态代理

此处仅突出CGLIB动态代理跟JDK动态代理在代理类上的区别:

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;

import org.springframework.cglib.proxy.MethodInterceptor;

import org.springframework.cglib.proxy.MethodProxy;

public class HelloServiceCgLib implements MethodInterceptor{

         private Object target;

         public Object getInstance(Object target) {

                   this.target = target;

                   Enhancer enhancer = new Enhancer();

                   enhancer.setSuperclass(this.target.getClass());

                   //回调方法

                   enhancer.setCallback(this);

                   return enhancer.create();

         }

         @Override

         public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

                   System.err.println("##########我是CGLIB的动态代理##########");

                   //反射方法前调用

                   System.err.println("我准备说hello");

                   Object returnObj = proxy.invokeSuper(obj, args);

                   //反射方法后调用

                   System.err.println("我说过hello了");

                   return returnObj;

         }

}

可以看到CGLIB的代理类是实现MethodInterceptor的代理方法。在mybatis中通常在延迟加载的时候才会用到CGLIB的动态代理。

(十二)mybatis之动态代理的更多相关文章

  1. Mybatis mapper动态代理的原理详解

    在开始动态代理的原理讲解以前,我们先看一下集成mybatis以后dao层不使用动态代理以及使用动态代理的两种实现方式,通过对比我们自己实现dao层接口以及mybatis动态代理可以更加直观的展现出my ...

  2. Spring事务Transactional和动态代理(二)-cglib动态代理

    系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...

  3. 浅谈Java代理二:Cglib动态代理-MethodInterceptor

    浅谈Java代理二:Cglib动态代理-MethodInterceptor CGLib动态代理特点: 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生 ...

  4. aop学习总结二------使用cglib动态代理简单实现aop功能

    aop学习总结二------使用cglib动态代理简单实现aop功能 模拟业务需求: 1.拦截所有业务方法 2.判断用户是否有权限,有权限就允许用户执行业务方法,无权限不允许用户执行业务方法 (判断是 ...

  5. Java动态代理(二)——jdk动态代理

    一.什么是动态代理?代理类在程序运行时创建的代理方式被成为动态代理.动态代理的代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的.相比于静态代理, 动态代理的 ...

  6. MyBatis学习(三)MyBatis基于动态代理方式的增删改查

    1.前言 上一期讲到MyBatis-Statement版本的增删改查.可以发现.这种代码写下来冗余的地方特别多.写一套没啥.如果涉及到多表多查询的时候就容易出现问题.故.官方推荐了一种方法.即MyBa ...

  7. 初看Mybatis 源码 (二) Java动态代理类

    先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...

  8. Mybatis使用动态代理实现拦截器功能

    1.背景介绍 拦截器顾名思义为拦截某个功能的一个武器,在众多框架中均有“拦截器”.这个Plugin有什么用呢?或者说拦截器有什么用呢?可以想想拦截器是怎么实现的.Plugin用到了Java中很重要的一 ...

  9. JAVA框架 Spring 和Mybatis整合(动态代理)

    一.使用传统方式的dao的书写方式,不建议.目前采用的是动态代理的方式交给mybatis进行处理. 首先回顾下动态代理要求: 1)子配置文件的中,namespace需要是接口的全路径,id是接口的方法 ...

随机推荐

  1. css sprite讲解与使用实例

    转自:http://www.manongjc.com/article/886.html 一.什么是css sprites css sprites直译过来就是CSS精灵.通常被解释为“CSS图像拼合”或 ...

  2. CV_Assert

    转:http://blog.csdn.net/ding977921830/article/details/46376847 Checks a condition at runtime and thro ...

  3. 1.1-1.3 HBase入门

    一.HBASE入门 部分参考链接:https://www.cnblogs.com/steven-note/p/7209398.html 1.简介 HBase – Hadoop Database,是一个 ...

  4. 2-1赋值运算符 & 2-2自增自减运算符 &2-3

    2-1赋值运算符 先定义一个变量,把定义好的变量在赋值给另外一个变量.变向之间的互相赋值 2-2自增自减运算符 元素符,放在变量前和变量后的区别 先进行自增运算,再进行赋值运算.这里先进行num1的+ ...

  5. SQL2005恢复只有mdf文件的数据库

    我把原来的数据库分离后,直接把日志文件给干掉了.原来在SQL 2000里经常这么干,只用一个mdf就附加了.没想到sql2005居然不行.我试验了一圈 终于找到一个成功的方法.转载,供后来者参考. S ...

  6. ADT版本查看,This Android SDK requires Andr...ate ADT to the latest问题

    ADT版本查看 Help->About ADT This Android SDK requires Andr...ate ADT to the latest问题 这样的问题很好解决,一个升级AD ...

  7. 理解Bitcode:一种中间代码

    原文网址: http://www.cocoachina.com/ios/20150818/13078.html 今天试着用Xcode 7 beta 3在真机(iOS 8.3)上运行一下我们的工程,结果 ...

  8. 当前View的坐标相对其他View的位置坐标

    // 将rect由rect所在视图转换到目标视图view中,返回在目标视图view中的rect - (CGRect)convertRect:(CGRect)rect toView:(UIView *) ...

  9. python 基础(十五) socket编程

    SOCKET TCP协议: 有请求 有响应 称之为 tcp协议 是面向连接的协议 就是在收发数据之前 必须先要建立一个可靠的链接 三次握手 如:网站 UDP协议: 是一个非链接的协议 传输之前不需要键 ...

  10. DWR+Spring配置使用

    一.DWR介绍 DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,利用这个框架可以让AJAX开发变得很简单.利用DWR可以在客户端 ...