替换Spring Boot 的EnableCaching注解
SpringBoot 中可使用@Cacheable注解来更方便的使用redis,这个注解是通过拦截器工作的,使用了@Cacheable的方法执行时,执行到CglibAopProxy.java中的 DynamicAdvisedInterceptor.intercept方法中如下图位置时,会发现CacheInterceptor:

CacheInterceptor是由EnableCaching注解引入的:

CachingConfigurationSelector:

注意上图中的ProxyCachingConfiguration:

方法的返回值如果缓存中存在直接返回缓存中结果,缓存中没有才会实际执行方法这个功能的实现就是在CacheInterceptor拦截器中了,它的invoke方法:
public Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
CacheOperationInvoker aopAllianceInvoker = new CacheOperationInvoker() {
@Override
public Object invoke() {
try {
return invocation.proceed();
}
catch (Throwable ex) {
throw new ThrowableWrapper(ex);
}
}
};
try {
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
}
catch (CacheOperationInvoker.ThrowableWrapper th) {
throw th.getOriginal();
}
}
具体读取数据在protected的execute方法中的private的execute中:
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
// Check whether aspect is enabled (to cope with cases where the AJ is pulled in automatically)
if (this.initialized) {
Class<?> targetClass = getTargetClass(target);
Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
return execute(invoker, method, new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
return invoker.invoke();
}

首先下面代码第一行findCachedItem方法判断缓存中是否有数据,然后在后面的那个判断中判断,有就取缓存并直接返回结果,不再执行被拦截方法;否则else执行被拦截方法,被拦截方法中一般就是读数据库了,不过这就和这部分没啥关系了。
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// Collect puts from any @Cacheable miss, if no cached item is found
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
}
Object cacheValue;
Object returnValue;
if (cacheHit != null && cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
// If there are no put requests, just use the cache hit
cacheValue = cacheHit.get();
returnValue = wrapCacheValue(method, cacheValue);
}
else {
// Invoke the method if we don't have a cache hit
returnValue = invokeOperation(invoker);
cacheValue = unwrapReturnValue(returnValue);
}
我这是用redis做缓存的,通过上面代码可以发现,一旦redis挂了,findCachedItem方法报异常,被拦截的方法就不能正常使用了,那么我需要redis出异常了,正常走数据库该怎么办呢。我首先考虑的是重写protected的那个execute方法,然而发现有一个private的内部类绕不过去,全都自己实现一遍,完全没必要,因为懒得细调了于是我就新建了一个拦截器,继承CacheInterceptor:
@Override
protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
try {
return super.execute(invoker, target, method, args);
}catch (Exception e){
return invokeOperation(invoker);
}
}
然后就是让新拦截器起作用,我讨厌SpringBoot的注解就讨厌在这部分。如果还用EnableCaching注解这问题就复杂了,于是简单粗暴新建注解代替EnableCaching,然后CachingConfigurationSelector也需要替换掉。接着是ProxyCachingConfiguration以及它的基类AbstractCachingConfiguration:

重写这个方法,用新建的注解替换掉方法中的EnableCaching就可以了,由于用的是线上代码测试的就不好往这贴了,不过亲测成功,虽然方法比较粗糙,但是SpringBoot里的代码留的扩展余地就那样,也不想太费工夫了。
==========================================================
咱最近用的github:https://github.com/saaavsaaa
微信公众号:
替换Spring Boot 的EnableCaching注解的更多相关文章
- spring boot @ConditionalOnxxx相关注解总结
Spring boot @ConditionalOnxxx相关注解总结 下面来介绍如何使用@Condition public class TestCondition implements Condit ...
- Spring boot 使用的注解有哪些?
Spring boot 使用的注解有哪些? 注解 作用 @SpringBootApplication 等价于 @Configuration + @EnableAutoConfiguration + @ ...
- (32)Spring Boot使用@SpringBootApplication注解,从零开始学Spring Boot
[来也匆匆,去也匆匆,在此留下您的脚印吧,转发点赞评论] 如果看了我之前的文章,这个节你就可以忽略了,这个是针对一些刚入门的选手存在的困惑进行写的一篇文章. 很多Spring Boot开发者总是使用 ...
- Spring Boot 二十个注解
Spring Boot 二十个注解 占据无力拥有的东西是一种悲哀. Cold on the outside passionate on the insede. 背景:Spring Boot 注解的强大 ...
- spring boot 中@Autowired注解无法自动注入的错误
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/huihuilovei/article/de ...
- Spring Boot中@Scheduled注解的使用方法
Spring Boot中@Scheduled注解的使用方法 一.定时任务注解为@Scheduled,使用方式举例如下 //定义一个按时间执行的定时任务,在每天16:00执行一次. @Scheduled ...
- Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解: @SpringBootConfiguration:组合了 ...
- Spring Boot Web 开发注解篇
本文提纲 1. spring-boot-starter-web 依赖概述 1.1 spring-boot-starter-web 职责 1.2 spring-boot-starter-web 依赖关系 ...
- 读懂这些spring boot的核心注解,快速配置完成项目搭建
在spring boot中,摒弃了spring以往项目中大量繁琐的配置,遵循约定大于配置的原则,通过自身默认配置,极大的降低了项目搭建的复杂度.同样在spring boot中,大量注解的使用,使得代码 ...
随机推荐
- Bottle源码阅读笔记(二):路由
前言 程序收到请求后,会根据URL来寻找相应的视图函数,随后由其生成页面发送回给客户端.其中,不同的URL对应着不同的视图函数,这就存在一个映射关系.而处理这个映射关系的功能就叫做路由.路由的实现分为 ...
- python爬虫之re正则表达式库
python爬虫之re正则表达式库 正则表达式是用来简洁表达一组字符串的表达式. 编译:将符合正则表达式语法的字符串转换成正则表达式特征 操作符 说明 实例 . 表示任何单个字符 [ ] 字符集,对单 ...
- AS3批量替换文件
在做项目时,经过会遇到资源替换问题.比如配音公司,提供了一批八九百个配音MP3文件,用到后面却发现有些配音不能正常使用.可能是十几个,也可能是一两百个.只能是配音公司重新提供.因为之前的配音资源,已经 ...
- 前端学习数据库MYSQL
这篇文章主要写了 1.数据库MYSQL 2.基本上会遇到的所有SQL语句 数据库可视化软件------Navicat 数据库里边存放的是表,表与表之间是有关联的,而且可以对表进行相关操作(增,删,改, ...
- 二叉树问题(区间DP好题)
二叉树问题 时间限制: 1 Sec 内存限制: 128 MB 题目描述 Petya Bulochkin很幸运:他得到了一份在"Macrohard"公司的工作.他想要展现他的才华, ...
- 详解ES6中的 let 和const
前 言 JRedu ECMAScript 6 是 JavaScript 语言教程,全面介绍 ECMAScript 6 新引入的语法特性. ES6 与上一个版本 ES5 的所有不同之处,对涉及的语 ...
- 如何使用Node.js编写命令工具——以vue-cli为例
vue-cli全局安装之后,提供了vue命令和vue init.vue list.vue build三个子命令,通过命令可以搭建基于vue.js的脚手架项目.本文简单介绍一下这些命令是如何实现的. v ...
- java如何LOG打印出日志信息
log4j 记录日志方式 log4j 是apache 提供的记录日志的jar 档. 下载路径: http://logging.apache.org/log4j/1.2/download.html 这里 ...
- 打开vmvare出现The VMware Authorization Service is not running。
win+r再输入cmd打开doc,输入services.msc打开服务,吧Vmware Authorization Service 更改为自动或者将其启动即可.
- Spring (3.2.4) 常用jar 包解析
Spring (3.2.4) 常用jar 包解析 基本jar包 spring-aop-3.2.4.RELEASE.jar spring-aspects-3.2.4.RELEASE.jar spring ...