摘要:因為抽象類天生就是用來被繼承的。由于不支多繼承,子類不能夠繼承多個類,但可以實現多個接口如果基本功能在不斷改變,那么就需要使用抽象類。全局異常處理接下來,我們在看看控制統一的異常攔截機制。
3、Spring Boot 緩存配置、全局異常處理 說明
如果您有幸能看到,請認閱讀以下內容;
1、本項目臨摹自abel533的Guns,他的項目 fork 自 stylefeng 的 Guns!開源的世界真好,可以學到很多知識。
2、版權歸原作者所有,自己只是學習使用。跟著大佬的思路,希望自己也能變成大佬。gogogo》。。
3、目前只是一個后臺模塊,希望自己技能增強到一定時,可以把stylefeng 的 [Guns]融合進來。
4、note里面是自己的學習過程,菜鳥寫的,不是大佬寫的。內容都是大佬的。
5、如有拼寫錯誤,還請見諒。目前的桌子不適合打字,本文只為自己記錄.
目錄1、SpringBoot第一站:分析了啟動類。還有各種自動配置的源碼點這里
2、SpringBoot第二站:定義了異常、注解、Node節點、Page點這里
3、SpringBoot第三站:SpringBoot數據源配置、Mybatis配置、日志記錄點這里
4、SpringBoot第四站:SpringBoot緩存配置、全局異常處理點這里
昨天看了數據源、日志記錄紙配置,我們今天再來看看緩存配置。
緩存配置1、利用Ehcache框架對經常調用的查詢進行緩存,從而提高系統性能。還是先看接口定義,需要注意的是get()方法使用了泛型
/** * 通用緩存接口 */ public interface ICache { void put(String cacheName, Object key, Object value);抽象類T get(String cacheName, Object key); @SuppressWarnings("rawtypes") List getKeys(String cacheName); void remove(String cacheName, Object key); void removeAll(String cacheName); T get(String cacheName, Object key, ILoader iLoader); T get(String cacheName, Object key, Class extends ILoader> iLoaderClass); } -------------------------------------------------------------------------------- /** * 數據重載 */ public interface ILoader { Object load(); }
接下來看下基礎CacheFactory,注意,這里定義成抽象的。因為抽象類天生就是用來被繼承的。
那什么時候使用抽象類和接口呢:
1、如果你擁有一些方法想讓他們中的一些默認實現,那么使用抽象類。
2、如果你想實現多重繼承,那么你必須使用接口。由于java不支多繼承,子類不能夠繼承多個類,但可以實現多個接口
3、如果基本功能在不斷改變,那么就需要使用抽象類。如果不斷改變基本功能并且使用接口 ,那么就需要改變所有實現了該接口的類。
/** * 緩存工廠基類 */ public abstract class BaseCacheFactory implements ICache { @SuppressWarnings("unchecked") public延遲初始化方案T get(String cacheName, Object key, ILoader iLoader) {..略..} @SuppressWarnings("unchecked") public T get(String cacheName, Object key, Class extends ILoader> iLoaderClass) { Object data = get(cacheName, key); if (data == null) { try { ILoader dataLoader = iLoaderClass.newInstance(); data = dataLoader.load(); put(cacheName, key, data); } catch (Exception e) { throw new RuntimeException(e); } } return (T) data; } }
接著在看看具體的EnCacheFactory,這里你自己也可以定義其他緩存工廠,擴展的時候只要繼承BaseCacheFactory就行。
第一點需要注意的是這里使用了org.slf4j.LoggerFactory
第二點需要注意的是靜態getCacheManager()方法,這里使用了雙重檢查機制,還有延時加載(創建)。有沒有想起單例模式啊,直接貼一段代碼
關鍵點是使用了volatile和synchronized保證了可見性和同步性。后者可以用在方法上,代碼塊上,具體內容看這里吧,不展開了友情提示.
主要作用:延遲初始化降低了初始化類或創建實例的開銷,但也增加了訪問被延遲初始化的字段的開銷。正常初始化要優于延遲加載,
如果確實要對實例字段使用多線程的安全的延遲初始化,使用基于volatile的初始化,如果需要對靜態字段使用線程安全的初始化,則使用基于類的初始化方案。
/** * Created by guo on 2018/1/29. */ public class SafeDoubleCheckedLocking { private volatile static Instacen instance; public static Instacen getInstance() { if(instance == null) { synchronized (SafeDoubleCheckedLocking.class) { if (instance == null) { instance = new Instacen(); } } } return instance; } } class Instacen{ } --------------------------對比------------------------------------------------- /** * Created by guo on 2018/1/29. * 基于類的初始化解決方案 */ public class InstanceFactory { private static class InstanceHolder{ public static Instance instance = new Instance(); } public static Instacen getInstance() { return InstanceHolder.instance; } } class Instance extends Instacen { }
回到我們Ehcache緩存工廠吧,重點是CacheManager.Spring框架底層有許多個Manager。如DataSourceTransactionManager.還有就是創建CacheManager的create()方法。人家也使用了雙重檢查,延遲加載。看見singleton了么。private static volatile CacheManager singleton;
public static CacheManager create() throws CacheException { if(singleton != null) { LOG.debug("Attempting to create an existing singleton. Existing singleton returned."); return singleton; } else { Class var0 = CacheManager.class; synchronized(CacheManager.class) { if(singleton == null) { singleton = newInstance(); } else { LOG.debug("Attempting to create an existing singleton. Existing singleton returned."); } return singleton; } } }
這里是調用cacheManager.getCache來獲取緩存。大家還是親自看看源碼把,這里只是自己明白了討論,記錄下。
/** * Ehcache緩存工廠 */ public class EhcacheFactory extends BaseCacheFactory { private static CacheManager cacheManager; private static volatile Object locker = new Object(); private static final Logger log = LoggerFactory.getLogger(EhcacheFactory.class); private static CacheManager getCacheManager() { if (cacheManager == null) { synchronized (EhcacheFactory.class) { if (cacheManager == null) { cacheManager = CacheManager.create(); } } } return cacheManager; } static Cache getOrAddCache(String cacheName) { CacheManager cacheManager = getCacheManager(); Cache cache = cacheManager.getCache(cacheName); if (cache == null) { synchronized(locker) { cache = cacheManager.getCache(cacheName); if (cache == null) { log.warn("無法找到緩存 [" + cacheName + "]的配置, 使用默認配置."); cacheManager.addCacheIfAbsent(cacheName); cache = cacheManager.getCache(cacheName); log.debug("緩存 [" + cacheName + "] 啟動."); } } } return cache; } -----------------------省略幾個---------------------------------------------- public void put(String cacheName, Object key, Object value) { getOrAddCache(cacheName).put(new Element(key, value)); } publicT get(String cacheName, Object key) { Element element = getOrAddCache(cacheName).get(key); return element != null ? (T)element.getObjectValue() : null; } public void remove(String cacheName, Object key) { getOrAddCache(cacheName).remove(key); } }
接著我們來看幾個常量的定義及實現
/** * 獲取被緩存的對象(用戶刪除業務) */ String getCacheObject(String para); ----------------------------------------------------------------------------------- /** * 獲取被緩存的對象(用戶刪除業務) */ @Override public String getCacheObject(String para) { return LogObjectHolder.me().get().toString(); //還有一個set()記得嗎? }
配置完了你總的使用,看代碼。先不關注權限那塊。CacheKit是一個工具類。
/** * 刪除角色 */ @RequestMapping(value = "/remove") @BussinessLog(value = "刪除角色", key = "roleId", dict = Dict.DeleteDict) @Permission(Const.ADMIN_NAME) @ResponseBody public Tip remove(@RequestParam Integer roleId) { if (ToolUtil.isEmpty(roleId)) { throw new BussinessException(BizExceptionEnum.REQUEST_NULL); } //不能刪除超級管理員角色 if(roleId.equals(Const.ADMIN_ROLE_ID)){ throw new BussinessException(BizExceptionEnum.CANT_DELETE_ADMIN); } //緩存被刪除的角色名稱 LogObjectHolder.me().set(ConstantFactory.me().getSingleRoleName(roleId)); roleService.delRoleById(roleId); //刪除緩存 CacheKit.removeAll(Cache.CONSTANT); return SUCCESS_TIP; } ---------------------------工具類------------------------------------------------ /** * 緩存工具類 */ public class CacheKit { private static ICache defaultCacheFactory = new EhcacheFactory(); //這里創建Encache工廠。 public static void put(String cacheName, Object key, Object value) { defaultCacheFactory.put(cacheName, key, value); } public static void removeAll(String cacheName) { defaultCacheFactory.removeAll(cacheName); } }
到這里緩存部分算是結束了,再次說明,只是自己記錄過程,要讓我實現,目前不現實,還需要自己請自看看源碼,跑一遍。
全局異常處理接下來,我們在看看控制統一的異常攔截機制。這里用到了切面的思想。第一眼看到的是@ControllerAdvice。這是什么東東,看圖說話。GlobalExceptionHandler全部代碼點這里點這里。ResponseStatus狀態先不關注。
/** * 全局的的異常攔截器(攔截所有的控制器)(帶有@RequestMapping注解的方法上都會攔截) */ @ControllerAdvice public class GlobalExceptionHandler { private Logger log = LoggerFactory.getLogger(this.getClass()); /** * 攔截業務異常 * * @author fengshuonan */ @ExceptionHandler(BussinessException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public ErrorTip notFount(BussinessException e) { LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e)); getRequest().setAttribute("tip", e.getMessage()); log.error("業務異常:", e); return new ErrorTip(e.getCode(), e.getMessage()); } /** * 用戶未登錄 */ @ExceptionHandler(AuthenticationException.class) @ResponseStatus(HttpStatus.UNAUTHORIZED) public String unAuth(AuthenticationException e) { log.error("用戶未登陸:", e); return "/login.html"; } /** * 攔截未知的運行時異常 */ @ExceptionHandler(RuntimeException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public ErrorTip notFount(RuntimeException e) { LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e)); getRequest().setAttribute("tip", "服務器未知運行時異常"); log.error("運行時異常:", e); return new ErrorTip(BizExceptionEnum.SERVER_ERROR); } }
異常處理看得也差不多了,接下來看什么好呢?持續關注,
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68668.html
摘要:開公眾號差不多兩年了,有不少原創教程,當原創越來越多時,大家搜索起來就很不方便,因此做了一個索引幫助大家快速找到需要的文章系列處理登錄請求前后端分離一使用完美處理權限問題前后端分離二使用完美處理權限問題前后端分離三中密碼加鹽與中異常統一處理 開公眾號差不多兩年了,有不少原創教程,當原創越來越多時,大家搜索起來就很不方便,因此做了一個索引幫助大家快速找到需要的文章! Spring Boo...
摘要:目前只是一個后臺模塊,希望自己技能增強到一定時,可以把的融合進來。目錄第一站,分析了啟動類??匆姏],這個也是配置類,它聲明了視圖解析器地域解析器以及靜態資源的位置,想起來沒,就是前置,后置。程序啟動類我們點擊源碼看看。 Guns基于SpringBoot,致力于做更簡潔的后臺管理系統,完美整合springmvc + shiro + 分頁插件PageHelper + 通用Mapper + ...
摘要:前言如題,今天介紹是如何統一處理全局異常的。主要是用于異常攔截出獲取并將設置到消息類中返回。狀態碼異常攔截類通過加入來聲明該類可攔截請求,同時在方法加入并在該注解中指定要攔截的異常類。測試訪問測試正常返回數據結果。 微信公眾號:一個優秀的廢人如有問題或建議,請后臺留言,我會盡力解決你的問題。 前言 如題,今天介紹 SpringBoot 是如何統一處理全局異常的。SpringBoot 中...
摘要:仿抖音短視頻小程序開發一項目的簡介仿抖音短視頻小程序開發二項目功能分析與具體實現源代碼仿抖音短視頻小程序開發全棧式實戰項目短視頻后臺管理系統小程序的后臺管理系統涉及的技術棧框架一用戶列表的獲取與分頁前端代碼用戶列表展示的表格底部 SpringBoot 仿抖音短視頻小程序開發(一):項目的簡介(https://segmentfault.com/a/11...SpringBoot 仿抖音短...
閱讀 1075·2021-09-29 09:35
閱讀 4621·2021-09-22 15:24
閱讀 1449·2021-07-25 21:37
閱讀 2178·2019-08-30 14:17
閱讀 965·2019-08-30 13:56
閱讀 2411·2019-08-29 17:07
閱讀 1250·2019-08-29 12:44
閱讀 2705·2019-08-26 18:26