程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 變通實現微服務的per request以提高IO效率(三),perio

變通實現微服務的per request以提高IO效率(三),perio

編輯:JAVA綜合教程

變通實現微服務的per request以提高IO效率(三),perio


效率

變通實現微服務的per request以提高IO效率(二)遺留一個問題,如何正確的釋放存儲在ThreadLocal中的緩存,最理由就是在我們請求的方法執行完成後去清除緩存。

Filter

由於我的項目是基於dubbo的,所以可以利用dubbo提供的Filter機制去完成這件事情,可以看下filter的地位:

最終的效果:

創建ThreadLocalCacheFilter

創建一個類讓其實現Filter接口,就一個方法invoke,這個invoke方法的功能類似於AOP的Around方法,我們想清除緩存就有地方操作了,只需要在return的前面,invoker.invoke方法後面添加相應的清除邏輯即可達到目的。由於緩存是線程獨有的,所以直接清空就可以。

由於Filter加載機制問題,在Filter中使用Spring的注解是有點問題的,暫時是通過手動獲取Bean的方式來加載cacheManager,後面在看dubbo的filter加載機制時會有簡單提到。大家如果有其它好的方案可以告訴我

@Activate
public class ThreadLocalCacheFilter implements Filter {

    private Logger logger = LoggerFactory.getLogger(getClass().getName());

    @Autowired
    private CacheManager cacheManager;

    private void clearCache(){
        if(null==cacheManager){
            ApplicationContext appCtx = ApplicationContextUtils.getApplicationContext();
            cacheManager= appCtx.getBean(ThreadLocalCacheManager.class);
        }
        Collection<String> cacheNames= this.cacheManager.getCacheNames();
        if(null!=cacheNames) {
            for(String cacheName :cacheNames) {
                this.cacheManager.getCache(cacheName).clear();
            }
        }
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result=invoker.invoke(invocation);
        this.logger.info("release cache start");
        this.clearCache();
        this.logger.info("release cache end");

        return result;
    }
}

@Active注解
要想激活filter,我們需要在創建的自定義filter類上加載@Active注解,看下它的相關參數,也可以不配置

  • group,條件之一,指定是服務端還是消費端
  • value,條件之一,一般就是這個filter的英文名稱,在dubbo配置文件中使用的
  • before,排序的信息,比如排在哪些filter之前
  • after,排序的信息,比如排在哪些filter之後
  • order,排序的信息,應該是值越小排在最前面

加載Filter

編寫的擴展filter,dubbo需要加載成功後才能使用,dubbo總共從resource下面的三個目錄中加載filter

  • META-INF/services/
  • META-INF/dubbo/
  • META-INF/dubbo/internal/

創建純文件文件com.alibaba.dubbo.rpc.Filter放入對應的目錄,然後寫入需要使用的filter信息

threadLocalCacheFilter=com.filter.ThreadLocalCacheFilter

應用Filter

在dubbo配置文件中增加如下內容:

<dubbo:provider filter="threadLocalCacheFilter" />

Dubbo Filter

dubbo有這樣一個類ProtocolFilterWrapper,它負責加載項目中所有的filter,並負責鏈式調用。

想學習設計模式的可以看看這個類是如何使用職責鏈模式的
這裡只看一個方法就可以了:

  • ExtensionLoader加載所以實現了Filter接口的類
  • 根據過濾條件過濾filter,裡面有排序
  • 循環調用所有符合條件且經過排序的filter

注意變量next,當前方法在執行invoke方法時,將調用傳遞到了next。這裡應該會有最後一個終結器來處理實際方法的執行。

 private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (filters.size() > 0) {
            for (int i = filters.size() - 1; i >= 0; i --) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    public Class<T> getInterface() {
                        return invoker.getInterface();
                    }

                    public URL getUrl() {
                        return invoker.getUrl();
                    }

                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }

                    public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);
                    }

                    public void destroy() {
                        invoker.destroy();
                    }

                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
        return last;
    }

總結

結過三篇筆記,從最初的Context問題,到緩存的釋放,基本可以非常方便的使用請求級的緩存了。這裡需要注意的是需要明確哪些方案是適合做請求級緩存的。比如查詢用戶,有些操作中先插入用戶然後再查詢,如果查詢的是被標記了請求級緩存的方法就會有問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved