2022-03-08_spring@EnableCaching注解源码分析学习笔记

20220308_spring@EnableCaching注解源码分析学习笔记.md

1概述

1.1涉及知识点

  1. EnableCaching启动入口
  2. AnnotationAwareAspectJAutoProxyCreator(本质BeanPostProcessor)的构建过程
  3. 普通Bean(UserController)一步步演变成代理对象的细节分析

1.2源码分析

1.2.1EnableCaching启动入口

package org.springframework.cache.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Import;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({CachingConfigurationSelector.class})
public @interface EnableCaching {
    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}

1.2.1.1CachingConfigurationSelector

public class CachingConfigurationSelector extends AdviceModeImportSelector {

如果adviceMode:PROXY,则将类AutoProxyRegistrar、ProxyCachingConfiguration添加到Imports数组中。

image-20220308213205938.png
1.2.1.1.1AutoProxyRegistrar创建bpp元数据

AutoProxyRegistrar功能,负责创建RootBeanDefinition,并注入到registry容器,后续会创建Bean对象,名称为:AnnotationAwareAspectJAutoProxyCreator(实际就是一个BeanPostProcessor),内置BeanFactoryCacheOperationSourceAdvisor的配置。

注意,低版本可能为:InfrastructureAdvisorAutoProxyCreator。

if (mode == AdviceMode.PROXY) {
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean) proxyTargetClass) {
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }
public abstract class AopConfigUtils {
    
    static {
        // Set up the escalation list...
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }
    
    /**
     * The bean name of the internally managed auto-proxy creator.
     */
    public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
            "org.springframework.aop.config.internalAutoProxyCreator";
            
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, @Nullable Object source) {

RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 2:ROLE_INFRASTRUCTURE
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
    @Nullable
    private ConfigurableListableBeanFactory beanFactory;

    public InfrastructureAdvisorAutoProxyCreator() {
    }
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
    @Nullable
    private List includePatterns;
    @Nullable
    private AspectJAdvisorFactory aspectJAdvisorFactory;
    @Nullable
    private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;

    public AnnotationAwareAspectJAutoProxyCreator() {
    }
1.2.1.1.2ProxyCachingConfiguration代理配置类
image-20220308214651223.png
/**
     * The name of the cache advisor bean.
     */
public static final String CACHE_ADVISOR_BEAN_NAME =
    "org.springframework.cache.config.internalCacheAdvisor";

// 注入切面
@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor(
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheOperationSource cacheOperationSource() {
    // 注解解析器:AnnotationCacheOperationSource
    return new AnnotationCacheOperationSource();
}

public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
        this.publicMethodsOnly = publicMethodsOnly;
    // 这里内置了注解解析器:SpringCacheAnnotationParser
    this.annotationParsers = Collections.singleton(new SpringCacheAnnotationParser());
}
public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable {

   private static final Set> 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);
   }
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {

1.2.2AnnotationAwareAspectJAutoProxyCreator(本质BeanPostProcessor)的构建过程

// AbstractApplicationContext.java
@Override
public void refresh() throws BeansException, IllegalStateException {
    
    // Register bean processors that intercept bean creation.
    // Eg:org.springframework.aop.config.internalAutoProxyCreator
    // 最终生成bpp:AnnotationAwareAspectJAutoProxyCreator(本质BeanPostProcessor)
    registerBeanPostProcessors(beanFactory);

1.2.3普通Bean(UserController)一步步演变成代理对象的细节分析

1.2.3.1我们知道spring创建一个Bean的三部曲如下:

AbstractAutowireCapableBeanFactory.class:
// 1.bean实例化
if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 2.属性填充
populateBean(beanName, mbd, instanceWrapper);A
// 3.初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
// 3.1
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 3.2.
invokeInitMethods(beanName, wrappedBean, mbd);
// 3.3重点在这儿
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

1.2.3.2applyBeanPostProcessorsAfterInitialization

如果发现该Bean的方法存在上述4个注解定义时,会对该类套一层缓存代理。

// 这里遍历所有的bpp,并调用bpp中的方法:postProcessAfterInitialization
// 我们重点关注:AnnotationAwareAspectJAutoProxyCreator 这个bpp
// existingBean:原生Bean
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }

InfrastructureAdvisorAutoProxyCreator这个bpp,执行流程:

BeanFactoryCacheOperationSourceAdvisor实例,继承了Advisor接口,在获取后续的Bean时,会对这些Bean Bean.getDeclaredMethods方法清单里的每个方法,调用matches进行检测:

// BeanFactoryCacheOperationSourceAdvisor的private属性CacheOperationSourcePointcut 里的方法
@Override
public boolean matches(Method method, Class targetClass) {
    CacheOperationSource cas = getCacheOperationSource();
    return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
}

这个cas就是ProxyCachingConfiguration里的AnnotationCacheOperationSource实例,通过cas.getCacheOperations方法,
调用org.springframework.cache.annotation.SpringCacheAnnotationParser类的方法parseCacheAnnotations,
读取Bean的方法上的Cacheable、CacheEvict、CachePut、Caching这4个注解定义,并转成 CacheOperation,然后缓存起来.
如果发现该Bean的方法存在上述4个注解定义时,会对该类套一层缓存代理,每次调用缓存方法,都会被 BeanFactoryCacheOperationSourceAdvisor.getAdvice()所拦截,这个getAdvice方法返回的就是上面ProxyCachingConfiguration里的CacheInterceptor实例。

2实验代码

2.1MyCacheConfig

@Configuration
@EnableCaching
public class MyCacheConfig {
}

2.2UserController

@RestController
public class UserController {
@RequestMapping(value = "updateUserInfo", method = {RequestMethod.GET, RequestMethod.POST})
    // 当需要在不影响方法执行的情况下更新缓存时,可以使用 @CachePut,也就是说,被 @CachePut 注解的缓存方法总是会执行
    // 表示对key=kikop的数据进行更新
    @CachePut
    @ResponseBody
    public JSONObject updateUserInfo(@RequestBody JSONObject reqParam) {
        return null;
    }
}

2总结

2.1@CachePut和@Cacheable的区别

@CachePut负责增加缓存

@Cacheable负责查询缓存,如果没查到,则将执行方法,并将方法的结果增加到缓存

由于与 @Cacheable 的属性基本相同,所以不再重复示例。这里重点说明一下它们的区别:

@Cacheable 的逻辑是:查找缓存 - 有就返回 -没有就执行方法体 - 将结果缓存起来;

@CachePut 的逻辑是:执行方法体 - 将结果缓存起来;

所以 @Cacheable 适用于查询数据的方法,@CachePut 适用于更新数据的方法。

参考

1.1springboot2.0 redis EnableCaching的配置和使用

http://www.javashuo.com/article/p-docwscfv-dh.html

1.2Spring boot 下redis缓存的使用@EnableCaching、@CacheConfig、@Cacheable、@CacheEvict、@CachePut

https://blog.csdn.net/weixin_42404323/article/details/94722161?spm=1001.2014.3001.5506

1.3Spring框架的Cache缓存实现源码解读与原理解析

https://blog.csdn.net/youbl/article/details/112573887?spm=1001.2014.3001.5506

1.4spring cache 学习——@CachePut 使用详解

https://www.cnblogs.com/coding-one/p/12403801.html

你可能感兴趣的:(2022-03-08_spring@EnableCaching注解源码分析学习笔记)