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

Java Cache詳解及簡單實(shí)現(xiàn)

 更新時(shí)間:2017年02月04日 14:36:35   作者:EthanPark  
這篇文章主要介紹了 Java Cache詳解及簡單實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下

 Java Cache詳解及簡單實(shí)現(xiàn)

概要:

最近在做spring的項(xiàng)目,想做一個(gè)緩存,訪問數(shù)據(jù)庫,定期來做數(shù)據(jù)更新

要實(shí)現(xiàn)兩個(gè)功能

  1. 可以通過http請(qǐng)求來立刻刷新緩存
  2. 緩存可以通過自己配置的時(shí)間間隔來定期刷新

通過Controller來做

因?yàn)樾枰ㄟ^http來刷新緩存,所以第一個(gè)想法就是把緩存做成一個(gè)Controller

Controller的實(shí)現(xiàn)

Controller最大的優(yōu)勢(shì),就是可以通過Spring的配置,注入很多依賴,比如對(duì)Service的依賴,對(duì)數(shù)據(jù)庫的依賴等。

大量的訪問數(shù)據(jù)庫跟服務(wù)層的代碼,都可以進(jìn)行復(fù)用

定義一個(gè)Cache接口如下:

public interface Cache {
  /**
  * Refresh the cache. If succeed, return true, else return false;
  * 
  * @return
  */
  boolean refresh();

  /**
  * How much time it will refresh the cache.
  * 
  * @return
  */
  long interval();
}

但是這里碰到了問題,自己寫的Controller可以通過注入的方式輕而易舉的與Http服務(wù)跟Service層,數(shù)據(jù)庫層連接,但是如果CacheController實(shí)現(xiàn)Cache接口,會(huì)發(fā)現(xiàn)很難調(diào)用interval函數(shù)來找到間隔的時(shí)間。

因?yàn)镃acheController也是一個(gè)Bean,需要通過Spring找到這個(gè)bean來調(diào)用。無法找到Bean,就不能調(diào)用Interval,也就不能夠順勢(shì)通過另外的線程來控制緩存刷新。為了獲取這個(gè)Bean可以將所有的CacheController都Autowired到一個(gè)CacheManagerController之中

@Controller
public class CacheManagerController {

  @Autowired
  private CacheController cache;

  private static ScheduledExecutorService executor = Executors
     .newScheduledThreadPool(1);

  public CacheManagerController() {
   executor.scheduleAtFixedRate(() -> cache.refresh(), 0, cache.interval(),
      TimeUnit.MILLISECONDS);
  }
}

曾經(jīng)考慮這么做,但是發(fā)現(xiàn)一個(gè)問題,這樣做,CacheManagerController在初始化的時(shí)候,也就是構(gòu)造Bean的時(shí)候,各種的Cache還沒有被注入CacheController,而如果不將方法放入構(gòu)造函數(shù),那么CacheManagerController是無法自動(dòng)的調(diào)用調(diào)度服務(wù)的。需要手動(dòng)調(diào)用才行。但是程序的入口不一定從哪一個(gè)Controller進(jìn)入,如果寫攔截器,也是很繁瑣,而且每次調(diào)用都會(huì)執(zhí)行。

這個(gè)時(shí)候,就通過一個(gè)CacheService來實(shí)現(xiàn)這個(gè)問題

public class CacheService {
  public static final long ONE_MINUTE = 60 * 1000;

  private static ScheduledExecutorService executor = Executors
     .newScheduledThreadPool(1);

  public static void register(Cache cache) {
   executor.scheduleAtFixedRate(() -> cache.refresh(), 0, cache.interval(),
      TimeUnit.MILLISECONDS);
  }
}

@Controller
public class CacheController implements Cache {

  // autowire 各種不同的service,或者是repo連接數(shù)據(jù)庫
  @Autowired
  private Service service;

  public CacheController() {
   CacheService.register(this);
  }

  // cache interface
  @Override
  public long interval() {
   return 1000;
  }

  @Override
  public boolean refresh() {
   return true;
  }
}

因?yàn)榫唧w的CacheController是通過反射構(gòu)造成Bean由Spring管理的,所以可以直接通過無參構(gòu)造函數(shù)來注冊(cè)一下,這樣就沒有問題了,當(dāng)Spring在加載CacheController的時(shí)候,就會(huì)直接調(diào)用CacheService的注冊(cè)方法,將緩存注冊(cè)到CacheService中定義的線程池當(dāng)中,然后立刻執(zhí)行刷新方法,同時(shí)還會(huì)根據(jù)時(shí)間間隔來自動(dòng)的刷新。

至于獲取指定的Cache,更簡單了,因?yàn)镃ache本身是一個(gè)Controller,所以可以通過Autowire自動(dòng)注冊(cè)到需要使用的其他Controller之中。

當(dāng)然了,目前這么寫是沒有什么問題,但是當(dāng)refresh為立刻調(diào)用的時(shí)候,會(huì)無法拿到Autowired注入的那些Service。因?yàn)镾pring是統(tǒng)一全部實(shí)例化,然后再進(jìn)行裝載的,所以,如果refresh函數(shù)中調(diào)用了service,那么顯然,程序肯定會(huì)報(bào)空指針異常的。這也是使用Controller來做Cache的問題。如果要獲得全部的Spring裝載的實(shí)例,那么肯定就都要修改構(gòu)造函數(shù)來將實(shí)例注入到統(tǒng)一的集合當(dāng)中了,那樣就跟前文提到的問題一樣了,也就是獲取Bean。如果能夠獲取Bean,那直接就能調(diào)用實(shí)例方法,也就沒有這么多事情了。

總結(jié)

使用Controller的特點(diǎn)如下:

  • 代碼復(fù)用,定義的repo層,service層代碼都可以繼續(xù)使用,不用重寫
  • 因?yàn)镾pring聲明周期的問題,refresh操作立刻執(zhí)行會(huì)拋異常,需要延時(shí)刷新

通過Listener來做

Listener有一個(gè)優(yōu)勢(shì),就是可以通過一個(gè)寫一個(gè)PreloadListener 實(shí)現(xiàn)ServletContextListener,這樣就能夠利用Tomcat加載web.xml的時(shí)候,將代碼提前進(jìn)行初始化了。

Listener的實(shí)現(xiàn)

public class PreloadListener implements ServletContextListener {
  @Override
  public void contextInitialized(ServletContextEvent servletContextEvent) {
   CacheFactory.init();
  }

  @Override
  public void contextDestroyed(ServletContextEvent servletContextEvent) {

  }
}

下面是web.xml的代碼

// web.xml
  <listener>
    <listener-class>com.sapphire.listener.PreloadListener</listener-class>
  </listener>

當(dāng)然了,有優(yōu)勢(shì)肯定會(huì)存在劣勢(shì),因?yàn)槭褂肔istener的方式來提前加載,也會(huì)因?yàn)閃eb的聲明周期,產(chǎn)生問題。

Tomcat在加載Web.xml的時(shí)候,Listener的初始化,會(huì)在Spring容器啟動(dòng)之前,這樣也就碰到一個(gè)問題。PreloadListener中可以調(diào)用的代碼,肯定是無法Autowire到任何的Bean的。這也就是對(duì)比Controller碰到的一個(gè)巨大的劣勢(shì)了,需要自己重寫那些Service。

除此以外, 還需要單獨(dú)寫一個(gè)Controller來刷新指定的緩存。

public class CacheFactory {
  private static ConcurrentHashMap<String, Cache> caches = new ConcurrentHashMap<>();
  private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

  private static void register(Cache cache) {
   caches.put(cache.category(), cache);
  }

  private static void registerAll() {
   register(new StockCache());
  }

  public static void init() {
   registerAll();

   for (Cache cache : caches.values()) {
     executorService.scheduleAtFixedRate(new Runnable() {
      @Override
      public void run() {
        cache.refresh();
      }
     }, 0, cache.interval(), TimeUnit.MILLISECONDS);
   }
  }

  public static Cache getCache(String key) {
   if (caches.contains(key)) {
     return caches.get(key);
   }
   return null;
  }
}

// cache接口除了需要提供interval和refresh以外,還需要提供一個(gè)category來區(qū)分不同的Cache
public interface Cache {
  /**
  * Refresh the cache. If succeed, return true, else return false;
  * 
  * @return
  */
  boolean refresh();

  /**
  * How much time it will refresh the cache.
  * 
  * @return
  */
  long interval();

  /**
  * Cache's category. Each cache has distinct category.
  * 
  * @return
  */
  String category();
}

這樣完成的CacheFactory,可以在PreloadListener之中調(diào)用init方法來初始化所有的Cache,來完成Cache的啟動(dòng)。可以看出,所有的CacheFactory之中的方法都是靜態(tài)方法,可以直接由Controller層隨便調(diào)用。

之后,不同的Cache就需要單獨(dú)來寫init方法,放到各自實(shí)現(xiàn)的refresh方法之中。跟數(shù)據(jù)庫的鏈接等,都需要建立。不同的Cache都需要重寫各自的初始化方法,還需要寫一個(gè)讀取文件配置的東西讀取數(shù)據(jù)庫的一些配置信息??傊?,感覺很麻煩。

總結(jié)

通過Listener來實(shí)現(xiàn),更加靈活,可以在容器啟動(dòng)之前就將需要的信息加載到內(nèi)存之中,但是很多業(yè)務(wù)代碼都需要重新來寫,數(shù)據(jù)庫的鏈接,解析Property,靈活刷新的CacheController。

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • Java導(dǎo)出Excel統(tǒng)計(jì)報(bào)表合并單元格的方法詳解

    Java導(dǎo)出Excel統(tǒng)計(jì)報(bào)表合并單元格的方法詳解

    我們?cè)谌粘>幊踢^程中,總是會(huì)碰見導(dǎo)出相關(guān)表格信息的需求,所以就讓我們一起來學(xué)習(xí)一下,這篇文章主要給大家介紹了關(guān)于Java導(dǎo)出Excel統(tǒng)計(jì)報(bào)表合并單元格的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • SpringBoot上傳圖片的示例

    SpringBoot上傳圖片的示例

    這篇文章主要介紹了SpringBoot上傳圖片的示例,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下
    2020-11-11
  • Feign如何使用protobuf的類作為參數(shù)調(diào)用

    Feign如何使用protobuf的類作為參數(shù)調(diào)用

    這篇文章主要介紹了Feign如何使用protobuf的類作為參數(shù)調(diào)用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Maven項(xiàng)目分析剔除無用jar引用的方法步驟

    Maven項(xiàng)目分析剔除無用jar引用的方法步驟

    這篇文章主要介紹了Maven項(xiàng)目分析剔除無用jar引用的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Java面試必備之ArrayList陷阱解析

    Java面試必備之ArrayList陷阱解析

    昨天小楓接到了一個(gè)公司的面試電話,其中一道面試題覺得有點(diǎn)意思,在這里和大家一起分享下。面試題是ArrayList如何刪除指定元素。乍聽很簡單的問題,但是如果沒有實(shí)際踩過坑很容易掉進(jìn)面試官的陷阱中,我們一起來分析下吧
    2022-02-02
  • Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼

    Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Mybatis如何傳入多個(gè)參數(shù)的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Java控制臺(tái)版五子棋的簡單實(shí)現(xiàn)方法

    Java控制臺(tái)版五子棋的簡單實(shí)現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于Java控制臺(tái)版五子棋的簡單實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • spring?boot項(xiàng)目中集成rocketmq詳細(xì)步驟

    spring?boot項(xiàng)目中集成rocketmq詳細(xì)步驟

    這篇文章主要給大家介紹了關(guān)于spring?boot項(xiàng)目中集成rocketmq的相關(guān)資料,springboot集成rocketmq的方法非常簡單,文中直接上代碼,需要的朋友可以參考下
    2023-09-09
  • springmvc如何使用map接收參數(shù)

    springmvc如何使用map接收參數(shù)

    這篇文章主要介紹了springmvc如何使用map接收參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • spring中的BeanFactory與FactoryBean的講解

    spring中的BeanFactory與FactoryBean的講解

    今天小編就為大家分享一篇關(guān)于spring中的BeanFactory與FactoryBean的講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評(píng)論

黄骅市| 铁岭市| 漠河县| 台山市| 沙坪坝区| 都兰县| 手游| 翁牛特旗| 拜泉县| 枞阳县| 林西县| 突泉县| 元氏县| 余庆县| 咸宁市| 巴林左旗| 怀柔区| 会东县| 柘荣县| 商河县| 隆林| 凭祥市| 黑山县| 景宁| 类乌齐县| 陆丰市| 潞城市| 从化市| 台安县| 麻栗坡县| 南汇区| 灵丘县| 襄城县| 阿拉尔市| 汤阴县| 广南县| 南昌市| 威远县| 南皮县| 修水县| 武城县|