緩存是我們常用的一種優化系統的方案。
無論是前端緩存還是應用層緩存或者數據庫緩存,其本質都是將查詢過的數據緩存下來,下次再次查詢該數據的時候如果數據沒有過期,則直接返回緩存中該數據即可,不再執行查詢操作。
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