成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

基于SpringBoot的后臺(tái)管理系統(tǒng)(Encache配置、全局異常處理(重點(diǎn)))(四)

Benedict Evans / 543人閱讀

摘要:因?yàn)槌橄箢?lèi)天生就是用來(lái)被繼承的。由于不支多繼承,子類(lèi)不能夠繼承多個(gè)類(lèi),但可以實(shí)現(xiàn)多個(gè)接口如果基本功能在不斷改變,那么就需要使用抽象類(lèi)。全局異常處理接下來(lái),我們?cè)诳纯纯刂平y(tǒng)一的異常攔截機(jī)制。

3、Spring Boot 緩存配置、全局異常處理 說(shuō)明

如果您有幸能看到,請(qǐng)認(rèn)閱讀以下內(nèi)容;

1、本項(xiàng)目臨摹自abel533的Guns,他的項(xiàng)目 fork 自 stylefeng 的 Guns!開(kāi)源的世界真好,可以學(xué)到很多知識(shí)。

2、版權(quán)歸原作者所有,自己只是學(xué)習(xí)使用。跟著大佬的思路,希望自己也能變成大佬。gogogo》。。

3、目前只是一個(gè)后臺(tái)模塊,希望自己技能增強(qiáng)到一定時(shí),可以把stylefeng 的 [Guns]融合進(jìn)來(lái)。

4、note里面是自己的學(xué)習(xí)過(guò)程,菜鳥(niǎo)寫(xiě)的,不是大佬寫(xiě)的。內(nèi)容都是大佬的。

5、如有拼寫(xiě)錯(cuò)誤,還請(qǐng)見(jiàn)諒。目前的桌子不適合打字,本文只為自己記錄.

目錄

1、SpringBoot第一站:分析了啟動(dòng)類(lèi)。還有各種自動(dòng)配置的源碼點(diǎn)這里

2、SpringBoot第二站:定義了異常、注解、Node節(jié)點(diǎn)、Page點(diǎn)這里

3、SpringBoot第三站:SpringBoot數(shù)據(jù)源配置、Mybatis配置、日志記錄點(diǎn)這里

4、SpringBoot第四站:SpringBoot緩存配置、全局異常處理點(diǎn)這里

昨天看了數(shù)據(jù)源、日志記錄紙配置,我們今天再來(lái)看看緩存配置。

緩存配置

1、利用Ehcache框架對(duì)經(jīng)常調(diào)用的查詢(xún)進(jìn)行緩存,從而提高系統(tǒng)性能。還是先看接口定義,需要注意的是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 iLoaderClass);

}
--------------------------------------------------------------------------------
/**
 *  數(shù)據(jù)重載
 */
public interface ILoader {
    Object load();
}
抽象類(lèi)

接下來(lái)看下基礎(chǔ)CacheFactory,注意,這里定義成抽象的。因?yàn)槌橄箢?lèi)天生就是用來(lái)被繼承的。

那什么時(shí)候使用抽象類(lèi)和接口呢:

1、如果你擁有一些方法想讓他們中的一些默認(rèn)實(shí)現(xiàn),那么使用抽象類(lèi)。

2、如果你想實(shí)現(xiàn)多重繼承,那么你必須使用接口。由于java不支多繼承,子類(lèi)不能夠繼承多個(gè)類(lèi),但可以實(shí)現(xiàn)多個(gè)接口

3、如果基本功能在不斷改變,那么就需要使用抽象類(lèi)。如果不斷改變基本功能并且使用接口 ,那么就需要改變所有實(shí)現(xiàn)了該接口的類(lèi)。

/**
 * 緩存工廠基類(lèi)
 */
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 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,這里你自己也可以定義其他緩存工廠,擴(kuò)展的時(shí)候只要繼承BaseCacheFactory就行。

第一點(diǎn)需要注意的是這里使用了org.slf4j.LoggerFactory

第二點(diǎn)需要注意的是靜態(tài)getCacheManager()方法,這里使用了雙重檢查機(jī)制,還有延時(shí)加載(創(chuàng)建)。有沒(méi)有想起單例模式啊,直接貼一段代碼

關(guān)鍵點(diǎn)是使用了volatilesynchronized保證了可見(jiàn)性和同步性。后者可以用在方法上,代碼塊上,具體內(nèi)容看這里吧,不展開(kāi)了友情提示.

主要作用:延遲初始化降低了初始化類(lèi)或創(chuàng)建實(shí)例的開(kāi)銷(xiāo),但也增加了訪問(wèn)被延遲初始化的字段的開(kāi)銷(xiāo)。正常初始化要優(yōu)于延遲加載,

如果確實(shí)要對(duì)實(shí)例字段使用多線程的安全的延遲初始化,使用基于volatile的初始化,如果需要對(duì)靜態(tài)字段使用線程安全的初始化,則使用基于類(lèi)的初始化方案。

/**
 * 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{

}
--------------------------對(duì)比-------------------------------------------------
/**
 * Created by guo on 2018/1/29.
 * 基于類(lèi)的初始化解決方案
 */
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緩存工廠吧,重點(diǎn)是CacheManager.Spring框架底層有許多個(gè)Manager。如DataSourceTransactionManager.還有就是創(chuàng)建CacheManager的create()方法。人家也使用了雙重檢查,延遲加載。看見(jiàn)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;
        }
    }
}

這里是調(diào)用cacheManager.getCache來(lái)獲取緩存。大家還是親自看看源碼把,這里只是自己明白了討論,記錄下。

/**
 * 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("無(wú)法找到緩存 [" + cacheName + "]的配置, 使用默認(rèn)配置.");
                    cacheManager.addCacheIfAbsent(cacheName);
                    cache = cacheManager.getCache(cacheName);
                    log.debug("緩存 [" + cacheName + "] 啟動(dòng).");
                }
            }
        }
        return cache;
    }
-----------------------省略幾個(gè)----------------------------------------------
    public void put(String cacheName, Object key, Object value) {
        getOrAddCache(cacheName).put(new Element(key, value));
    }

    public  T 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);
    }
}

接著我們來(lái)看幾個(gè)常量的定義及實(shí)現(xiàn)

/**
 * 獲取被緩存的對(duì)象(用戶刪除業(yè)務(wù))
 */
String getCacheObject(String para);
-----------------------------------------------------------------------------------
/**
 * 獲取被緩存的對(duì)象(用戶刪除業(yè)務(wù))
 */
@Override
public String getCacheObject(String para) {
    return LogObjectHolder.me().get().toString();     //還有一個(gè)set()記得嗎?
}

配置完了你總的使用,看代碼。先不關(guān)注權(quán)限那塊。CacheKit是一個(gè)工具類(lèi)。

/**
 * 刪除角色
 */
@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);
    }
    //不能刪除超級(jí)管理員角色
    if(roleId.equals(Const.ADMIN_ROLE_ID)){
        throw new BussinessException(BizExceptionEnum.CANT_DELETE_ADMIN);
    }
    //緩存被刪除的角色名稱(chēng)
    LogObjectHolder.me().set(ConstantFactory.me().getSingleRoleName(roleId));
    roleService.delRoleById(roleId);
    //刪除緩存
    CacheKit.removeAll(Cache.CONSTANT);
    return SUCCESS_TIP;
}

---------------------------工具類(lèi)------------------------------------------------
/**
 * 緩存工具類(lèi)
 */
public class CacheKit {
    private static ICache defaultCacheFactory = new EhcacheFactory();    //這里創(chuàng)建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);
    }
}

到這里緩存部分算是結(jié)束了,再次說(shuō)明,只是自己記錄過(guò)程,要讓我實(shí)現(xiàn),目前不現(xiàn)實(shí),還需要自己請(qǐng)自看看源碼,跑一遍。

全局異常處理

接下來(lái),我們?cè)诳纯纯刂平y(tǒng)一的異常攔截機(jī)制。這里用到了切面的思想。第一眼看到的是@ControllerAdvice。這是什么東東,看圖說(shuō)話。GlobalExceptionHandler全部代碼點(diǎn)這里點(diǎn)這里。ResponseStatus狀態(tài)先不關(guān)注。

/**
 * 全局的的異常攔截器(攔截所有的控制器)(帶有@RequestMapping注解的方法上都會(huì)攔截)
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 攔截業(yè)務(wù)異常
     *
     * @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("業(yè)務(wù)異常:", 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";
    }


    /**
     * 攔截未知的運(yùn)行時(shí)異常
     */
    @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", "服務(wù)器未知運(yùn)行時(shí)異常");
        log.error("運(yùn)行時(shí)異常:", e);
        return new ErrorTip(BizExceptionEnum.SERVER_ERROR);
    }
}

異常處理看得也差不多了,接下來(lái)看什么好呢?持續(xù)關(guān)注,

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/68668.html

相關(guān)文章

  • 兩年了,我寫(xiě)了這些干貨!

    摘要:開(kāi)公眾號(hào)差不多兩年了,有不少原創(chuàng)教程,當(dāng)原創(chuàng)越來(lái)越多時(shí),大家搜索起來(lái)就很不方便,因此做了一個(gè)索引幫助大家快速找到需要的文章系列處理登錄請(qǐng)求前后端分離一使用完美處理權(quán)限問(wèn)題前后端分離二使用完美處理權(quán)限問(wèn)題前后端分離三中密碼加鹽與中異常統(tǒng)一處理 開(kāi)公眾號(hào)差不多兩年了,有不少原創(chuàng)教程,當(dāng)原創(chuàng)越來(lái)越多時(shí),大家搜索起來(lái)就很不方便,因此做了一個(gè)索引幫助大家快速找到需要的文章! Spring Boo...

    huayeluoliuhen 評(píng)論0 收藏0
  • 基于SpringBoot后臺(tái)管理系統(tǒng)(啟動(dòng)類(lèi)解析,開(kāi)源世界真好)(一)

    摘要:目前只是一個(gè)后臺(tái)模塊,希望自己技能增強(qiáng)到一定時(shí),可以把的融合進(jìn)來(lái)。目錄第一站,分析了啟動(dòng)類(lèi)??匆?jiàn)沒(méi),這個(gè)也是配置類(lèi),它聲明了視圖解析器地域解析器以及靜態(tài)資源的位置,想起來(lái)沒(méi),就是前置,后置。程序啟動(dòng)類(lèi)我們點(diǎn)擊源碼看看。 Guns基于SpringBoot,致力于做更簡(jiǎn)潔的后臺(tái)管理系統(tǒng),完美整合springmvc + shiro + 分頁(yè)插件PageHelper + 通用Mapper + ...

    SwordFly 評(píng)論0 收藏0
  • SpringBoot 實(shí)戰(zhàn) (十) | 統(tǒng)一處理異常

    摘要:前言如題,今天介紹是如何統(tǒng)一處理全局異常的。主要是用于異常攔截出獲取并將設(shè)置到消息類(lèi)中返回。狀態(tài)碼異常攔截類(lèi)通過(guò)加入來(lái)聲明該類(lèi)可攔截請(qǐng)求,同時(shí)在方法加入并在該注解中指定要攔截的異常類(lèi)。測(cè)試訪問(wèn)測(cè)試正常返回?cái)?shù)據(jù)結(jié)果。 微信公眾號(hào):一個(gè)優(yōu)秀的廢人如有問(wèn)題或建議,請(qǐng)后臺(tái)留言,我會(huì)盡力解決你的問(wèn)題。 前言 如題,今天介紹 SpringBoot 是如何統(tǒng)一處理全局異常的。SpringBoot 中...

    arashicage 評(píng)論0 收藏0
  • SpringBoot 仿抖音短視頻小程序開(kāi)發(fā)(三)

    摘要:仿抖音短視頻小程序開(kāi)發(fā)一項(xiàng)目的簡(jiǎn)介仿抖音短視頻小程序開(kāi)發(fā)二項(xiàng)目功能分析與具體實(shí)現(xiàn)源代碼仿抖音短視頻小程序開(kāi)發(fā)全棧式實(shí)戰(zhàn)項(xiàng)目短視頻后臺(tái)管理系統(tǒng)小程序的后臺(tái)管理系統(tǒng)涉及的技術(shù)??蚣芤挥脩袅斜淼墨@取與分頁(yè)前端代碼用戶列表展示的表格底部 SpringBoot 仿抖音短視頻小程序開(kāi)發(fā)(一):項(xiàng)目的簡(jiǎn)介(https://segmentfault.com/a/11...SpringBoot 仿抖音短...

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

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

0條評(píng)論

閱讀需要支付1元查看
<