Mybatis源码解析(七)

开课吧开课吧锤锤2021-03-03 11:13

    Java是一门全球范围内使用最广泛的,面向对象的编程语言。Java语言具有功能强大和简单易用两个特征,它作为面向对象编程语言系列的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。

java

    六、Mybatis插件开发

    6.1四大对象

    Mybatis四大对象指的是:Executor、StatementHandler、ParamaterHandler、ResultSetHandler。Mybatis允许我们在四大对象执行的过程中对其指定方法进行拦截,这样就可以很方便了进行功能的增强,这个功能跟Spring的切面编程非常类似。上文我们都有提到过,在四大对象创建的时候,都进行了插件增强,下面我们就来讲解一下其实现原理。

    例如我们希望在sql语句之前前后进行时间打印,计算出sql执行的时间。此功能我们就可以拦截StatementHandler。这里我们需要时间Mybatis提供的Intercaptor接口。

    packagecom.cl.mybatis.learn.intercaptor;

    /**

    *@Author:chengli

    *@Date:2018/11/2417:37

    */

    /**该注解签名告诉此拦截器拦截四大对象中的哪个对象的哪个方法,以及方法的签名信息*/

    @Intercepts({

    @Signature(type=StatementHandler.class,method="query",args={Statement.class,ResultHandler.class})

    })

    publicclassSqlLogPluginimplementsInterceptor{

    @Override

    publicObjectintercept(Invocationinvocation)throwsThrowable{

    longbegin=System.currentTimeMillis();

    try{

    returninvocation.proceed();

    }finally{

    longtime=System.currentTimeMillis()-begin;

    System.out.println("sql运行了:"+time+"ms");

    }

    }

    @Override

    publicObjectplugin(Objecttarget){

    returnPlugin.wrap(target,this);

    }

    @Override

    publicvoidsetProperties(Propertiesproperties){

    }

    }

    接下来我们需要在mybatis-config.xml配置该拦截器:

    <plugins>

    <plugininterceptor="com.cl.mybatis.learn.intercaptor.SqlLogPlugin">

    <propertyname="参数1"value="root"/>

    <propertyname="参数2"value="123456"/>

    </plugin>

    </plugins>

    此时,拦截器的配置就完成了,运行结果如下:

    DEBUG11-2417:51:34,877==>Preparing:select*fromuserwhereid=?(BaseJdbcLogger.java:139)

    DEBUG11-2417:51:34,940==>Parameters:1(Integer)(BaseJdbcLogger.java:139)

    DEBUG11-2417:51:34,990<==Total:1(BaseJdbcLogger.java:139)

    sql运行了:51ms

    User{id=1,name='张三',age=42,sex=0}

    6.2插件原理探究

    从代码我们可以看出:

    publicObjectplugin(Objecttarget){

    returnPlugin.wrap(target,this);

    }

    该代码是对目标对象的包装,实际运行的时候,是使用的包装之后的类,运行的时候执行的是intercept方法。那么现在我们来看下它是怎么进行包装的:

    publicstaticObjectwrap(Objecttarget,Interceptorinterceptor){

    Map<Class<?>,Set<Method>>signatureMap=getSignatureMap(interceptor);

    Class<?>type=target.getClass();

    Class<?>[]interfaces=getAllInterfaces(type,signatureMap);

    if(interfaces.length>0){

    returnProxy.newProxyInstance(

    type.getClassLoader(),

    interfaces,

    newPlugin(target,interceptor,signatureMap));

    }

    returntarget;

    }

    而Plugin类实现了InvocationHanlder接口:

    publicclassPluginimplementsInvocationHandler{

    ……

    }

    显然这里使用的就是JDK的动态代理,对目标对象包装了一层。

    假如一个对象被多个拦截器进行了多次包装,那么后包装的在最外层会先执行。

    以上内容由开课吧老师左撇子小哥哥提供,更多Java教程尽在开课吧广场Java教程频道。

有用
分享