成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Mybatis:一種 Redis 緩存實(shí)現(xiàn)

caige / 3011人閱讀

摘要:前言本文介紹一種緩存的實(shí)現(xiàn)方法,使用實(shí)例如下通過(guò)使用注解來(lái)標(biāo)注哪些數(shù)據(jù)庫(kù)訪問(wèn)需要緩存,屬性設(shè)置前綴,這樣做的好處是將緩存的實(shí)現(xiàn)和業(yè)務(wù)邏輯分開(kāi),可擴(kuò)展性強(qiáng)實(shí)現(xiàn)如上所述,注解用于注釋需要緩存的接口方法在容器中通常都會(huì)配置一個(gè)用來(lái)指定的位置包名,

前言

本文介紹一種 mybatis redis 緩存的實(shí)現(xiàn)方法,使用實(shí)例如下:

@Repository
public interface UserDao {
    @Cache(prefix="user:")
    @Select(...)
    public User findUserById(int userId);
}

通過(guò)使用 Cache 注解來(lái)標(biāo)注哪些數(shù)據(jù)庫(kù)訪問(wèn)(select)需要緩存,prefix 屬性設(shè)置 Redis key 前綴,這樣做的好處是將緩存的實(shí)現(xiàn)和業(yè)務(wù)邏輯分開(kāi),可擴(kuò)展性強(qiáng)

實(shí)現(xiàn) Cache

如上所述,Cache 注解用于注釋需要緩存的 mapper 接口方法

public @interface Cache {

    long expire() default DEFAULT_EXPIRE_TIME;

    String prefix();
}
MapperScannerConfigurer

在 spring 容器中 mybatis 通常都會(huì)配置一個(gè) MapperScannerConfigurer 用來(lái)指定 mapper(ORM)的位置(包名),通過(guò)閱讀相關(guān)源代碼可以知道 MapperScannerConfigurer 會(huì)為每個(gè) mapper 接口生成一個(gè)動(dòng)態(tài)代理,我們要做的就是擴(kuò)展 MapperScannerConfigurer,給 mybatis 提供的動(dòng)態(tài)代理提供一個(gè) wrapper 包裝

public class MapperScannerConfigurerProxy extends MapperScannerConfigurer {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        super.postProcessBeanDefinitionRegistry(registry);
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionName);
            if (!(beanDefinition instanceof GenericBeanDefinition)) {
                continue;
            }

            GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanDefinition;
            if (!genericBeanDefinition.hasBeanClass()) {
                continue;
            }

            if (genericBeanDefinition.getBeanClass() != MapperFactoryBean.class) {
                continue;
            }

            genericBeanDefinition.setBeanClass(MapperFactoryBeanProxy.class);
            genericBeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
    }
}

postProcessBeanDefinitionRegistry 是 spring bean 生命周期回調(diào)方法,這里先調(diào)用父類方法,然后遍歷 bean registry,找到 MapperFactoryBean(mapper 動(dòng)態(tài)代理工廠 bean),將它的 bean class 修改成我們提供的 MapperFactoryBeanProxy

MapperFactoryBeanProxy

MapperFactoryBeanProxy 是對(duì) mybatis 提供的 MapperFactoryBean 的代理,它有三個(gè)屬性(字段)

public class MapperFactoryBeanProxy implements FactoryBean {

    private Class mapperInterface;

    @Autowired
    private MapperCacheStrategy mapperCacheStrategy;

    private MapperFactoryBean mapperFactoryBean;
}

mapperInterfacemapper, mapper 接口類(例如 UserDao)

mapperCacheStrategy, 具體的緩存策略(模式)

mapperFactoryBean, mybatis 提供的默認(rèn)的 mapper factory bean

構(gòu)造方法

保存 mapper interface 的引用以及創(chuàng)建 mybatis MapperFactoryBean 對(duì)象

public MapperFactoryBeanFactory(Class mapperInterface) {
    this.mapperInterface = mapperInterface;
    mapperFactoryBean = new MapperFactoryBean<>(mapperInterface);
}
getObject

spring 通過(guò)調(diào)用 FactoryBean 的 getObject 方法創(chuàng)建 bean 對(duì)象,這里先調(diào)用 mybatis MapperFactoryBean 的 getObject 方法獲取 mybatis 創(chuàng)建的動(dòng)態(tài)代理,然后調(diào)用 Proxy.newProxyInstance 方法基于 mapper interface 再創(chuàng)建一個(gè)動(dòng)態(tài)代理,handler 為 MapperProxy

    @Override
    public Object getObject() throws Exception {
        mapperFactoryBean.afterPropertiesSet();
        Object object = mapperFactoryBean.getObject();
        return Proxy.newProxyInstance(getClass().getClassLoader(),
                new Class[]{mapperFactoryBean.getMapperInterface()},
                new MapperProxy(object, mapperCacheStrategy));
    }
MapperProxy

MapperProxy 動(dòng)態(tài)代理 handler 用于實(shí)現(xiàn)具體的緩存策略

public class MapperProxy implements InvocationHandler {

    private Object target;

    private MapperCacheStrategy mapperCacheStrategy;

    public MapperProxy(Object target, MapperCacheStrategy mapperCacheStrategy) {
        this.target = target;
        this.mapperCacheStrategy = mapperCacheStrategy;
    }

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

invoke 方法基本流程:

如果是 Object 中定義的方法直接返回

判斷方法時(shí)候有 Cache 注解,如果沒(méi)有,表明不需要緩存,直接返回

調(diào)用 mapper cache strategy 類的 get 方法獲取緩存,如果命中直接返回

調(diào)用 原始方法(查庫(kù))并更新緩存

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if (Object.class.equals(method.getDeclaringClass())) {
        try {
            return method.invoke(this, args);
        } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
        }
    }
    Cache annotation = method.getAnnotation(Cache.class);
    if (annotation == null) {
        return method.invoke(target, args);
    }
    long expire = annotation.expire();
    String prefix = annotation.prefix();
    String key = getKey(prefix, args);
    Object object = null;
    try {
        object = mapperCacheStrategy.get(key, method.getGenericReturnType());
    } catch (Exception e) {
        logger.error("mapperCacheStrategy.get " + key, e);
    }
    if (object != null) {
        return object;
    }
    object = method.invoke(target, args);
    if (!isBlank(object)) {
        mapperCacheStrategy.set(key, object, expire);
    }
    return object;
}

這里沒(méi)有考慮諸如 緩存穿透 之類的問(wèn)題,讀者可以自行擴(kuò)展

總結(jié)

本文介紹了一種通過(guò) 擴(kuò)展 mybatis,增加自定義注解來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)緩存的方法,該方法不僅可以用于緩存處理,稍微修改一下就可以實(shí)現(xiàn)數(shù)據(jù)的讀寫(xiě)分離,例如定義一個(gè) DataSource 注解注釋 mapper 方法需要連接哪個(gè)數(shù)據(jù)源~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67002.html

相關(guān)文章

  • MyBatis緩存介紹

    摘要:緩存介紹正如大多數(shù)持久層框架一樣,同樣提供了一級(jí)緩存和二級(jí)緩存的支持一級(jí)緩存基于的本地緩存,其存儲(chǔ)作用域?yàn)椋?dāng)或之后,該中的所有就將清空。一級(jí)緩存實(shí)現(xiàn)對(duì)的操作內(nèi)部都是通過(guò)來(lái)執(zhí)行的。 MyBatis緩存介紹   正如大多數(shù)持久層框架一樣,MyBatis 同樣提供了一級(jí)緩存和二級(jí)緩存的支持   一級(jí)緩存: 基于PerpetualCache 的 HashMap本地緩存,其存儲(chǔ)作用域?yàn)?Se...

    mingde 評(píng)論0 收藏0
  • Spring Boot2(三):使用Spring Boot2集成Redis緩存

    摘要:本文章的源碼再文章末尾什么是查詢緩存有一級(jí)緩存和二級(jí)緩存。默認(rèn)開(kāi)啟一級(jí)緩存。證明了一級(jí)緩存只是在數(shù)據(jù)庫(kù)會(huì)話內(nèi)部共享的。但是,整合到中后,一級(jí)緩存就會(huì)被關(guān)閉。根據(jù)時(shí)間表比如沒(méi)有刷新間隔緩存不會(huì)以任何時(shí)間順序來(lái)刷新。 學(xué)習(xí)SpringBoot集成Mybatis的第二章,了解到Mybatis自帶的緩存機(jī)制,在部署的時(shí)候踩過(guò)了一些坑。在此記錄和分享一下Mybatis的緩存作用。 本文章的源碼再...

    NusterCache 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<