若是您有幸能看到,请认阅读如下内容;html
昨天看了数据源、日志记录纸配置,咱们今天再来看看缓存配置。java
一、利用Ehcache框架对常常调用的查询进行缓存,从而提升系统性能。仍是先看接口定义,须要注意的是get()方法使用了泛型<T>.git
/** * 通用缓存接口 */ 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,注意,这里定义成抽象的。由于抽象类天生就是用来被继承的。github
那何时使用抽象类和接口呢:缓存
/** * 缓存工厂基类 */ 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
保证了可见性和同步性。后者能够用在方法上,代码块上,具体内容看这里吧,不展开了友情提示.app
主要做用:延迟初始化下降了初始化类或建立实例的开销,但也增长了访问被延迟初始化的字段的开销。正常初始化要优于延迟加载,框架
若是确实要对实例字段使用多线程的安全的延迟初始化,使用基于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) @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); } }
异常处理看得也差很少了,接下来看什么好呢?持续关注,