亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

概要:

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

要實現(xiàn)兩個功能

  1. 可以通過http請求來立刻刷新緩存
  2. 緩存可以通過自己配置的時間間隔來定期刷新

通過Controller來做

因為需要通過http來刷新緩存,所以第一個想法就是把緩存做成一個Controller

Controller的實現(xiàn)

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

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

定義一個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服務跟Service層,數(shù)據(jù)庫層連接,但是如果CacheController實現(xiàn)Cache接口,會發(fā)現(xiàn)很難調(diào)用interval函數(shù)來找到間隔的時間。

因為CacheController也是一個Bean,需要通過Spring找到這個bean來調(diào)用。無法找到Bean,就不能調(diào)用Interval,也就不能夠順勢通過另外的線程來控制緩存刷新。為了獲取這個Bean可以將所有的CacheController都Autowired到一個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)一個問題,這樣做,CacheManagerController在初始化的時候,也就是構造Bean的時候,各種的Cache還沒有被注入CacheController,而如果不將方法放入構造函數(shù),那么CacheManagerController是無法自動的調(diào)用調(diào)度服務的。需要手動調(diào)用才行。但是程序的入口不一定從哪一個Controller進入,如果寫攔截器,也是很繁瑣,而且每次調(diào)用都會執(zhí)行。

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

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;
  }
}

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

至于獲取指定的Cache,更簡單了,因為Cache本身是一個Controller,所以可以通過Autowire自動注冊到需要使用的其他Controller之中。

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

總結

使用Controller的特點如下:

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

通過Listener來做

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

Listener的實現(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>

當然了,有優(yōu)勢肯定會存在劣勢,因為使用Listener的方式來提前加載,也會因為Web的聲明周期,產(chǎn)生問題。

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

除此以外, 還需要單獨寫一個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以外,還需要提供一個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的啟動??梢钥闯觯械腃acheFactory之中的方法都是靜態(tài)方法,可以直接由Controller層隨便調(diào)用。

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

總結

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

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

相關文章

  • IntelliJ?IDEA?2023.2最新版激活方法及驗證ja-netfilter配置是否成功

    IntelliJ?IDEA?2023.2最新版激活方法及驗證ja-netfilter配置是否成功

    隨著2023.2版本的發(fā)布,用戶們渴望了解如何激活這個最新版的IDE,本文將介紹三種可行的激活方案,包括許可證服務器、許可證代碼和idea?vmoptions配置,幫助讀者成功激活并充分利用IDEA的功能,感興趣的朋友參考下吧
    2023-08-08
  • Windows下將JAVA?jar注冊成windows服務的方法

    Windows下將JAVA?jar注冊成windows服務的方法

    這篇文章主要介紹了Windows下將JAVA?jar注冊成windows服務的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • Java計算一個數(shù)加上100是完全平方數(shù),加上168還是完全平方數(shù)

    Java計算一個數(shù)加上100是完全平方數(shù),加上168還是完全平方數(shù)

    這篇文章主要介紹了Java計算一個數(shù)加上100是完全平方數(shù),加上168還是完全平方數(shù),需要的朋友可以參考下
    2017-02-02
  • Java中關于Null的9個解釋(Java Null詳解)

    Java中關于Null的9個解釋(Java Null詳解)

    這篇文章主要介紹了Java中關于Null的9個解釋(Java Null詳解),本文詳細講解了Java中Null的9個相關知識,需要的朋友可以參考下
    2015-01-01
  • java數(shù)據(jù)結構與算法之中綴表達式轉(zhuǎn)為后綴表達式的方法

    java數(shù)據(jù)結構與算法之中綴表達式轉(zhuǎn)為后綴表達式的方法

    這篇文章主要介紹了java數(shù)據(jù)結構與算法之中綴表達式轉(zhuǎn)為后綴表達式的方法,簡單分析了java中綴表達式轉(zhuǎn)為后綴表達式的相關實現(xiàn)方法與技巧,需要的朋友可以參考下
    2016-08-08
  • java 全角半角字符轉(zhuǎn)換的方法實例

    java 全角半角字符轉(zhuǎn)換的方法實例

    這篇文章主要介紹了java 全角半角字符轉(zhuǎn)換的方法,大家參考使用吧
    2013-11-11
  • JVM核心教程之JVM運行與類加載全過程詳解

    JVM核心教程之JVM運行與類加載全過程詳解

    我們都知道一個java程序運行要經(jīng)過編譯和執(zhí)行,但是這太概括了,中間還有很多步驟,下面這篇文章主要給大家介紹了關于JVM核心教程之JVM運行與類加載全過程的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。
    2018-04-04
  • java的引用類型的詳細介紹

    java的引用類型的詳細介紹

    在java中提供了4個級別的引用:強引用、軟引用、弱引用、虛引用。其中強引用FinalReference是default個飾符來修飾,其它3個級別均為public修飾
    2013-10-10
  • Java中Properties配置類用法詳解

    Java中Properties配置類用法詳解

    所謂的配置文件問題,是指我們在開發(fā)時,經(jīng)常需要讀取和修改一些配置信息,比如數(shù)據(jù)庫、消息隊列、Nginx、Web服務器等的配置,為了便于修改這些信息,我們可以采用Properties配置類,本文給大家講一下Properties配置類是怎么回事,以及怎么使用
    2023-06-06
  • Mybatis動態(tài)sql中@Param使用詳解

    Mybatis動態(tài)sql中@Param使用詳解

    這篇文章主要介紹了Mybatis動態(tài)sql中@Param使用詳解,當方法的參數(shù)為非自定義pojo類型,且使用了動態(tài)sql,那么就需要在參數(shù)前加上@Param注解,需要的朋友可以參考下
    2023-10-10

最新評論