基于SpringBoot的后台管理系统(Encache配置、全局异常处理(重点))(四)
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()
方法,这里使用了双重检查机制,还有延时加载(创建)。有没有想起单例模式啊,直接贴一段代码
关键点是使用了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));}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配置、全局异常处理(重点))(四)相关推荐
- 基于SpringBoot的后台管理系统(启动类解析,开源的世界真好)(一)
Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + 分页插件PageHelper + 通用Mapper + beetl!Guns项目代码简洁 ...
- 主流的基于SpringBoot的后台管理系统
项目介绍 一款 Java 语言基于 SpringBoot2.x.Layui.Thymeleaf.MybatisPlus.Shiro.MySQL等框架精心打造的一款模块化.插件化.高性能的前后端分离架构 ...
- 基于SpringBoot的后台管理系统(异常、注解、node、page)(二)
common.exception.annotation.node.page 说明 如果您有幸能看到,请认阅读以下内容: 1.本项目临摹自abel533的Guns,他的项目 fork 自 stylefe ...
- 基于jsp+SpringBoot美容院后台管理系统
<基于jsp+mysql+mybatis的SpringBoot美容院后台管理系统>该项目采用技术HTML+CSS+JavaScript+jsp+mysql+mybatis+layui+ma ...
- 基于SpringBoot的毕业论文管理系统的设计与实现(开题报告)
基于Spring Boot的毕业论文管理系统 研究的背景与意义 随着信息化时代的到来,高校的管理工作也面临着信息化改革.目前,各大高校纷纷引入教务管理信息系统来加强和改善对学生.教师以及各种教务信息的 ...
- 基于SpringBoot的房屋租赁管理系统的设计与实现
基于SpringBoot的房屋租赁管理系统的设计与实现 1 绪论 1.1 课题来源 随着社会的不断发展以及大家生活水平的提高,越来越多的年轻人选择在大城市发展.在大城市发展就意味着要在外面有一处安身的 ...
- Springboot毕设项目基于SpringBoot的房源管理系统lyh88(java+VUE+Mybatis+Maven+Mysql)
Springboot毕设项目基于SpringBoot的房源管理系统lyh88(java+VUE+Mybatis+Maven+Mysql) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + ...
- java计算机毕业设计基于springboot小区物业管理系统
项目介绍 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势:对于小区物业管理系统当然也不能排除在外,随着网络技术的不断成熟,带动了小区物业管理系统,它彻底改变了过 ...
- 基于SpringBoot的图书管理系统[毕业设计]
基于SpringBoot的图书管理系统[毕业设计] 前言 该图书管理系统是基于SpringBoot的项目,包含源码和非正式论文,下载地址: https://download.csdn.net/down ...
- 基于SpringBoot医院信息管理系统源码
hisystem 1. 用idea打开项目,并且配置maven下载依赖 2. 导入数据库 hisystem.sql 3. 修改application.yml数据库相关配置 4. 用户注册,验证邮件的邮 ...
最新文章
- python对文件的读操作有哪些方法-Python中文件的读取和写入操作
- nginx 安装及使用命令
- 360公布权威机构对扣扣保镖的测试报告
- 1295 N皇后问题
- 通过听力写代码?盲人程序员就是这样做的
- 杀不死的人狼——我读《人月神话》(四)
- CodeBlocks13.12汉化以及去掉注释及字符串的下划线
- Qt 之 QPainter
- Gentoo Linux安装教程20220218(长期更新维护)
- 使用TMS320F28335控制四位共阳数码管
- python ppt自动生成_实战 | Python自动生成PPT调研报告
- 基于chatgpt开发QQ机器人
- 面试成功一个公司,微信上HR和我谈好了薪资和入职日期。却不发offer。这种企业值得去吗?
- vscode代码提示出来慢
- Sublime插件安装
- 【成神之路】Http网络相关面试题
- gitbook 插件 主题
- 自己动手搭建恶意软件样本行为分析环境
- php删除文件夹函数,PHP 删除文件与文件夹操作 unlink()与rmdir()这两个函数的使用...
- 熟练使用计算机的意思,熟练使用是什么意思
热门文章
- Laravel 5.4 api 允许跨域访问
- Win8(X64)下MySQL5.6版本安装及配置
- 我的PDF阅读器之muPDF的编译
- 转载]转如何理解 File's Owner 与 First Responder
- 第二章 驱动程序调测方法与技巧
- DLL错误之——无法加载DLL***.dll:找不到指定的模块(异常来自HRESULT:0x8007007E)问题的终极感悟
- Android studio 设置函数功能悬浮提示(鼠标放到上班提示参数和功能)
- python怎么替换主干网络_无法将关键字“model”解析到字段中。活塞主干网.js
- 推荐系统中的矩阵分解详解
- java 不以科学记数法输出double