栗子
// 配置类
@Configuration
@EnableCaching
public static class Spr11124Config {
// 注入 CacheManager
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
// 注入业务类TestService
@Bean
public TestService service() {
return new TestServiceImpl();
}
}
// 业务接口
public interface TestService {
int single(int id);
}
// 业务实现类
public static class TestServiceImpl implements TestService {
@Override
@Cacheable("smallCache")
public int single(int id) {
System.out.println("执行逻辑。。。");
return id;
}
}
@Test
public void spr11124MultipleAnnotations2() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);
TestService bean = context.getBean(TestService.class);
System.out.println(bean.single(2));
System.out.println(bean.single(2));
context.close();
}
执行结果:
System.out.println("执行逻辑。。。"); 只执行了一次,说明第二次走了缓存。
缓存包类成员介绍
源码分析
实例化bean
@EnableCaching 注解
类介绍
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
/**
是否要创建基于子类 (CGLIB) 的代理,而不是创建标准的基于 Java 接口的代理。
默认值为false 。仅当mode()设置为AdviceMode.PROXY 。
请注意,将此属性设置为true将影响所有需要代理的 Spring 管理的 bean,
而不仅仅是标记有@Cacheable的那些。
例如,其他标有 Spring 的@Transactional注解的 bean 将同时升级为子类代理。
这种方法在实践中没有负面影响,除非明确期望一种类型的代理与另一种类型的代理,例如在测试中。
*/
boolean proxyTargetClass() default false;
/**
* 指示应如何应用缓存建议。
默认值为AdviceMode.PROXY 。请注意,代理模式只允许通过代理拦截呼叫。同一类中的本地调用不能以这种方式被拦截;
本地调用中此类方法上的缓存注释将被忽略,因为 Spring 的拦截器甚至不会在此类运行时场景中启动。
对于更高级的拦截模式,请考虑将其切换为AdviceMode.ASPECTJ 。
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* 当在特定连接点应用多个建议时,指示缓存顾问的执行顺序。
默认值为Ordered.LOWEST_PRECEDENCE 。
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
该注解标识当前开启springcache功能。
boolean proxyTargetClass() default false; true:使用CGLIB代理模式;--false:使用JDK动态代理(默认)。
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
源码解析
@EnableCaching 注解上有 @Import(CachingConfigurationSelector.class)
@import注解作用是向IOC容器中注入bean,也就是将CachingConfigurationSelector注入,相当于给CachingConfigurationSelector加上@component注解。
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
private static final String PROXY_JCACHE_CONFIGURATION_CLASS =
"org.springframework.cache.jcache.config.ProxyJCacheConfiguration";
private static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJCachingConfiguration";
private static final String JCACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJJCacheConfiguration";
private static final boolean jsr107Present;
private static final boolean jcacheImplPresent;
static {
ClassLoader classLoader = CachingConfigurationSelector.class.getClassLoader();
jsr107Present = ClassUtils.isPresent("javax.cache.Cache", classLoader);
jcacheImplPresent = ClassUtils.isPresent(PROXY_JCACHE_CONFIGURATION_CLASS, classLoader);
}
/**
* Returns {@link ProxyCachingConfiguration} or {@code AspectJCachingConfiguration}
* for {@code PROXY} and {@code ASPECTJ} values of {@link EnableCaching#mode()},
* respectively. Potentially includes corresponding JCache configuration as well.
*/
@Override
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return getProxyImports();
case ASPECTJ:
return getAspectJImports();
default:
return null;
}
}
/**
* Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#PROXY}.
* <p>Take care of adding the necessary JSR-107 import if it is available.
*/
private String[] getProxyImports() {
List<String> result = new ArrayList<>(3);
// 注册aop的入口类InfrastructureAdvisorAutoProxyCreator
result.add(AutoProxyRegistrar.class.getName());
// 配置类
result.add(ProxyCachingConfiguration.class.getName());
if (jsr107Present && jcacheImplPresent) {
result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
}
return StringUtils.toStringArray(result);
}
/**
* Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#ASPECTJ}.
* <p>Take care of adding the necessary JSR-107 import if it is available.
*/
private String[] getAspectJImports() {
List<String> result = new ArrayList<>(2);
result.add(CACHE_ASPECT_CONFIGURATION_CLASS_NAME);
if (jsr107Present && jcacheImplPresent) {
result.add(JCACHE_ASPECT_CONFIGURATION_CLASS_NAME);
}
return StringUtils.toStringArray(result);
}
}
30 行:当该类被转换为BeanDefinition时,会调用 selectImports(),该类将需要注入的类的类名存储到数组中并返回。adviceMode 默认为“PROXY”,转掉getProxyImports()
45 行:需要把 AutoProxyRegistrar.class、ProxyCachingConfiguration.class 交给IOC管理
ProxyCachingConfiguration.class
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
// 注册Advisor
@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() {
BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
// AnnotationCacheOperationSource
advisor.setCacheOperationSource(cacheOperationSource());
// CacheInterceptor 属性CacheOperationSource = AnnotationCacheOperationSource
advisor.setAdvice(cacheInterceptor());
if (this.enableCaching != null) {
advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
}
return advisor;
}
// 切点 AnnotationCacheOperationSource
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheOperationSource cacheOperationSource() {
return new AnnotationCacheOperationSource();
}
// 增强 CacheInterceptor
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheInterceptor cacheInterceptor() {
CacheInterceptor interceptor = new CacheInterceptor();
interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
interceptor.setCacheOperationSource(cacheOperationSource());
return interceptor;
}
}
@Configuration类,用于注册缓存管理所需的 bean。就是把springcache功能需要的bean注入到IOC容器。
spring大多高级功能都是基于Aop实现的,而Aop又是根据动态代理实现的,使用Aop就需要定义Adviser,一个Adviser包含切点(PointCut)、增强(Advice)。cacheAdvisor():注册advisor BeanFactoryCacheOperationSourceAdvisor,并调用 cacheOperationSource() 和 cacheInterceptor() 设置切点和增强。
cacheOperationSource():注册切点,类型就是 AnnotationCacheOperationSource实现了CacheOperationSource接口。
24 行:创建的时候干了一些事情(见图1):
- 设置本类属性 boolean publicMethodsOnly 为 true(后面会用到)。
- 设置本类属性 Set annotationParsers 为 Collections.singleton(new SpringCacheAnnotationParser()),SpringCacheAnnotationParser 类就是用来解析方法上是否有缓存注解的,静态属性设置了注解操作信息。
cacheInterceptor():注册增强 CacheInterceptor(缓存操作就在这里面了)。
31 行:创建一个CacheInterceptor 对象。 32 行:进行一些初始化设置
- errorHandler = SimpleCacheErrorHandler
- keyGenerator = SimpleKeyGenerator
- cacheResolver = SimpleCacheResolver
33 行:设置缓存操作源,和上面设置切点一样
public abstract class CacheAspectSupport extends AbstractCacheInvoker
implements BeanFactoryAware, InitializingBean, SmartInitializingSingleton {
protected final Log logger = LogFactory.getLog(getClass());
private final Map<CacheOperationCacheKey, CacheOperationMetadata> metadataCache = new ConcurrentHashMap<>(1024);
private final CacheOperationExpressionEvaluator evaluator = new CacheOperationExpressionEvaluator();
@Nullable
private CacheOperationSource cacheOperationSource;
private SingletonSupplier<KeyGenerator> keyGenerator = SingletonSupplier.of(SimpleKeyGenerator::new);
@Nullable
private SingletonSupplier<CacheResolver> cacheResolver;
@Nullable
private BeanFactory beanFactory;
private boolean initialized = false;
/**
* Configure this aspect with the given error handler, key generator and cache resolver/manager
* suppliers, applying the corresponding default if a supplier is not resolvable.
* @since 5.1
*/
public void configure(
@Nullable Supplier<CacheErrorHandler> errorHandler, @Nullable Supplier<KeyGenerator> keyGenerator,
@Nullable Supplier<CacheResolver> cacheResolver, @Nullable Supplier<CacheManager> cacheManager) {
this.errorHandler = new SingletonSupplier<>(errorHandler, SimpleCacheErrorHandler::new);
this.keyGenerator = new SingletonSupplier<>(keyGenerator, SimpleKeyGenerator::new);
this.cacheResolver = new SingletonSupplier<>(cacheResolver,
() -> SimpleCacheResolver.of(SupplierUtils.resolve(cacheManager)));
}
/**
* Set the CacheOperationSource for this cache aspect.
* @since 5.1
* @see #setCacheOperationSources
*/
public void setCacheOperationSource(@Nullable CacheOperationSource cacheOperationSource) {
this.cacheOperationSource = cacheOperationSource;
}
}
CacheInterceptor
CacheInterceptor 实现了 SmartInitializingSingleton 接口,实现该接口的类在bean实例化之后会调用afterSingletonsInstantiated()
@Override
public void afterSingletonsInstantiated() {
if (getCacheResolver() == null) {
// Lazily initialize cache resolver via default cache manager...
Assert.state(this.beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
try {
setCacheManager(this.beanFactory.getBean(CacheManager.class));
}
catch (NoUniqueBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no unique bean of type " +
"CacheManager found. Mark one as primary or declare a specific CacheManager to use.");
}
catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException("No CacheResolver specified, and no bean of type CacheManager found. " +
"Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.");
}
}
this.initialized = true;
}
public void setCacheManager(CacheManager cacheManager) {
this.cacheResolver = SingletonSupplier.of(new SimpleCacheResolver(cacheManager));
}
7 行:设置CacheManager。从IOC容器中获取到CacheManager,然后作为入参创建SimpleCacheResolver 并赋值给本类的cacheResolver属性。
业务类
// 配置类
@Configuration
@EnableCaching
public static class Spr11124Config {
// 注入 CacheManager
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
// 注入业务类TestService
@Bean
public TestService service() {
return new TestServiceImpl();
}
}
// 业务接口
public interface TestService {
int single(int id);
}
// 业务实现类
public static class TestServiceImpl implements TestService {
@Override
@Cacheable("smallCache")
public int single(int id) {
System.out.println("执行逻辑。。。");
return id;
}
}
@Test
public void spr11124MultipleAnnotations2() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);
TestService bean = context.getBean(TestService.class);
System.out.println(bean.single(2));
System.out.println(bean.single(2));
context.close();
}
bean实例化之后会进入aop创建代理逻辑,通过IOC中所有的Advisor 的 切点进行匹配,如果当前bean匹配成功,就会创建代理。
业务类 TestServiceImpl 在实例化之后,在进行Advisor匹配时,会被上面创建的BeanFactoryCacheOperationSourceAdvisor匹配到。匹配流程如下:
这一块属于Aop源码,这里不详细说明,只列出大致逻辑。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//调用ClassFilter的matches方法,判断类是否匹配
//通过AspectJ 类级别过滤
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
//方法级别过滤,精筛
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
// 只有AspectJExcpressionPointcut才会实现这个接口
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
// 保存 tagetClass 的 class对象
Set<Class<?>> classes = new LinkedHashSet<>();
// 判断当前class是不是代理的class
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
// 获取到当前class实现的接口 的 class对象(@AspectJ 注解没有,事务有用)
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//判断类中方法是否匹配,,有些可能是方法上面有注解的拦截,所以需要判断方法是否匹配
// 循环所有的class
for (Class<?> clazz : classes) {
// 找出class中所有的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
// 通过切点表达式进行匹配 AspectJ 方式
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
// 通过方法匹配器进行匹配,内置aop接口方式
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
37 行:调用Advisor.Pointcut#matches(),如下代码:
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
// 切点 AnnotationCacheOperationSource
@Nullable
private CacheOperationSource cacheOperationSource;
// 增强 CacheInterceptor
private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {
@Override
@Nullable
protected CacheOperationSource getCacheOperationSource() {
return cacheOperationSource;
}
};
...
}
8 行:pointcut 是 CacheOperationSourcePointcut 类型,如下代码
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected CacheOperationSourcePointcut() {
setClassFilter(new CacheOperationSourceClassFilter());
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
CacheOperationSource cas = getCacheOperationSource();
return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
}
...
@Nullable
protected abstract CacheOperationSource getCacheOperationSource();
...
}
9 行:matches() 就是具体匹配切点的逻辑。
10 行:首先获取CacheOperationSource,转调getCacheOperationSource(),这个方法是个抽象方法,具体实现在上面 BeanFactoryCacheOperationSourceAdvisor.pointcut 属性赋值的地方,最终返回的是BeanFactoryCacheOperationSourceAdvisor.cacheOperationSource属性的值,这个属性在上面讲实例化该bean的时候就已经赋值了--AnnotationCacheOperationSource
11 行:然后再调用AnnotationCacheOperationSource.getCacheOperations(),这个方法是父类AbstractFallbackCacheOperationSource的方法,如下代码:
public abstract class AbstractFallbackCacheOperationSource implements CacheOperationSource {
private static final Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
protected final Log logger = LogFactory.getLog(getClass());
// CacheOperation 缓存
private final Map<Object, Collection<CacheOperation>> attributeCache =
new ConcurrentHashMap<>(1024);
/**
* Determine the caching attribute for this method invocation.
* <p>Defaults to the class's caching attribute if no method attribute is found.
* @param method the method for the current invocation (never {@code null})
* @param targetClass the target class for this invocation (may be {@code null})
* @return {@link CacheOperation} for this method, or {@code null} if the method
* is not cacheable
*/
@Override
@Nullable
public Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 根据方法和目标类 生成缓存key
Object cacheKey = getCacheKey(method, targetClass);
// 先从缓存获取
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
if (cached != null) {
return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
}
else {
// 找出方法的缓存注解并生成CacheOperation,一个注解对应一个CacheOperation
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
if (cacheOps != null) {
if (logger.isTraceEnabled()) {
logger.trace("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
}
// 放入缓存中
this.attributeCache.put(cacheKey, cacheOps);
}
else {
// 放入缓存中,默认值
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
return cacheOps;
}
}
// 生成缓存key
protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
return new MethodClassKey(method, targetClass);
}
@Nullable
private Collection<CacheOperation> computeCacheOperations(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
// 方法不是public 修饰的,直接返回null
// allowPublicMethodsOnly() 默认为FALSE,AnnoXXX重写方法为true
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
Collection<CacheOperation> opDef = findCacheOperations(specificMethod);
if (opDef != null) {
return opDef;
}
// Second try is the caching operation on the target class.
opDef = findCacheOperations(specificMethod.getDeclaringClass());
if (opDef != null && ClassUtils.isUserLevelMethod(method)) {
return opDef;
}
if (specificMethod != method) {
// Fallback is to look at the original method.
opDef = findCacheOperations(method);
if (opDef != null) {
return opDef;
}
// Last fallback is the class of the original method.
opDef = findCacheOperations(method.getDeclaringClass());
if (opDef != null && ClassUtils.isUserLevelMethod(method)) {
return opDef;
}
}
return null;
}
// 抽象方法 被 AnnotationCacheOperationSource 实现
@Nullable
protected abstract Collection<CacheOperation> findCacheOperations(Method method);
// 被 AnnotationCacheOperationSource 重写,返回为true
protected boolean allowPublicMethodsOnly() {
return false;
}
...
}
21 行:如果是Object类的方法就跳过。
25 行:根据类和方法生成一个Key值。
27 行:先从缓存中获取。
34 行:第一次拿不到走生成逻辑,转调 computeCacheOperations() 整个方法尝试好几次调用findCacheOperations()获取CacheOperation ,findCacheOperations() 是抽象方法,被 AnnotationCacheOperationSource 实现,代码如下:
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {
private final boolean publicMethodsOnly;
private final Set<CacheAnnotationParser> annotationParsers;
@Override
@Nullable
protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
return determineCacheOperations(parser -> parser.parseCacheAnnotations(clazz));
}
@Override
@Nullable
protected Collection<CacheOperation> findCacheOperations(Method method) {
return determineCacheOperations(parser -> parser.parseCacheAnnotations(method));
}
}
转调 SpringCacheAnnotationParser.parseCacheAnnotations(),这个类上面提到过。代码如下:
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {
private static final Set<Class<? extends Annotation>> CACHE_OPERATION_ANNOTATIONS = new LinkedHashSet<>(8);
static {
CACHE_OPERATION_ANNOTATIONS.add(Cacheable.class);
CACHE_OPERATION_ANNOTATIONS.add(CacheEvict.class);
CACHE_OPERATION_ANNOTATIONS.add(CachePut.class);
CACHE_OPERATION_ANNOTATIONS.add(Caching.class);
}
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, CACHE_OPERATION_ANNOTATIONS);
}
@Override
@Nullable
public Collection<CacheOperation> parseCacheAnnotations(Class<?> type) {
DefaultCacheConfig defaultConfig = new DefaultCacheConfig(type);
return parseCacheAnnotations(defaultConfig, type);
}
@Override
@Nullable
public Collection<CacheOperation> parseCacheAnnotations(Method method) {
DefaultCacheConfig defaultConfig = new DefaultCacheConfig(method.getDeclaringClass());
return parseCacheAnnotations(defaultConfig, method);
}
@Nullable
private Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
// 解析缓存注解
// 把方法上面的缓存注解找出来 生成CacheOperation
Collection<CacheOperation> ops = parseCacheAnnotations(cachingConfig, ae, false);
if (ops != null && ops.size() > 1) {
// More than one operation found -> local declarations override interface-declared ones...
Collection<CacheOperation> localOps = parseCacheAnnotations(cachingConfig, ae, true);
if (localOps != null) {
return localOps;
}
}
return ops;
}
@Nullable
private Collection<CacheOperation> parseCacheAnnotations(
DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) {
// 获取方法所有注解
Collection<? extends Annotation> anns = (localOnly ?
AnnotatedElementUtils.getAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS) :
AnnotatedElementUtils.findAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS));
if (anns.isEmpty()) {
return null;
}
// 如果是缓存的注解,生成CacheOperation
final Collection<CacheOperation> ops = new ArrayList<>(1);
anns.stream().filter(ann -> ann instanceof Cacheable).forEach(
ann -> ops.add(parseCacheableAnnotation(ae, cachingConfig, (Cacheable) ann)));
anns.stream().filter(ann -> ann instanceof CacheEvict).forEach(
ann -> ops.add(parseEvictAnnotation(ae, cachingConfig, (CacheEvict) ann)));
anns.stream().filter(ann -> ann instanceof CachePut).forEach(
ann -> ops.add(parsePutAnnotation(ae, cachingConfig, (CachePut) ann)));
anns.stream().filter(ann -> ann instanceof Caching).forEach(
ann -> parseCachingAnnotation(ae, cachingConfig, (Caching) ann, ops));
return ops;
}
private CacheOperation parsePutAnnotation(
AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) {
CachePutOperation.Builder builder = new CachePutOperation.Builder();
builder.setName(ae.toString());
builder.setCacheNames(cachePut.cacheNames());
builder.setCondition(cachePut.condition());
builder.setUnless(cachePut.unless());
builder.setKey(cachePut.key());
builder.setKeyGenerator(cachePut.keyGenerator());
builder.setCacheManager(cachePut.cacheManager());
builder.setCacheResolver(cachePut.cacheResolver());
defaultConfig.applyDefault(builder);
CachePutOperation op = builder.build();
validateCacheOperation(ae, op);
return op;
}
}
parseCacheAnnotations()有4个重载,最终会调用到
parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly)
51 行:获取方法上面的注解。
58~67 行:判断这些注解是不是缓存注解,如果是,就调用对应方法创建CacheableOperation并返回。 这个地方如果返回CacheableOperation不为空,那就是切点匹配到了,先将CacheableOperation放入缓存,然后再给bean创建代理。
缓存流程
缓存需要的bean都已经注册到IOC容器了,此时IOC容器中存储的是业务类的代理类,当调用业务类的方法时,会被advisor(BeanFactoryCacheOperationSourceAdvisor)拦截,最终会调用到BeanFactoryCacheOperationSourceAdvisor 的增强也就是 CacheInterceptor 中,
// 配置类
@Configuration
@EnableCaching
public static class Spr11124Config {
// 注入 CacheManager
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
// 注入业务类TestService
@Bean
public TestService service() {
return new TestServiceImpl();
}
}
// 业务接口
public interface TestService {
int single(int id);
}
// 业务实现类
public static class TestServiceImpl implements TestService {
@Override
@Cacheable("smallCache")
public int single(int id) {
System.out.println("执行逻辑。。。");
return id;
}
}
@Test
public void spr11124MultipleAnnotations2() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);
TestService bean = context.getBean(TestService.class);
System.out.println(bean.single(2));
System.out.println(bean.single(2));
context.close();
}
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor {
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
CacheOperationInvoker aopAllianceInvoker = () -> {
try {
return invocation.proceed();
}
catch (Throwable ex) {
throw new CacheOperationInvoker.ThrowableWrapper(ex);
}
};
try {
// 执行缓存操作
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
}
catch (CacheOperationInvoker.ThrowableWrapper th) {
throw th.getOriginal();
}
}
}
@Nullable
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);
// 缓存操作源 AnnotationCacheOperationSource
CacheOperationSource cacheOperationSource = getCacheOperationSource();
if (cacheOperationSource != null) {
// 获取当前方法缓存注解信息,缓存操作对象CacheOperation 存储了缓存注解的信息
Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
return execute(invoker, method,
new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
}
return invoker.invoke();
}
7 行: 缓存操作源-->AnnotationCacheOperationSource
10 行:获取缓存操作源CacheOperationSource,getCacheOperations() 上面Advisor匹配方法创建代理的时候就是用的这个方法,当时已经获取到了所有方法的CacheOperationSource并且存储到了名为attributeCache 的缓存中,现在直接从缓存获取即可。
13 行:创建缓存上下文对象,包含了从缓存获取数据的逻辑。代码如下:
private class CacheOperationContexts {
// <类, CacheOperationContext>
// CacheOperationContext 封装了注解的信息 以及缓存值
private final MultiValueMap<Class<? extends CacheOperation>, CacheOperationContext> contexts;
private final boolean sync;
public CacheOperationContexts(Collection<? extends CacheOperation> operations, Method method,
Object[] args, Object target, Class<?> targetClass) {
this.contexts = new LinkedMultiValueMap<>(operations.size());
for (CacheOperation op : operations) {
// 把每一个CacheOperation 生成一个CacheOperationContext
this.contexts.add(op.getClass(),
// 创建CacheOperationContext
getOperationContext(op, method, args, target, targetClass));
}
this.sync = determineSyncFlag(method);
}
}
protected CacheOperationContext getOperationContext(
CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
// 缓存注解信息
CacheOperationMetadata metadata = getCacheOperationMetadata(operation, method, targetClass);
// 生成CacheOperationContext
//
return new CacheOperationContext(metadata, args, target);
}
protected class CacheOperationContext implements CacheOperationInvocationContext<CacheOperation> {
private final CacheOperationMetadata metadata;
private final Object[] args;
private final Object target;
private final Collection<? extends Cache> caches;
private final Collection<String> cacheNames;
@Nullable
private Boolean conditionPassing;
public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
this.metadata = metadata;
this.args = extractArgs(metadata.method, args);
this.target = target;
// 获取缓存
this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
this.cacheNames = createCacheNames(this.caches);
}
}
/**
* 获取缓存
*
* @param context 上下文
* @param cacheResolver 缓存解析器 SimpleCacheResolver
* @return {@link Collection}<{@link ?} {@link extends} {@link Cache}>
*/
protected Collection<? extends Cache> getCaches(
CacheOperationInvocationContext<CacheOperation> context, CacheResolver cacheResolver) {
// 缓存加载器 获取缓存对象
Collection<? extends Cache> caches = cacheResolver.resolveCaches(context);
if (caches.isEmpty()) {
throw new IllegalStateException("No cache could be resolved for '" +
context.getOperation() + "' using resolver '" + cacheResolver +
"'. At least one cache should be provided per cache operation.");
}
return caches;
}
12 行:给每一个CacheOperation创建一个上下文对象
17 行:创建上下文对象
29 行:执行创建上下文对象
47 行:构造方法,可以看出,上下文对象存储了方法的注解信息、方法参数、类信息、缓存值,缓存名称
52 行:获取缓存值,转掉本类方法getCaches()
66 行:转调cacheResolver.resolveCaches(context) ,代码如下:
public abstract class AbstractCacheResolver implements CacheResolver, InitializingBean {
@Nullable
private CacheManager cacheManager;
public CacheManager getCacheManager() {
Assert.state(this.cacheManager != null, "No CacheManager set");
return this.cacheManager;
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
// 获取到缓存名称
Collection<String> cacheNames = getCacheNames(context);
if (cacheNames == null) {
return Collections.emptyList();
}
// 缓存结果
Collection<Cache> result = new ArrayList<>(cacheNames.size());
for (String cacheName : cacheNames) {
// 从缓存管理器中获取缓存对象
Cache cache = getCacheManager().getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("Cannot find cache named '" +
cacheName + "' for " + context.getOperation());
}
result.add(cache);
}
return result;
}
}
14 行:首选拿到缓存名
20 行:循环缓存名,去缓存管理器CacheManager获取缓存值,这个CacheManager就是我们向容器中注入的 ConcurrentMapCacheManager,那就会转调到ConcurrentMapCacheManager.getCache(),代码如下:
public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {
// <缓存名,缓存值>
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
@Override
@Nullable
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = createConcurrentMapCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
protected Cache createConcurrentMapCache(String name) {
SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256), isAllowNullValues(), actualSerialization);
}
}
这个逻辑就比较简单了,先根据缓存名称去缓存Map中查找缓存对象,没找到就创建一个放入缓存Map中,这里的缓存对象是ConcurrentMapCache,然后一路返回到CacheAspectSupport#execute()
@Nullable
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);
// 缓存操作源 AnnotationCacheOperationSource
CacheOperationSource cacheOperationSource = getCacheOperationSource();
if (cacheOperationSource != null) {
// 获取当前方法缓存注解信息,缓存操作对象CacheOperation 存储了缓存注解的信息
Collection<CacheOperation> operations = cacheOperationSource.getCacheOperations(method, targetClass);
if (!CollectionUtils.isEmpty(operations)) {
return execute(invoker, method,
new CacheOperationContexts(operations, method, args, target, targetClass));
}
}
}
return invoker.invoke();
}
那现在13 行已经走完了,走12 行转调 本类 execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts)
@Nullable
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
// Special handling of synchronized invocation
// 同步调用的特殊处理 线程安全处理
if (contexts.isSynchronized()) {
// 拿到缓存上下文对象
CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
Cache cache = context.getCaches().iterator().next();
try {
return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))));
}
catch (Cache.ValueRetrievalException ex) {
// Directly propagate ThrowableWrapper from the invoker,
// or potentially also an IllegalArgumentException etc.
ReflectionUtils.rethrowRuntimeException(ex.getCause());
}
}
else {
// No caching required, only call the underlying method
return invokeOperation(invoker);
}
}
//先处理@CacheEvicts的逻辑,,其实就是掉clear方法
// Process any early evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationExpressionEvaluator.NO_RESULT);
//处理@Cacheable的逻辑,其实就是掉get方法
// Check if we have a cached item matching the conditions
// cacheHit 就是缓存对象对应的值,也就是缓存的值
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// Collect puts from any @Cacheable miss, if no cached item is found
// 存储没有命中缓存的 CacheableOperation 并封装成 CachePutRequest 对象
List<CachePutRequest> cachePutRequests = new LinkedList<>();
//如果缓存没命中或者不是使用的@Cacheable注解
if (cacheHit == null) {
//处理@Cacheable的逻辑,收集插入请求,插入缓存的值需要调用被代理方法
collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
}
// 缓存值
Object cacheValue;
// 本方法返回的值
Object returnValue;
//如果缓存命中了
if (cacheHit != null && !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);
}
// 处理@CachePut注解,收集put请求
// Collect any explicit @CachePuts
collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
//处理put请求,其实就是掉put方法
// Process any collected put requests, either from @CachePut or a @Cacheable miss
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(cacheValue);
}
// Process any late evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
return returnValue;
}
这个方法干了什么事情呢?
- 处理各个注解
- 如果缓存没有命中就调用原方法获取返回值并放入缓存Map中
总结
这就是sprng-cache 整体的逻辑,可以看到,sprng-cache可以看做是一个通用的缓存规范框架,真正操作缓存的就是cachemanager 和 cache 这两个类,而这两个类又是需要开发者自己定义的,例子中使用的是ConcurrentMapCacheManager 和 ConcurrentMapCache , spring本身也提供了别的,如下图:
使用哪个只需要注入到容器即可。
注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。