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()方法使用了泛型<T>.

/*** 通用缓存接口*/
public interface ICache {void put(String cacheName, Object key, Object value);<T> T get(String cacheName, Object key);@SuppressWarnings("rawtypes")List getKeys(String cacheName);void remove(String cacheName, Object key);void removeAll(String cacheName);<T> T get(String cacheName, Object key, ILoader iLoader);<T> 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> T get(String cacheName, Object key, ILoader iLoader) {..略..}@SuppressWarnings("unchecked")public <T> 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()方法,这里使用了双重检查机制,还有延时加载(创建)。有没有想起单例模式啊,直接贴一段代码

关键点是使用了volatilesynchronized保证了可见性和同步性。后者可以用在方法上,代码块上,具体内容看这里吧,不展开了友情提示.

主要作用:延迟初始化降低了初始化类或创建实例的开销,但也增加了访问被延迟初始化的字段的开销。正常初始化要优于延迟加载,

如果确实要对实例字段使用多线程的安全的延迟初始化,使用基于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));}public <T> 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);}
}

接着我们来看几个常量的定义及实现

/*** 获取被缓存的对象(用户删除业务)*/
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)@ResponseBodypublic 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)@ResponseBodypublic 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);}
}

异常处理看得也差不多了,接下来看什么好呢?持续关注,

基于SpringBoot的后台管理系统(Encache配置、全局异常处理(重点))(四)相关推荐

  1. 基于SpringBoot的后台管理系统(启动类解析,开源的世界真好)(一)

    Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + 分页插件PageHelper + 通用Mapper + beetl!Guns项目代码简洁 ...

  2. 主流的基于SpringBoot的后台管理系统

    项目介绍 一款 Java 语言基于 SpringBoot2.x.Layui.Thymeleaf.MybatisPlus.Shiro.MySQL等框架精心打造的一款模块化.插件化.高性能的前后端分离架构 ...

  3. 基于SpringBoot的后台管理系统(异常、注解、node、page)(二)

    common.exception.annotation.node.page 说明 如果您有幸能看到,请认阅读以下内容: 1.本项目临摹自abel533的Guns,他的项目 fork 自 stylefe ...

  4. 基于jsp+SpringBoot美容院后台管理系统

    <基于jsp+mysql+mybatis的SpringBoot美容院后台管理系统>该项目采用技术HTML+CSS+JavaScript+jsp+mysql+mybatis+layui+ma ...

  5. 基于SpringBoot的毕业论文管理系统的设计与实现(开题报告)

    基于Spring Boot的毕业论文管理系统 研究的背景与意义 随着信息化时代的到来,高校的管理工作也面临着信息化改革.目前,各大高校纷纷引入教务管理信息系统来加强和改善对学生.教师以及各种教务信息的 ...

  6. 基于SpringBoot的房屋租赁管理系统的设计与实现

    基于SpringBoot的房屋租赁管理系统的设计与实现 1 绪论 1.1 课题来源 随着社会的不断发展以及大家生活水平的提高,越来越多的年轻人选择在大城市发展.在大城市发展就意味着要在外面有一处安身的 ...

  7. Springboot毕设项目基于SpringBoot的房源管理系统lyh88(java+VUE+Mybatis+Maven+Mysql)

    Springboot毕设项目基于SpringBoot的房源管理系统lyh88(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + ...

  8. java计算机毕业设计基于springboot小区物业管理系统

    项目介绍 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势:对于小区物业管理系统当然也不能排除在外,随着网络技术的不断成熟,带动了小区物业管理系统,它彻底改变了过 ...

  9. 基于SpringBoot的图书管理系统[毕业设计]

    基于SpringBoot的图书管理系统[毕业设计] 前言 该图书管理系统是基于SpringBoot的项目,包含源码和非正式论文,下载地址: https://download.csdn.net/down ...

  10. 基于SpringBoot医院信息管理系统源码

    hisystem 1. 用idea打开项目,并且配置maven下载依赖 2. 导入数据库 hisystem.sql 3. 修改application.yml数据库相关配置 4. 用户注册,验证邮件的邮 ...

最新文章

  1. python对文件的读操作有哪些方法-Python中文件的读取和写入操作
  2. nginx 安装及使用命令
  3. 360公布权威机构对扣扣保镖的测试报告
  4. 1295 N皇后问题
  5. 通过听力写代码?盲人程序员就是这样做的
  6. 杀不死的人狼——我读《人月神话》(四)
  7. CodeBlocks13.12汉化以及去掉注释及字符串的下划线
  8. Qt 之 QPainter
  9. Gentoo Linux安装教程20220218(长期更新维护)
  10. 使用TMS320F28335控制四位共阳数码管
  11. python ppt自动生成_实战 | Python自动生成PPT调研报告
  12. 基于chatgpt开发QQ机器人
  13. 面试成功一个公司,微信上HR和我谈好了薪资和入职日期。却不发offer。这种企业值得去吗?
  14. vscode代码提示出来慢
  15. Sublime插件安装
  16. 【成神之路】Http网络相关面试题
  17. gitbook 插件 主题
  18. 自己动手搭建恶意软件样本行为分析环境
  19. php删除文件夹函数,PHP 删除文件与文件夹操作 unlink()与rmdir()这两个函数的使用...
  20. 熟练使用计算机的意思,熟练使用是什么意思

热门文章

  1. Laravel 5.4 api 允许跨域访问
  2. Win8(X64)下MySQL5.6版本安装及配置
  3. 我的PDF阅读器之muPDF的编译
  4. 转载]转如何理解 File's Owner 与 First Responder
  5. 第二章 驱动程序调测方法与技巧
  6. DLL错误之——无法加载DLL***.dll:找不到指定的模块(异常来自HRESULT:0x8007007E)问题的终极感悟
  7. Android studio 设置函数功能悬浮提示(鼠标放到上班提示参数和功能)
  8. python怎么替换主干网络_无法将关键字“model”解析到字段中。活塞主干网.js
  9. 推荐系统中的矩阵分解详解
  10. java 不以科学记数法输出double