Mybatis——plugIn插件

简介

mybatis作为一个优秀的ORM框架,其框架本身具有很高的灵活性,有四大组件提供了简单易用的拓展机制。Mybatis支持用插件对这四大核心组件进行拦截,对核心功能进行增强,增强功能的实现就是借助底层的动态代理功能实现的。
Mybatis允许拦截的方法:
1、执行器Executor (update、query、commit、rollback等方法);
2、SQL语法构建器StatementHandler (prepare、parameterize、batch、updates query等方法);
3、参数处理器ParameterHandler (getParameterObject、setParameters方法);
4、结果集处理器ResultSetHandler (handleResultSets、handleOutputParameters等方法);

原理

mybatis是如何进行拦截的呢?我们以parameterHandler为例:

public ParameterHandler newParameterHandler(MappedStatement mappedStatement,
Object object, BoundSql sql, InterceptorChain interceptorChain){
ParameterHandler parameterHandler =
mappedStatement.getLang().createParameterHandler(mappedStatement,object,sql);
parameterHandler = (ParameterHandler)
interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}

从代码里面我们能看出来,新建parameterHandler对象不是直接去创建返回的对象,而是使用interceptorChain.pluginAll方法返回的对象。
interceptorChain保存了所有的interceptor拦截器对象,是在mybatis初始化的时候创建的,调用连接器链中的拦截器依次对目标对象进行增强,interceptor.plugin(target)中的target可以理解为四大组件对象,返回的是增强过后的对象。
如果我们想要拦截Executor的query方法,那么我们可以这样定义插件

@Intercepts({
@Signature(
type = Executor.class,
method = "query",
args=
{MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class}
)
})
public class ExeunplePlugin implements Interceptor {
//省略逻辑
}

同时我们还需要在config.xml中进行配置

<plugins>
<plugin interceptor="com.lagou.plugin.ExamplePlugin">
</plugin>
</plugins>

这样mybatis在启动的时候就会去加载插件,并且保存插件实例到interceptorChian中,等启动完成后,我们执行sql的时候,需要先使用defaultSessionFactory创建sqlsession,在创建sqlsession的时候就回去创建executor对象,这个时候就会创建动态代理对象,所以我们就能控制在原本的方法上执行增强方法

自定义插件

1、创建自定义插件

@Intercepts(
        @Signature(type = StatementHandler.class,
                method="prepare",
                args={Connection.class,Integer.class}
        )
)
public class mybatis_plugin implements Interceptor {
    // 对方法进行增强
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("mybatis增强-------------");
        Object proceed = invocation.proceed();// 使用原来的方法
        return proceed;
    }
    // 将拦截器存入拦截链中
    @Override
    public Object plugin(Object o) {
        Object wrap = Plugin.wrap(o, this);
        return wrap;
    }
    // 配置参数
    @Override
    public void setProperties(Properties properties) {
    System.out.println("properties: "+properties);
    }
}

2、sqlconnection.xml

 <plugin interceptor="plugin.mybatis_plugin"></plugin>

3、mapper接口和mapper.xml
这里写正常的mapper接口和mapper.xml就可以了,这里就不贴代码了
4、客户端调用

    @Test
    public void pluginQuery(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.queryList();
        System.out.println("查询数据成功!");
    }

5、执行结果
在这里插入图片描述

源码分析

执行插件逻辑
plugin实现了 InvocationHandler接口,所以它的invoke方法会拦截所有的方法调用, 并且会对拦截的方法进行检测,判断是否执行插件方法还是执行原来的方法
在这里插入图片描述
首先invoke方法判断被拦截的方法是否在被@Signature注解中的方法,如果是就执行插件逻辑
插件逻辑封装在intercept中,该
方法的参数类型为Invocationo Invocation主要用于存储目标类,方法以及方法参数列表
在这里插入图片描述

pageHelper分页插件

Mybatis可以使用第三方分页插件,对查询的数据进行分页查询
我们使用pageHelper举例
1、导入pageHelper依赖

<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>3.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>

2、sqlconnection.xml

        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
        </plugin>

3、客户端测试

    @Test
    public void pageHelperQuery(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        PageHelper.startPage(1, 20);
        List<User> users = mapper.queryList();
        PageInfo<User> userPageInfo = new PageInfo<>(users);
        System.out.println("条数:"+userPageInfo.getSize());
    }

4、执行结果
在这里插入图片描述

通用Mapper

通用Mapper是为了解决对单表的增删改查,开发人员不需要写sql也不需要写对应的接口,只要写好实体类,就能支持对应的增删改查方法
1、引入依赖

<dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>3.1.2</version>
        </dependency>

2、sqlconnection.xml

 <plugin interceptor="tk.mybatis.mapper.mapperhelper.MapperInterceptor">
            <!-- 通用Mapper接口,多个通用接口用逗号隔开 -->
            <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
        </plugin>

3、实体类设置主键

@Table(name="user")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    private String name;
    // 省略get set方法
    }

4、定义通用mapper

import mode.User;
import tk.mybatis.mapper.common.Mapper;

public interface commonMapper extends Mapper<User> {
}

5、测试

    @Test
    public void commonMybatisMapper(){
        // 1. 使用通过mapper进行查询
        SqlSession sqlSession = sqlSessionFactory.openSession();
        commonMapper mapper = sqlSession.getMapper(commonMapper.class);
        User user = new User();
        user.setId(1);
        User selectOneUser = mapper.selectOne(user);
        System.out.println(selectOneUser);

        // 2.使用模板
        Example example = new Example(User.class);
        example.createCriteria().andEqualTo("id",1);
        List<User> users = mapper.selectByExample(example);
        users.forEach(System.out::println);
        AtomicReference<Map<String,Boolean>> objectAtomicReference = new AtomicReference<>();
        Map<String, Boolean> stringBooleanMap = objectAtomicReference.get();
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值