龙空技术网

源码系列——mybatis源码刨析总结,下

大鹅啊 147

前言:

今天各位老铁们对“vardajquery”大体比较关心,看官们都想要剖析一些“vardajquery”的相关文章。那么小编在网上搜集了一些关于“vardajquery””的相关内容,希望小伙伴们能喜欢,我们一起来了解一下吧!

接上文简答题一.1.Mybatis动态sql是做什么的?

1.动态sql就是 根据条件标签动态的拼接sql,包括判空,循环,拼接等

2.哪些动态sql?

动态sql大致有

1.: if是为了判断传入的值是否符合某种规则,比如是否不为空;

2.:where标签可以用来做动态拼接查询条件,当和if标签配合的时候,不用显示的声明类似where 1=1这种无用的条件

3.:foreach标签可以把传入的集合对象进行遍历,然后把每一项的内容作为参数传到sql语句中,

4.:include可以把大量重复的代码整理起来,当使用的时候直接include即可,减少重复代码的编写;

5.:是一个格式化标签

6.choose、when、otherwise 标签类似于 Java 中的 switch、case、default。只有一个条件生效,

<select id="findOneById"  resultType="com.lagou.pojo.User">  select <include refid="userInfo"/> from user  <where>        <if test="id != null and id != 0">          AND id = #{id}        </if>  <foreach collection="list" item="id" open="(" close=")" separator="," >    #{id}  </foreach>     <trim prefix="where" suffix="order by id" prefixOverrides="and | or" suffixOverrides=",">        <if test="name != null and name != ''">          AND name = #{name}        </if>        <if test="id != null">          AND id = #{id}        </if>      </trim>  </where></select>
3. 简述一下动态sql的执行原理?

1.在xmlMapperBuilder中 解析配置文件时

2.解析 <mapper /> 节点

3.解析 节点

    // 1.在xmlMapperBuilder中 解析配置文件时    public void parse() {            // 解析 `<mapper />` 节点            configurationElement(parser.evalNode("/mapper"));    }    //2\. 解析 `<mapper />` 节点    private void configurationElement(XNode context) {        try {            // 获得 namespace 属性            String namespace = context.getStringAttribute("namespace");            if (namespace == null || namespace.equals("")) {                throw new BuilderException("Mapper's namespace cannot be empty");            }            // 设置 namespace 属性            builderAssistant.setCurrentNamespace(namespace);            // 解析 <resultMap /> 节点们            resultMapElements(context.evalNodes("/mapper/resultMap"));            // 解析 <sql /> 节点们            sqlElement(context.evalNodes("/mapper/sql"));            // 解析 <select /> <insert /> <update /> <delete /> 节点们            buildStatementFromContext(context.evalNodes("select|insert|update|delete"));        } catch (Exception e) {            throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);        }    }  // 3.解析 <select /> <insert /> <update /> <delete /> 节点们    private void buildStatementFromContext(List<XNode> list) {        if (configuration.getDatabaseId() != null) {            buildStatementFromContext(list, configuration.getDatabaseId());        }        buildStatementFromContext(list, null);        // 上面两块代码,可以简写成 buildStatementFromContext(list, configuration.getDatabaseId());    }    private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {        //遍历 <select /> <insert /> <update /> <delete /> 节点们        for (XNode context : list) {            // 创建 XMLStatementBuilder 对象,执行解析            final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);            try {                statementParser.parseStatementNode();            } catch (IncompleteElementException e) {                // 解析失败,添加到 configuration 中                configuration.addIncompleteStatement(statementParser);            }        }    }

4.XMLStatementBuilder对象

public class XMLStatementBuilder extends BaseBuilder {   /**     * 执行解析     */    public void parseStatementNode() {        // 获得 id 属性,编号。        String id = context.getStringAttribute("id");        // 获得 databaseId , 判断 databaseId 是否匹配        String databaseId = context.getStringAttribute("databaseId");        if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {            return;        }        // 获得各种属性        Integer fetchSize = context.getIntAttribute("fetchSize");        Integer timeout = context.getIntAttribute("timeout");        String parameterMap = context.getStringAttribute("parameterMap");        String parameterType = context.getStringAttribute("parameterType");        Class<?> parameterTypeClass = resolveClass(parameterType);        String resultMap = context.getStringAttribute("resultMap");        String resultType = context.getStringAttribute("resultType");        String lang = context.getStringAttribute("lang");        // 获得 lang 对应的 LanguageDriver 对象        LanguageDriver langDriver = getLanguageDriver(lang);        // 获得 resultType 对应的类        Class<?> resultTypeClass = resolveClass(resultType);        // 获得 resultSet 对应的枚举值        String resultSetType = context.getStringAttribute("resultSetType");        ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);        // 获得 statementType 对应的枚举值        StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));}

5.LanguageDriver的实现类XMLLanguageDriver的方法解析方法createSqlSource

public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {        // 创建 XMLScriptBuilder 对象,执行解析        XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);        return builder.parseScriptNode();    }

6.解析

XMLScriptBuilder标签解析/** * XML 动态语句( SQL )构建器,负责将 SQL 解析成 SqlSource 对象 * * @author Clinton Begin */public class XMLScriptBuilder extends BaseBuilder {    /**     * 当前 SQL 的 XNode 对象     */    private final XNode context;    /**     * 是否为动态 SQL     */    private boolean isDynamic;    /**     * SQL 方法类型     */    private final Class<?> parameterType;    /**     * NodeNodeHandler 的映射     */    private final Map<String, NodeHandler> nodeHandlerMap = new HashMap<>();    public XMLScriptBuilder(Configuration configuration, XNode context) {        this(configuration, context, null);    }    public XMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) {        super(configuration);        this.context = context;        this.parameterType = parameterType;        // 初始化 nodeHandlerMap 属性        initNodeHandlerMap();    }    /**     * 初始化 {@link #nodeHandlerMap} 属性     */    private void initNodeHandlerMap() {        nodeHandlerMap.put("trim", new TrimHandler());        nodeHandlerMap.put("where", new WhereHandler());        nodeHandlerMap.put("set", new SetHandler());        nodeHandlerMap.put("foreach", new ForEachHandler());        nodeHandlerMap.put("if", new IfHandler());        nodeHandlerMap.put("choose", new ChooseHandler());        nodeHandlerMap.put("when", new IfHandler());        nodeHandlerMap.put("otherwise", new OtherwiseHandler());        nodeHandlerMap.put("bind", new BindHandler());    }    /**     * 负责将 SQL 解析成 SqlSource 对象     *     * @return SqlSource 对象     */    public SqlSource parseScriptNode() {        // 解析 SQL        MixedSqlNode rootSqlNode = parseDynamicTags(context);        // 创建 SqlSource 对象        SqlSource sqlSource;        if (isDynamic) {            sqlSource = new DynamicSqlSource(configuration, rootSqlNode);        } else {            sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);        }        return sqlSource;    }    /**     * 解析 SQL 成 MixedSqlNode 对象     *     * @param node XNode 节点     * @return MixedSqlNode     */    protected MixedSqlNode parseDynamicTags(XNode node) {        // 创建 SqlNode 数组        List<SqlNode> contents = new ArrayList<>();        // 遍历 SQL 节点的所有子节点        NodeList children = node.getNode().getChildNodes();        for (int i = 0; i < children.getLength(); i++) {            // 当前子节点            XNode child = node.newXNode(children.item(i));            // 如果类型是 Node.CDATA_SECTION_NODE 或者 Node.TEXT_NODE 时            if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {                // 获得内容                String data = child.getStringBody("");                // 创建 TextSqlNode 对象                TextSqlNode textSqlNode = new TextSqlNode(data);                // 如果是动态的 TextSqlNode 对象                if (textSqlNode.isDynamic()) {                    // 添加到 contents 中                    contents.add(textSqlNode);                    // 标记为动态 SQL                    isDynamic = true;                // 如果是非动态的 TextSqlNode 对象                } else {                    // 创建 StaticTextSqlNode 添加到 contents 中                    contents.add(new StaticTextSqlNode(data));                }            // 如果类型是 Node.ELEMENT_NODE            } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628                // 根据子节点的标签,获得对应的 NodeHandler 对象                String nodeName = child.getNode().getNodeName();                NodeHandler handler = nodeHandlerMap.get(nodeName);                if (handler == null) { // 获得不到,说明是未知的标签,抛出 BuilderException 异常                    throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");                }                // 执行 NodeHandler 处理                handler.handleNode(child, contents);                // 标记为动态 SQL                isDynamic = true;            }        }        // 创建 MixedSqlNode 对象        return new MixedSqlNode(contents);    }    /**     * Node 处理器接口     */    private interface NodeHandler {        /**         * 处理 Node         *         * @param nodeToHandle 要处理的 XNode 节点         * @param targetContents 目标的 SqlNode 数组。实际上,被处理的 XNode 节点会创建成对应的 SqlNode 对象,添加到 targetContents 中         */        void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);    }    /**     * `<bind />` 标签的处理器     *     * @see VarDeclSqlNode     */    private class BindHandler implements NodeHandler {        public BindHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析 name、value 属性            final String name = nodeToHandle.getStringAttribute("name");            final String expression = nodeToHandle.getStringAttribute("value");            // 创建 VarDeclSqlNode 对象            final VarDeclSqlNode node = new VarDeclSqlNode(name, expression);            // 添加到 targetContents 中            targetContents.add(node);        }    }    /**     * `<trim />` 标签的处理器     *     * @see TrimSqlNode     */    private class TrimHandler implements NodeHandler {        public TrimHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析内部的 SQL 节点,成 MixedSqlNode 对象            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);            // 获得 prefix、prefixOverrides、"suffix"、suffixOverrides 属性            String prefix = nodeToHandle.getStringAttribute("prefix");            String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");            String suffix = nodeToHandle.getStringAttribute("suffix");            String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");            // 创建 TrimSqlNode 对象            TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);            // 添加到 targetContents 中            targetContents.add(trim);        }    }    /**     * `<where />` 标签的处理器     *     * @see WhereSqlNode     */    private class WhereHandler implements NodeHandler {        public WhereHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析内部的 SQL 节点,成 MixedSqlNode 对象            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);            // 创建 WhereSqlNode 对象            WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);            // 添加到 targetContents 中            targetContents.add(where);        }    }    /**     * `<set />` 标签的处理器     *     * @see SetSqlNode     */    private class SetHandler implements NodeHandler {        public SetHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析内部的 SQL 节点,成 MixedSqlNode 对象            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);            // 创建 SetSqlNode 对象            SetSqlNode set = new SetSqlNode(configuration, mixedSqlNode);            // 添加到 targetContents 中            targetContents.add(set);        }    }    /**     * `<foreach />` 标签的处理器     *     * @see ForEachSqlNode     */    private class ForEachHandler implements NodeHandler {        public ForEachHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析内部的 SQL 节点,成 MixedSqlNode 对象            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);            // 获得 collection、item、index、open、close、separator 属性            String collection = nodeToHandle.getStringAttribute("collection");            String item = nodeToHandle.getStringAttribute("item");            String index = nodeToHandle.getStringAttribute("index");            String open = nodeToHandle.getStringAttribute("open");            String close = nodeToHandle.getStringAttribute("close");            String separator = nodeToHandle.getStringAttribute("separator");            // 创建 ForEachSqlNode 对象            ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, index, item, open, close, separator);            // 添加到 targetContents 中            targetContents.add(forEachSqlNode);        }    }    /**     * `<if />` 标签的处理器     *     * @see IfSqlNode     */    private class IfHandler implements NodeHandler {        public IfHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析内部的 SQL 节点,成 MixedSqlNode 对象            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);            // 获得 test 属性            String test = nodeToHandle.getStringAttribute("test");            // 创建 IfSqlNode 对象            IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);            // 添加到 targetContents 中            targetContents.add(ifSqlNode);        }    }    /**     * `<otherwise />` 标签的处理器     */    private class OtherwiseHandler implements NodeHandler {        public OtherwiseHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            // 解析内部的 SQL 节点,成 MixedSqlNode 对象            MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);            // 添加到 targetContents 中            targetContents.add(mixedSqlNode);        }    }    /**     * `<choose />` 标签的处理器     *     * @see ChooseSqlNode     */    private class ChooseHandler implements NodeHandler {        public ChooseHandler() {            // Prevent Synthetic Access        }        @Override        public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {            List<SqlNode> whenSqlNodes = new ArrayList<>();            List<SqlNode> otherwiseSqlNodes = new ArrayList<>();            // 解析 `<when />` 和 `<otherwise />` 的节点们            handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);            // 获得 `<otherwise />` 的节点            SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);            // 创建 ChooseSqlNode 对象            ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode);            // 添加到 targetContents 中            targetContents.add(chooseSqlNode);        }        private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes, List<SqlNode> defaultSqlNodes) {            List<XNode> children = chooseSqlNode.getChildren();            for (XNode child : children) {                String nodeName = child.getNode().getNodeName();                NodeHandler handler = nodeHandlerMap.get(nodeName);                if (handler instanceof IfHandler) { // 处理 `<when />` 标签的情况                    handler.handleNode(child, ifSqlNodes);                } else if (handler instanceof OtherwiseHandler) { // 处理 `<otherwise />` 标签的情况                    handler.handleNode(child, defaultSqlNodes);                }            }        }        // 至多允许有一个 SqlNode 节点        private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {            SqlNode defaultSqlNode = null;            if (defaultSqlNodes.size() == 1) {                defaultSqlNode = defaultSqlNodes.get(0);            } else if (defaultSqlNodes.size() > 1) {                throw new BuilderException("Too many default (otherwise) elements in choose statement.");            }            return defaultSqlNode;        }    }}
二、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?

延迟加载主要通过动态代理实现,通过代理拦截指定方法没执行数据加载。

javassisProxyFactory会创建一个User代理对象,所有调用User对象方法,都会经过EnhancedResultObjectProxyImpl.invoke()方法的拦截。、

于是当调用User.getOrder()方法时,才真正去执行查询Order的动作并把结果赋值

<settings>    <!-- 开启全局配置的懒加载 -->    <setting name="lazyLoadingEnabled" value="true"/>    <!-- 关闭积极加载 -->    <setting name="aggressiveLazyLoading" value="false"/>    </settings><mapper namespace="demo.cyj.dao.TeacherDao">    <select id="findTeacherByTname" resultType="Teacher" resultMap="getTeacher">        select t.t_id t_id,t.t_name t_name from teacher t where t.t_name =#{name}    </select>    //延迟加载    <resultMap type="Teacher" id="getTeacher">        <collection ofType="Student" property="stuList" fetchType="lazy" column="t_name" select="findTeacherByTnameLazy" />    </resultMap>    <select id="findTeacherByTnameLazy" resultType="Student" >        select s.id id,s.stu_name stu_name,s.stu_age age,s.t_id t_id from student s left join teacher t on t.t_id = s.t_id where t.t_name=#{name}     </select>       </mapper>
2.延迟加载的类
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());    if (closed) {      throw new ExecutorException("Executor was closed.");    }    if (queryStack == 0 && ms.isFlushCacheRequired()) {      clearLocalCache();    }    List<E> list;    try {      queryStack++;      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;      if (list != null) {        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);      } else {        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);      }    } finally {      queryStack--;    }    if (queryStack == 0) {      for (DeferredLoad deferredLoad : deferredLoads) {        deferredLoad.load();      }      // issue #601      deferredLoads.clear();      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {        // issue #482        clearLocalCache();      }    }    return list;  }

延迟加载的类

  private static class DeferredLoad {    private final MetaObject resultObject;    private final String property;    private final Class<?> targetType;    private final CacheKey key;    private final PerpetualCache localCache;    private final ObjectFactory objectFactory;    private final ResultExtractor resultExtractor;    // issue #781    public DeferredLoad(MetaObject resultObject,                        String property,                        CacheKey key,                        PerpetualCache localCache,                        Configuration configuration,                        Class<?> targetType) {      this.resultObject = resultObject;      this.property = property;      this.key = key;      this.localCache = localCache;      this.objectFactory = configuration.getObjectFactory();      this.resultExtractor = new ResultExtractor(configuration, objectFactory);      this.targetType = targetType;    }    public boolean canLoad() {      return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;    }    public void load() {      @SuppressWarnings( "unchecked" )      // we suppose we get back a List      List<Object> list = (List<Object>) localCache.getObject(key);      Object value = resultExtractor.extractObjectFromList(list, targetType);      resultObject.setValue(property, value);    }  }
1.Mybatis都有哪些Executor执行器

BaseExecutor 简单执行器,是 MyBatis 中默认使用的执行器,每执行一次 update 或 select,就开启一个 Statement 对象,用完就直接关闭 Statement 对象(可以是 Statement 或者是 PreparedStatment 对象)

BatchExecutor 批处理执行器,用于将多个SQL一次性输出到数据库

simpleExexutor 每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。

ReuseExecutor 执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。

cachingExecutor 更新缓存2.它们之间的区别是什么?

作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

默认是SimplExcutor,需要配置在创建SqlSession对象的时候指定执行器的类型即可。

1.一级缓存

Mybatis的一级缓存是指SqlSession级别的,作用域是SqlSession,Mybatis默认开启一级缓存,在同一个SqlSession中,相同的Sql查询的时候,第一次查询的时候,就会从缓存中取,如果发现没有数据,那么就从数据库查询出来,并且缓存到HashMap中,如果下次还是相同的查询,就直接从缓存中查询,就不在去查询数据库,对应的就不在去执行SQL语句。当查询到的数据,进行增删改的操作的时候,缓存将会失效

2. 二级缓存

MyBatis的二级缓存是基于Mapper级别的,也就是说多个SqlSession去使用某个Mapper的查询语句时,得到的缓存数据是可共用的。第一次调用mapper下的sql 的时候去查询信息,查询到的信息会存放到该mapper对应的二级缓存区域,第二次调用namespace下的mapper映射文件中,相同的SQL去查询,回去对应的二级缓存内取结果。二级缓存开启后,查询就会走二级缓存,没查到直接查库。MyBatis默认不开启二级缓存

简述Mybatis的插件运行原理,以及如何编写一个插件?

插件运行原理

实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可

实现Interceptor接口 在定义StatementHandler处理器的时候拦截prepare方法也就是准备的方法

//1.configuration.newStatementHandler()获取对象  public int doUpdate(MappedStatement ms, Object parameter) throws  SQLException {    Statement stmt = null;      Configuration configuration = ms.getConfiguration();      //定义StatementHandler处理器      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);      //初始化      stmt = prepareStatement(handler, ms.getStatementLog());      //执行      return handler.update(stmt);  }  //2.获取执行sql的StatementHandler组件    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);    //代理对象    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);    return statementHandler;  }  //3.  public class InterceptorChain {  private final List<Interceptor> interceptors = new ArrayList<Interceptor>();  public Object pluginAll(Object target) {    for (Interceptor interceptor : interceptors) {      target = interceptor.plugin(target);    }    return target;  }  }
如何编写插件

实现Interceptor接口,Interceptors注解表明要拦截的类,方法,参数

package com.lagou.plugin;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.plugin.*;import java.sql.Connection;import java.util.Properties;    @Intercepts({            @Signature(type= StatementHandler.class,//拦截那个接口                    method = "prepare",//这个接口内的那个方法名                    args={Connection.class,Integer.class})//拦截方法的入参,如果方法重载,通过方法名跟参数确定唯一    })    public class MyPlugin implements Interceptor {        //这里是每次执行操作的时候,都会进行这个方法        @Override        public Object intercept(Invocation invocation) throws Throwable {            System.out.println("增强了");            return invocation.proceed();        }        //把这个拦截器生成一个代理放到拦截器链中        @Override        public Object plugin(Object target) {            System.out.println("将要包装的目标对象"+target);            return Plugin.wrap(target,this);        }        //插件初始化时候调用,只调用一次  获取配置文件的属性        @Override        public void setProperties(Properties properties) {            System.out.println("获取配置文件的属性"+properties);        }    }tementHandler);    return statementHandler;  }  //3.  public class InterceptorChain {  private final List<Interceptor> interceptors = new ArrayList<Interceptor>();  public Object pluginAll(Object target) {    for (Interceptor interceptor : interceptors) {      target = interceptor.plugin(target);    }    return target;  }  }
如何编写插件

实现Interceptor接口,Interceptors注解表明要拦截的类,方法,参数

package com.lagou.plugin;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.plugin.*;import java.sql.Connection;import java.util.Properties;    @Intercepts({            @Signature(type= StatementHandler.class,//拦截那个接口                    method = "prepare",//这个接口内的那个方法名                    args={Connection.class,Integer.class})//拦截方法的入参,如果方法重载,通过方法名跟参数确定唯一    })    public class MyPlugin implements Interceptor {        //这里是每次执行操作的时候,都会进行这个方法        @Override        public Object intercept(Invocation invocation) throws Throwable {            System.out.println("增强了");            return invocation.proceed();        }        //把这个拦截器生成一个代理放到拦截器链中        @Override        public Object plugin(Object target) {            System.out.println("将要包装的目标对象"+target);            return Plugin.wrap(target,this);        }        //插件初始化时候调用,只调用一次  获取配置文件的属性        @Override        public void setProperties(Properties properties) {            System.out.println("获取配置文件的属性"+properties);        }    }
结尾

上下两部分已经更完了,本文到这里就结束了,感谢看到最后的朋友,都看到最后了,点个赞再走啊,如有不对之处还请多多指正。

标签: #vardajquery