SpringCache源碼深度解析


緩存是我們常用的一種優化系統的方案。

    無論是前端緩存還是應用層緩存或者數據庫緩存,其本質都是將查詢過的數據緩存下來,下次再次查詢該數據的時候如果數據沒有過期,則直接返回緩存中該數據即可,不再執行查詢操作。

    SpringCache是我們常用的一種應用層緩存方案,其一般應用在方法上,下面我們先來看下具體的使用方式,然后再從源碼角度分析其實現方案

1.SpringCache的使用

 

    1)maven引入依賴

        cache功能相關代碼都在spring-context中,一般使用Spring的項目中都有該包,所以不用再單獨引入

 

    2)Service(業務處理類,代碼參考網上文章,非原創,有改動)

// 接口類
package cache;
 
public interface IService {
    Account getAccountByName(String userName);
    void updateAccount(Account account);
}
 
// 實現類
public class AccountService implements IService{
    @Override
    @Cacheable(value = "accountCache") // 使用了一個緩存名叫 accountCache
    public Account getAccountByName(String userName) {
        // 方法內部實現不考慮緩存邏輯,直接實現業務
        System.out.println("real query account." + userName);
        return getFromDB(userName);
    }
 
    @Override
    @CacheEvict(value="accountCache",key="#account.getName()")
    public void updateAccount(Account account) {
        updateDB(account); 
    }
 
    @CacheEvict(value = "accountCache", allEntries = true)
    public void reload() {
    }
 
    private Account getFromDB(String acctName) {
        System.out.println("real querying db..." + acctName);
        return new Account(acctName);
    }
 
    private void updateDB(Account account) {
        System.out.println("real update db..." + account.getName());
    }
}

如上所示:在方法上加上@cacheable等注解即可

3)Spring-cache-anno.xml文件(用於定義bean)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache.xsd">
 
    <!-- 添加driven -->
    <cache:annotation-driven />
    
    <bean id="accountServiceBean" class="cache.AccountService" />
    <!-- generic cache manager -->
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <bean
                    class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
                    p:name="accountCache" />
            </set>
        </property>
    </bean>
</beans>

使用默認的SimpleCacheManager

 

    4)測試(測試緩存是否生效)

public class Test {
 
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-cache-anno.xml");
        IService s = context.getBean(IService.class);
        // 第一次查詢,應該走數據庫
        System.out.print("first query...");
        s.getAccountByName("somebody");
        // 第二次查詢,應該不查數據庫,直接返回緩存的值
        System.out.print("second query...");
        s.getAccountByName("somebody");
        System.out.println();
    }
}
 
//result:
first query...
real query account.somebody
real querying db...somebody
second query...

總結:根據結果可以看到,第二次查詢的時候沒有真正執行getFromDB()方法,而是從緩存中取的數據

 

2.寫在源碼分析之前

    如果是我們來做的話,如何實現該功能?

    基於我們對Spring的一貫理解,這應該是個代理,我們在獲取IService的bean時候,應該獲取的是個代理類,代理類執行業務方法,先去查詢是否在緩存中有該數據,如果有則直接從緩存中獲取,如果沒有,則調用AccountService的方法

    

3.SpringCache源碼結構分析

    根據我們的示例可知,真正的內容都放在配置文件里了

    配置文件中添加了一個driven(真正的功能應該在這里實現的)

<cache:annotation-driven />

下面是兩個bean(accountServiceBean是我們需要的,需要將AccountService注入到容器中。

    至於SimpleCacheManager暫時不知道其作用,只知道其實現了CacheManage接口,我們先暫時放一下)

<bean id="accountServiceBean" class="cache.AccountService" />
    <!-- generic cache manager -->
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <bean
                    class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
                    p:name="accountCache" />
            </set>
        </property>
    </bean>

  1)<cache:annotation-driven/>的分析

        但凡這種注解,都有對應的解析器,從之前分析AOP功能的源碼可知,解析器都實現了NamespaceHandlerSupport類,我們來獲取下NamespaceHandlerSupport的實現類都有哪些

 

 

 里面有一個叫做CacheNamespaceHandler的類,看名字就像這個,我們來看下這個類

2)CacheNamespaceHandler

public class CacheNamespaceHandler extends NamespaceHandlerSupport {
 
    static final String CACHE_MANAGER_ATTRIBUTE = "cache-manager";
 
    static final String DEFAULT_CACHE_MANAGER_BEAN_NAME = "cacheManager";
    ...
    @Override
    public void init() {
        // 主要是這句代碼
        registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
        registerBeanDefinitionParser("advice", new CacheAdviceParser());
    }
}

Spring會默認調用其init()方法,annotation-driven對應的是AnnotationDrivenCacheBeanDefinitionParser解析器,我們來看下這個解析器的作用

 

    3)AnnotationDrivenCacheBeanDefinitionParser

@Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String mode = element.getAttribute("mode");// mode默認為proxy
        if ("aspectj".equals(mode)) {
            // mode="aspectj"
            registerCacheAspect(element, parserContext);
        }
        else {
            // 直接調用該方法
            registerCacheAdvisor(element, parserContext);
        }
 
        return null;
    }
 
// registerCacheAdvisor()
    private void registerCacheAdvisor(Element element, ParserContext parserContext) {
        // 1.注冊ProxyCreator類 在4)中詳細分析
        AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
        // 2.注冊CacheAdvisor 在5)中詳細分析
        SpringCachingConfigurer.registerCacheAdvisor(element, parserContext);
        if (jsr107Present && jcacheImplPresent) {
            // 默認不會調用
            JCacheCachingConfigurer.registerCacheAdvisor(element, parserContext);
        }
    }

4)AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element)

public static void registerAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {
        // 重點在這里
        BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }
 
// AopConfigUtils.registerAutoProxyCreatorIfNecessary()
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
        // 重點在這里
        return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
    }

可以看到,主要是為了將InfrastructureAdvisorAutoProxyCreator注冊到容器中

5)SpringCachingConfigurer.registerCacheAdvisor(element, parserContext)

private static void registerCacheAdvisor(Element element, ParserContext parserContext) {
            if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)) {
                Object eleSource = parserContext.extractSource(element);
 
                // 1.注冊AnnotationCacheOperationSource類到容器中
                RootBeanDefinition sourceDef = new RootBeanDefinition("org.springframework.cache.annotation.AnnotationCacheOperationSource");
                sourceDef.setSource(eleSource);
                sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
 
                // 2.注冊CacheInterceptor類到容器中
                RootBeanDefinition interceptorDef = new RootBeanDefinition(CacheInterceptor.class);
                interceptorDef.setSource(eleSource);
                interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                parseCacheResolution(element, interceptorDef, false);
                parseErrorHandler(element, interceptorDef);
                CacheNamespaceHandler.parseKeyGenerator(element, interceptorDef);
                interceptorDef.getPropertyValues().add("cacheOperationSources", new RuntimeBeanReference(sourceName));
                String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
 
                // 3.注冊BeanFactoryCacheOperationSourceAdvisor類到容器中,
                RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryCacheOperationSourceAdvisor.class);
                advisorDef.setSource(eleSource);
                advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                // 注意這里,將AnnotationCacheOperationSource和CacheInterceptor作為其屬性注入進來
                advisorDef.getPropertyValues().add("cacheOperationSource", new RuntimeBeanReference(sourceName));
                advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
                if (element.hasAttribute("order")) {
                    advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
                }
                // 注意這句,將BeanFactoryCacheOperationSourceAdvisor類的注冊名稱設置為
                // org.springframework.cache.config.internalCacheAdvisor
                // 在下面會用到這個名稱
                parserContext.getRegistry().registerBeanDefinition(CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME, advisorDef);
 
                ...
            }
        }

總結:由以上分析可知,我們添加<cache:annotation-driven />注解,主要是將以下類注入進Spring容器

    * InfrastructureAdvisorAutoProxyCreator

    * AnnotationCacheOperationSource

    * CacheInterceptor(主要的攔截功能都實現在這里)

    * BeanFactoryCacheOperationSourceAdvisor(重點關注這個,這個類在創建代理的時候被使用)

 

    我們暫時只知道加載driven注解的時候,只是將這四個類注入到Spring容器中,而這些類具體在做什么,我們也不知道,更不知道與我們的AccountService類有什么關聯。這些我們先暫時放一下,先看下CacheInterceptor和InfrastructureAdvisorAutoProxyCreator的功能簡介

4.CacheInterceptor功能簡單分析

其代碼結構如下

 

 

 

可知:

    * 其實現了InitializingBean接口,則CacheInterceptor創建的時候會默認調用afterPropertiesSet()方法;

    * 其實現了SmartInitializingSingleton接口,則CacheInterceptor創建的時候會默認調用afterSingletonsInstantiated()方法

    * 其實現了MethodInterceptor接口,則在被其攔截的方法上,默認會調用其invoke()方法

    有關於這些接口的作用,不太明白的同學可以先看下對應的文章了解其大致作用

 

    1)初始化afterPropertiesSet()方法

// 只是做了校驗,沒有其他功能    
    public void afterPropertiesSet() {
        Assert.state(getCacheOperationSource() != null, "The 'cacheOperationSources' property is required: " +
                "If there are no cacheable methods, then don't use a cache aspect.");
        Assert.state(getErrorHandler() != null, "The 'errorHandler' property is required");
    }

2)初始化afterSingletonsInstantiated()方法

public void afterSingletonsInstantiated() {
        if (getCacheResolver() == null) {
            // Lazily initialize cache resolver via default cache manager...
            try {
                // 重點在這里
                // 從工廠類中獲取CacheManager的實現類
                // 這里就與我們的Spring-cache-anno.xml配置文件中的創建的cacheManager 
                // bean關聯起來了,在配置文件中創建的bean實現了接口CacheManager
                // 則會在這里被使用
                setCacheManager(this.beanFactory.getBean(CacheManager.class));
            }
            ...
        }
        this.initialized = true;
    }
        
// setCacheManager()
    public void setCacheManager(CacheManager cacheManager) {
        //     private CacheResolver cacheResolver;
        this.cacheResolver = new SimpleCacheResolver(cacheManager);
    }

3)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();
        }
    }

總結4:

    CacheInterceptor主要是一個方法攔截器,在初始化的時候將CacheManager的實現類(由用戶自定義實現)添加進來;

    invoke()方法,真正執行攔截的方法

 

5.InfrastructureAdvisorAutoProxyCreator功能分析

    其代碼結構如下:

 

 

可以看到,其實現了BeanPostProcessor接口,則Spring在創建bean的時候,會默認調用InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization()方法,就是在這個方法中創建代理類的,下面我們來看下這個方法

 1)AbstractAutoProxyCreator.postProcessAfterInitialization()

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                // 重要方法
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
 
// wrapIfNecessary()
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        ...
 
        // 1.獲取當前類的所有切面攔截類,在2)中詳細分析
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        // 2.如果攔截類不為空,則需要創建當前類的代理類
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 3.創建代理類,在3)中詳細分析
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
 
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

以上邏輯類似於之前分析的AOP源碼,讀者也可以先看下 https://blog.csdn.net/qq_26323323/article/details/81012855  

 

 

    2)getAdvicesAndAdvisorsForBean()獲取當前類的所有切面攔截器

    本方法為抽象方法,實現由子類AbstractAdvisorAutoProxyCreator實現

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);//重點在這里
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }
 
// findEligibleAdvisors()
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        // 1.獲取所有的Advisor
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        // 2.獲取適合當前類的Advisor
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }

* findCandidateAdvisors()獲取所有的Advisor

//     findCandidateAdvisors()
    protected List<Advisor> findCandidateAdvisors() {
        return this.advisorRetrievalHelper.findAdvisorBeans();
    }
 
 
//findAdvisorBeans()
    public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = null;
        synchronized (this) {
            // 1.cachedAdvisorBeanNames=org.springframework.cache.config.internalCacheAdvisor
            advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) {
                // Do not initialize FactoryBeans here: We need to leave all regular beans
                // uninitialized to let the auto-proxy creator apply to them!
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Advisor.class, true, false);
                this.cachedAdvisorBeanNames = advisorNames;
            }
        }
        if (advisorNames.length == 0) {
            return new LinkedList<Advisor>();
        }
 
        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String name : advisorNames) {
            if (isEligibleBean(name)) {
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipping currently created advisor '" + name + "'");
                    }
                }
                else {
                    try {
                        // 2.從工廠中獲取CacheInterceptor對應的bean
                        // 在上述代碼 3節5)中,可知,
                        // org.springframework.cache.config.internalCacheAdvisor這個名稱對應bean為
                        // BeanFactoryCacheOperationSourceAdvisor類,
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    }
                    catch (BeanCreationException ex) {
                        Throwable rootCause = ex.getMostSpecificCause();
                        if (rootCause instanceof BeanCurrentlyInCreationException) {
                            BeanCreationException bce = (BeanCreationException) rootCause;
                            if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Skipping advisor '" + name +
                                            "' with dependency on currently created bean: " + ex.getMessage());
                                }
                                // Ignore: indicates a reference back to the bean we're trying to advise.
                                // We want to find advisors other than the currently created bean itself.
                                continue;
                            }
                        }
                        throw ex;
                    }
                }
            }
        }
        return advisors;
    }

總結2):適合當前類的Advisor最終為BeanFactoryCacheOperationSourceAdvisor類,也就是我們之前在分析<cache:annotation-driven/>中注冊的BeanFactoryCacheOperationSourceAdvisor bean

    3)createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource)

    創建代理類    

    這里筆者就不再繼續分析了,具體讀者可參考 https://blog.csdn.net/qq_26323323/article/details/81012855  博文中創建proxy過程分析一節

總結5:InfrastructureAdvisorAutoProxyCreator的主要作用就是實現了BeanPostProcessor接口,那么Spring的每個bean在創建的過程中,都需要調用其postProcessAfterInitialization()方法,在這個方法中查詢出所有適合當前類的Advisor,然后創建當前類的代理類,並將Advisor封裝進來,在以后調用當前類的方法時使用

6.代理類invoke()方法調用

    通過以上分析可知,Spring為我們創建的AccountService bean實際是一個關於AccountService的代理類,在調用AccountService的相關方法時,實際調用的是代理類的invoke()方法,下面我們就來分析下,invoke()方法被調用的過程,具體了解下我們的緩存是如何工作的

    由於本例是JDKProxy創建的方式,而非CGLIBProxy的創建方式,所以AccountService的代理類為JdkDynamicAopProxy,下面看下其invoke()方法

    1)JdkDynamicAopProxy.invoke()

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
 
        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;
 
        try {
            ...
            Object retVal;
 
            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
 
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
 
            // 1.獲取當前方法的攔截器鏈,也就是Advisor列表
            // 最終返回的是當前Advisor的攔截器MethodInterceptor列表
            // 在2)中詳細分析
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 
            // 2.如果攔截器鏈為空,說明當前方法沒有緩存注解,直接調用方法即可
            if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            // 3.說明當前方法有緩存注解,則需要先調用攔截器鏈的方法
            else {
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // 真正的調用在這里
                // 在3)中詳細分析
                retVal = invocation.proceed();
            }
 
            ...
            return retVal;
        }
        ...
    }

 2)AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);獲取當前方法的攔截器鏈

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            // 真正的實現在這里
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }
 
//DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass) {
 
        // This is somewhat tricky... We have to process introductions first,
        // but we need to preserve order in the ultimate list.
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
 
        // 1.遍歷當前bean的所有Advisor
        // 就當前示例而言,只有一個Advisor,就是之前創建的BeanFactoryCacheOperationSourceAdvisor
        for (Advisor advisor : config.getAdvisors()) {
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    // 2.獲取Advisor的Interceptor,也就是在分析<cache:annotation-driven />時
                    // 被添加到BeanFactoryCacheOperationSourceAdvisor類的CacheInterceptor類
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
 
        return interceptorList;
    }

所以,攔截器鏈最終返回的是我們之前分析的CacheInterceptor類

    3)ReflectiveMethodInvocation.proceed()攔截器鏈的調用分析

// InterceptedMethodInvocation.proceed()    
    public Object proceed() throws Throwable {
      try {
        // 主要就是遍歷調用Interceptor的invoke方法
        return index == interceptors.length
            ? methodProxy.invokeSuper(proxy, arguments)
            : interceptors[index].invoke(
                new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
      } catch (Throwable t) {
        pruneStacktrace(t);
        throw t;
      }
    }

那我們看下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();
        }
    }
 
//CacheAspectSupport.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);
            // 1.獲取當前方法的緩存操作
            Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
            if (!CollectionUtils.isEmpty(operations)) {
                // 2.執行緩存操作
                return execute(invoker, method, new CacheOperationContexts(operations, method, args, target, targetClass));
            }
        }
 
        return invoker.invoke();
    }

* getCacheOperationSource().getCacheOperations(method, targetClass)獲取當前方法的緩存操作

    默認實現類為AbstractFallbackCacheOperationSource

// AbstractFallbackCacheOperationSource.getCacheOperations(Method method, Class<?> targetClass)
    public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
        if (method.getDeclaringClass() == Object.class) {
            return null;
        }
 
        Object cacheKey = getCacheKey(method, targetClass);
        Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
 
        if (cached != null) {
            return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
        }
        else {
            Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
            if (cacheOps != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
                }
                this.attributeCache.put(cacheKey, cacheOps);
            }
            else {
                this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
            }
            return cacheOps;
        }
    }

   * 執行execute()方法(關於操作緩存細節筆者不再詳細分析,讀者可自行分析)

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, new Callable<Object>() {
                        @Override
                        public Object call() throws Exception {
                            return unwrapReturnValue(invokeOperation(invoker));
                        }
                    }));
                }
                catch (Cache.ValueRetrievalException ex) {
                    // The invoker wraps any Throwable in a ThrowableWrapper instance so we
                    // can just make sure that one bubbles up the stack.
                    throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();
                }
            }
            else {
                // No caching required, only call the underlying method
                return invokeOperation(invoker);
            }
        }
 
 
        // Process any early evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
                CacheOperationExpressionEvaluator.NO_RESULT);
 
        // Check if we have a cached item matching the conditions
        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);
        }
 
        // Collect any explicit @CachePuts
        collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);
 
        // 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;
    }

總結:

    緩存功能的實現實際也是通過Spring代理來實現的。生成當前類的代理類,調用代理類的invoke()方法,在invoke()方法中調用CacheInterceptor攔截器的execute()方法,攔截器會使用緩存器(本例中的SimpleCacheManager)來進行具體方法實現。

 

    重要操作流程如下:

    1)解析<cache:annotation-driven />,將InfrastructureAdvisorAutoProxyCreator注入到Spring容器中,該類的作用是在Spring創建bean實例的時候,會執行其postProcessAfterInitialization()方法,生成bean實例的代理類

 

    2)解析<cache:annotation-driven />,將BeanFactoryCacheOperationSourceAdvisor類注入到Spring容器中,該類的主要作用是作為一個Advisor添加到上述代理類中

 

    3)BeanFactoryCacheOperationSourceAdvisor類擁有對CacheInterceptor的依賴,CacheInterceptor作為一個方法攔截器,負責對緩存方法的攔截,

 

    4)當前類方法調用被攔截到CacheInterceptor后,CacheInterceptor會調用我們在配置文件中配置的CacheManager實現(也就是本例中的SimpleCacheManager),來真正實現緩存功能

原文鏈接:https://blog.csdn.net/qq_26323323/article/details/81700626


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM