最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

探究MyBatis插件原理以及自定義插件實現(xiàn)

 更新時間:2023年07月25日 08:39:50   作者:共飲一杯無  
這篇文章主要介紹了探究MyBatis插件原理以及自定義插件實現(xiàn),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

插件簡介

?般情況下,開源框架都會提供插件或其他形式的拓展點,供開發(fā)者??拓展。這樣的好處是顯?易?的,?是增加了框架的靈活性。?是開發(fā)者可以結(jié)合實際需求,對框架進(jìn)?拓展,使其能夠更好的?作。以MyBatis為例,我們可基于MyBati s插件機(jī)制實現(xiàn)分?、分表,監(jiān)控等功能。由于插件和業(yè)務(wù)?關(guān),業(yè)務(wù)也?法感知插件的存在。因此可以?感植?插件,在?形中增強(qiáng)功能。

Mybatis插件介紹

Mybati s作為?個應(yīng)??泛的優(yōu)秀的ORM開源框架,這個框架具有強(qiáng)?的靈活性,在四?組件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)處提供了簡單易?的插 件擴(kuò)展機(jī)制。Mybatis對持久層的操作就是借助于四?核?對象。MyBatis?持?插件對四?核?對象進(jìn)?攔截,對mybatis來說插件就是攔截器,?來增強(qiáng)核?對象的功能,增強(qiáng)功能本質(zhì)上是借助于底層的 動態(tài)代理實現(xiàn)的,換句話說,MyBatis中的四?對象都是代理對象。
MyBatis所允許攔截的?法如下:

  • 執(zhí)?器Executor (update、query、commit、rollback等?法);
  • SQL語法構(gòu)建器StatementHandler(prepare、parameterize、batch、updates query等? 法);
  • 參數(shù)處理器ParameterHandler (getParameterObject、setParameters?法);
  • 結(jié)果集處理器ResultSetHandler (handleResultSets、handleOutputParameters等?法);

Mybatis插件原理

在四?對象創(chuàng)建的時候

  1. 每個創(chuàng)建出來的對象不是直接返回的,?是interceptorChain.pluginAll(parameterHandler);
  2. 獲取到所有的Interceptor (攔截器)(插件需要實現(xiàn)的接?);調(diào)? interceptor.plugin(target);返回 target 包裝后的對象
  3. 插件機(jī)制,我們可以使?插件為?標(biāo)對象創(chuàng)建?個代理對象;AOP (?向切?)我們的插件可以為四?對象創(chuàng)建出代理對象,代理對象就可以攔截到四?對象的每?個執(zhí)?;

攔截

插件具體是如何攔截并附加額外的功能的呢?以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;
}

interceptorChain保存了所有的攔截器(interceptors),是mybatis初始化的時候創(chuàng)建的。調(diào)?攔截器鏈中的攔截器依次的對?標(biāo)進(jìn)?攔截或增強(qiáng)。interceptor.plugin(target)中的target就可以理解為mybatis中的四?對象。返回的target是被重重代理后的對象
如果我們想要攔截Executor的query?法,那么可以這樣定義插件:

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

除此之外,我們還需將插件配置到sqlMapConfig.xml中。

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

這樣MyBatis在啟動時可以加載插件,并保存插件實例到相關(guān)對象(InterceptorChain,攔截器鏈) 中。待準(zhǔn)備?作做完后,MyBatis處于就緒狀態(tài)。我們在執(zhí)?SQL時,需要先通過DefaultSqlSessionFactory創(chuàng)建 SqlSession。Executor 實例會在創(chuàng)建 SqlSession 的過程中被創(chuàng)建, Executor實例創(chuàng)建完畢后,MyBatis會通過JDK動態(tài)代理為實例?成代理類。這樣,插件邏輯即可在 Executor相關(guān)?法被調(diào)?前執(zhí)?。

以上就是MyBatis插件機(jī)制的基本原理。

?定義插件

插件接口

Mybatis 插件接?-Interceptor

  • Intercept?法,插件的核??法
  • plugin?法,?成target的代理對象
  • setProperties?法,傳遞插件所需參數(shù)

?定義插件

設(shè)計實現(xiàn)?個?定義插件

@Intercepts({//注意看這個?花括號,也就這說這?可以定義多個@Signature對多個地?攔截,都?這個攔截器
    @Signature(type = StatementHandler.class , //這是指攔截哪個接?
    method = "prepare", //這個接?內(nèi)的哪個?法名,不要拼錯了
    args = { Connection.class, Integer .class}),  //這是攔截的?法的?參,按順序?qū)懙竭@,不要多也不要少,如果?法重載,可是要通過?法名和?參來確定唯?的
})
public class MyPlugin implements Interceptor {
    // //這?是每次執(zhí)?操作的時候,都會進(jìn)?這個攔截器的?法內(nèi)
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //增強(qiáng)邏輯
        System.out.println("對?法進(jìn)?了增強(qiáng)....");
        return invocation.proceed(); //執(zhí)?原?法
    }
    /**
    * //主要是為了把這個攔截器?成?個代理放到攔截器鏈中
    * ^Description包裝?標(biāo)對象 為?標(biāo)對象創(chuàng)建代理對象
    * @Param target為要攔截的對象
    * @Return代理對象
    */
    @Override
    public Object plugin(Object target) {
        System.out.println("將要包裝的?標(biāo)對象:"+target);
        return Plugin.wrap(target,this);
    }
    /**獲取配置?件的屬性**/
    //插件初始化的時候調(diào)?,也只調(diào)??次,插件配置的屬性從這?設(shè)置進(jìn)來
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的初始化參數(shù):"+properties );
    }
}

sqlMapConfig.xml

mapper接?

mapper.xml

<mapper namespace="com.zjq.mapper.UserMapper">
    <!--sql語句抽取-->
    <sql id="selectUser">
      select * from user
    </sql>
    <select id="findByCondition" parameterType="user" resultType="user">
        <include refid="selectUser"></include>
        <where>
            <if test="id!=0">
                and id=#{id}
            </if>
            <if test="username!=null and username!=''">
                and username=#{username}
            </if>
            <if test="password!=null and password!=''">
                and password=#{password}
            </if>
        </where>
    </select>
  </mapper>

測試類

public class PluginTest {
    @Test
    public void test() throws IOException {
        InputStream resourceAsStream =
        Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User condition = new User();
        //condition.setId(1);
        condition.setUsername("zjq");
        List<User> byPaging = userMapper.findByCondition(condition);
        for (User user : byPaging) {
            System.out.println(user);
        }
    }
}

源碼分析

執(zhí)?插件邏輯Plugin實現(xiàn)了 InvocationHandler接?,因此它的invoke?法會攔截所有的?法調(diào)?。invoke?法會 對所攔截的?法進(jìn)?檢測,以決定是否執(zhí)?插件邏輯。該?法的邏輯如下:

// -Plugin
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
    try {
    /*
    *獲取被攔截?法列表,?如:
    * signatureMap.get(Executor.class), 可能返回 [query, update,
    commit]
    */
    Set<Method> methods = signatureMap.get(method.getDeclaringClass());
    //檢測?法列表是否包含被攔截的?法
    if (methods != null && methods.contains(method)) {
        //執(zhí)?插件邏輯
        return interceptor.intercept(new Invocation(target, method,
        args));
        //執(zhí)?被攔截的?法
        return method.invoke(target, args);
        } catch(Exception e){
    }
}

invoke?法的代碼?較少,邏輯不難理解。?先,invoke?法會檢測被攔截?法是否配置在插件的@Signature注解中,若是,則執(zhí)?插件邏輯,否則執(zhí)?被攔截?法。插件邏輯封裝在intercept中,該?法的參數(shù)類型為Invocationo Invocation主要?于存儲?標(biāo)類,?法以及?法參數(shù)列表。下?簡單看?下該類的定義

public class Invocation {
    private final Object target;
    private final Method method;
    private final Object[] args;
    public Invocation(Object targetf Method method, Object[] args) {
    this.target = target;
    this.method = method;
    //省略部分代碼
    public Object proceed() throws InvocationTargetException,
    IllegalAccessException { //調(diào)?被攔截的?法

關(guān)于插件的執(zhí)?邏輯就分析結(jié)束。

pageHelper分頁插件

MyBatis可以使?第三?的插件來對功能進(jìn)?擴(kuò)展,分?助?PageHelper是將分?的復(fù)雜操作進(jìn)?封裝,使?簡單的?式即可獲得分?的相關(guān)數(shù)據(jù)
開發(fā)步驟:

  • 導(dǎo)?通?PageHelper坐標(biāo)
<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>
  • 在mybatis核?配置?件中配置PageHelper插件
<!--注意:分?助?的插件 配置在通?館mapper之前*-->*
<plugin interceptor="com.github.pagehelper.PageHelper">
  <!—指定?? —>
  <property name="dialect" value="mysql"/>
</plugin>
  • 測試分?代碼實現(xiàn)
@Test
public void testPageHelper() {
    //設(shè)置分?參數(shù)
    PageHelper.startPage(1, 2);
    User condition = new User();
    //condition.setId(1);
    condition.setUsername("zjq");
    List<User> select = userMapper.findByCondition(condition);
    for (User user : select) {
        System.out.println(user);
    }
}

獲得分?相關(guān)的其他參數(shù)

//其他分?的數(shù)據(jù)
PageInfo<User> pageInfo = new PageInfo<User>(select);
System.out.println("總條數(shù):"+pageInfo.getTotal());
System.out.println("總?數(shù):"+pageInfo. getPages ());
System.out.println("當(dāng)前?:"+pageInfo. getPageNum());
System.out.println("每?顯示?度:"+pageInfo.getPageSize());
System.out.println("是否第??:"+pageInfo.isIsFirstPage());
System.out.println("是否最后??:"+pageInfo.isIsLastPage());

通? mapper

什么是通?Mapper

通?Mapper就是為了解決單表增刪改查,基于Mybatis的插件機(jī)制。開發(fā)?員不需要編寫SQL,不需要在DAO中增加?法,只要寫好實體類,就能?持相應(yīng)的增刪改查?法

如何使?

  1. ?先在maven項?,在pom.xml中引?mapper的依賴
<dependency>
  <groupId>tk.mybatis</groupId>
  <artifactId>mapper</artifactId>
  <version>3.1.2</version>
</dependency>
  • Mybatis配置?件中完成配置
<plugins>
  <!--分?插件:如果有分?插件,要排在通?mapper之前-->
  <plugin interceptor="com.github.pagehelper.PageHelper">
    <property name="dialect" value="mysql"/>
  </plugin>
  <plugin interceptor="tk.mybatis.mapper.mapperhelper.MapperInterceptor">
    <!-- 通?Mapper接?,多個通?接??逗號隔開 -->
    <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
  </plugin>
</plugins>
  • 實體類設(shè)置主鍵
@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
}
  • 定義通?mapper
import com.zjq.domain.User;
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper<User> {
}
  • 測試
@Test
public void test1() throws IOException {
    Inputstream resourceAsStream =
    Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory build = new
    SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = build.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    user.setId(4);
    //(1)mapper基礎(chǔ)接?
    //select 接?
    //根據(jù)實體中的屬性進(jìn)?查詢,只能有一個返回值
    User user1 = userMapper.selectOne(user); 
    //查詢?nèi)拷Y(jié)果
    List<User> users = userMapper.select(null); 
    //根據(jù)主鍵字段進(jìn)?查詢,?法參數(shù)必須包含完整的主鍵屬性,查詢條件使?等號
    userMapper.selectByPrimaryKey(1); 
    //根據(jù)實體中的屬性查詢總數(shù),查詢條件使?等號
    userMapper.selectCount(user); 
    // insert 接?
    //保存?個實體,null值也會保存,不會使?數(shù)據(jù)庫默認(rèn)值
    int insert = userMapper.insert(user);
    //保存實體,null的屬性不會保存,會使?數(shù)據(jù)庫默認(rèn)值
    int i = userMapper.insertSelective(user); 
    // update 接?
    //根據(jù)主鍵更新實體全部字段,null值會被更新
    int i1 = userMapper.updateByPrimaryKey(user);
    // delete 接?
    //根據(jù)實體屬性作為條件進(jìn)?刪除,查詢條件使?等號
    int delete = userMapper.delete(user);
    //根據(jù)主鍵字段進(jìn)?刪除,?法參數(shù)必須包含完整的主鍵屬性
    userMapper.deleteByPrimaryKey(1); 
    //(2)example?法
    Example example = new Example(User.class);
    example.createCriteria().andEqualTo("id", 1);
    example.createCriteria().andLike("val", "1");
    //?定義查詢
    List<User> users1 = userMapper.selectByExample(example);
}

以上就是探究MyBatis插件原理以及自定義插件實現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于MyBatis插件原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java web實現(xiàn)簡單留言板功能

    java web實現(xiàn)簡單留言板功能

    這篇文章主要為大家詳細(xì)介紹了java web實現(xiàn)簡單留言板功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • SpringBoot利用EasyExcel實現(xiàn)導(dǎo)出數(shù)據(jù)

    SpringBoot利用EasyExcel實現(xiàn)導(dǎo)出數(shù)據(jù)

    EasyExcel是一個基于Java的、快速、簡潔、解決大文件內(nèi)存溢出的Excel處理工具,它能讓你在不用考慮性能、內(nèi)存的等因素的情況下,快速完成Excel的讀、寫等功能看,本文就將介紹如何利用EasyExcel實現(xiàn)導(dǎo)出數(shù)據(jù),需要的朋友可以參考下
    2023-07-07
  • 一文詳解Springboot集成mybatis-plus

    一文詳解Springboot集成mybatis-plus

    這篇文章主要介紹了Mybatis-Plus與SpringBoot整合,并在項目中實戰(zhàn)運(yùn)用,列舉其增刪改查的使用方式,對學(xué)習(xí)或工作有一定的幫助,需要的小伙伴可以參考閱讀
    2023-04-04
  • VSCode中開發(fā)JavaWeb項目的詳細(xì)過程(Maven+Tomcat+熱部署)

    VSCode中開發(fā)JavaWeb項目的詳細(xì)過程(Maven+Tomcat+熱部署)

    這篇文章主要介紹了VSCode中開發(fā)JavaWeb項目(Maven+Tomcat+熱部署),本文分步驟通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • gradle項目中資源文件的相對路徑打包技巧必看

    gradle項目中資源文件的相對路徑打包技巧必看

    這篇文章主要介紹了gradle項目中資源文件的相對路徑打包技巧必看篇,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Java 數(shù)據(jù)類型及類型轉(zhuǎn)換的互相轉(zhuǎn)換實例代碼

    Java 數(shù)據(jù)類型及類型轉(zhuǎn)換的互相轉(zhuǎn)換實例代碼

    這篇文章主要介紹了Java 數(shù)據(jù)類型及類型轉(zhuǎn)換的互相轉(zhuǎn)換實例代碼,需要的朋友可以參考下
    2020-10-10
  • java并發(fā)編程之深入理解Synchronized的使用

    java并發(fā)編程之深入理解Synchronized的使用

    文詳細(xì)講述了線程、進(jìn)程的關(guān)系及在操作系統(tǒng)中的表現(xiàn),這是多線程學(xué)習(xí)必須了解的基礎(chǔ)。本文將接著講一下Java線程同步中的一個重要的概念synchronized,希望能夠給你有所幫助
    2021-06-06
  • JAVA操作XML實例分析

    JAVA操作XML實例分析

    這篇文章主要介紹了JAVA操作XML的方法,實例分析了java操作XML文件的常用技巧,需要的朋友可以參考下
    2015-03-03
  • Java利用AQS實現(xiàn)自定義鎖

    Java利用AQS實現(xiàn)自定義鎖

    本文主要介紹了Java利用AQS實現(xiàn)自定義鎖,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • SpringBoot實現(xiàn)動態(tài)切換數(shù)據(jù)源的示例代碼

    SpringBoot實現(xiàn)動態(tài)切換數(shù)據(jù)源的示例代碼

    這篇文章主要為大家詳細(xì)介紹了SpringBoot實現(xiàn)動態(tài)切換數(shù)據(jù)源的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-08-08

最新評論

德令哈市| 宁蒗| 赣州市| 华池县| 乳源| 灵山县| 建始县| 广德县| 洱源县| 宜兴市| 兴山县| 达孜县| 渑池县| 文安县| 仪征市| 三明市| 江山市| 漾濞| 新干县| 绿春县| 高平市| 浠水县| 康保县| 徐闻县| 佛教| 凤冈县| 天津市| 三原县| 家居| 刚察县| 南昌县| 久治县| 宣城市| 赤城县| 合江县| 廊坊市| 柞水县| 玛多县| 石屏县| 建平县| 凤凰县|