Spring的cache实现一


声明:本文转载自https://my.oschina.net/qixiaobo025/blog/1609015,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

背景

和事务实现类似Spring的事务实现二

那么缓存的实现也是借助于aop

方式

注解

同样是EnableCaching  相当类似于事务开启注解

Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(CachingConfigurationSelector.class) public @interface EnableCaching {      /**     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed     * to standard Java interface-based proxies. The default is {@code false}. <strong>     * Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.     *     * <p>Note that setting this attribute to {@code true} will affect <em>all</em>     * Spring-managed beans requiring proxying, not just those marked with     * {@code @Cacheable}. For example, other beans marked with Spring's     * {@code @Transactional} annotation will be upgraded to subclass proxying at the same     * time. This approach has no negative impact in practice unless one is explicitly     * expecting one type of proxy vs another, e.g. in tests.     */    boolean proxyTargetClass() default false;      /**     * Indicate how caching advice should be applied. The default is     * {@link AdviceMode#PROXY}.     * @see AdviceMode     */    AdviceMode mode() default AdviceMode.PROXY;      /**     * Indicate the ordering of the execution of the caching advisor     * when multiple advices are applied at a specific joinpoint.     * The default is {@link Ordered#LOWEST_PRECEDENCE}.     */    int order() default Ordered.LOWEST_PRECEDENCE; }

同样我们关注Import

public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {      /**     * {@inheritDoc}     * @return {@link ProxyCachingConfiguration} or {@code AspectJCacheConfiguration} for     * {@code PROXY} and {@code ASPECTJ} values of {@link EnableCaching#mode()}, respectively     */    public String[] selectImports(AdviceMode adviceMode) {       switch (adviceMode) {          case PROXY:             return new String[] { AutoProxyRegistrar.class.getName(), ProxyCachingConfiguration.class.getName() };          case ASPECTJ:             return new String[] { AnnotationConfigUtils.CACHE_ASPECT_CONFIGURATION_CLASS_NAME };          default:             return null;       }    }   }
@Configuration public class ProxyCachingConfiguration extends AbstractCachingConfiguration {      @Bean(name=AnnotationConfigUtils.CACHE_ADVISOR_BEAN_NAME)    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)    public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() {       BeanFactoryCacheOperationSourceAdvisor advisor =          new BeanFactoryCacheOperationSourceAdvisor();       advisor.setCacheOperationSource(cacheOperationSource());       advisor.setAdvice(cacheInterceptor());       advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));       return advisor;    }      @Bean    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)    public CacheOperationSource cacheOperationSource() {       return new AnnotationCacheOperationSource();    }      @Bean    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)    public CacheInterceptor cacheInterceptor() {       CacheInterceptor interceptor = new CacheInterceptor();       interceptor.setCacheOperationSources(cacheOperationSource());       if (this.cacheManager != null) {          interceptor.setCacheManager(this.cacheManager);       }       if (this.keyGenerator != null) {          interceptor.setKeyGenerator(this.keyGenerator);       }       return interceptor;    }   }

这样我们就可以获知advice为CacheInterceptor

advisor为BeanFactoryCacheOperationSourceAdvisor

public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {      private CacheOperationSource cacheOperationSource;      private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() {       @Override       protected CacheOperationSource getCacheOperationSource() {          return cacheOperationSource;       }    };        /**     * Set the cache operation attribute source which is used to find cache     * attributes. This should usually be identical to the source reference     * set on the cache interceptor itself.     */    public void setCacheOperationSource(CacheOperationSource cacheOperationSource) {       this.cacheOperationSource = cacheOperationSource;    }      /**     * Set the {@link ClassFilter} to use for this pointcut.     * Default is {@link ClassFilter#TRUE}.     */    public void setClassFilter(ClassFilter classFilter) {       this.pointcut.setClassFilter(classFilter);    }      public Pointcut getPointcut() {       return this.pointcut;    }   }

pointCut为

abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {      public boolean matches(Method method, Class<?> targetClass) {       CacheOperationSource cas = getCacheOperationSource();       return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));    }      @Override    public boolean equals(Object other) {       if (this == other) {          return true;       }       if (!(other instanceof CacheOperationSourcePointcut)) {          return false;       }       CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other;       return ObjectUtils.nullSafeEquals(getCacheOperationSource(), otherPc.getCacheOperationSource());    }      @Override    public int hashCode() {       return CacheOperationSourcePointcut.class.hashCode();    }      @Override    public String toString() {       return getClass().getName() + ": " + getCacheOperationSource();    }        /**     * Obtain the underlying {@link CacheOperationSource} (may be {@code null}).     * To be implemented by subclasses.     */    protected abstract CacheOperationSource getCacheOperationSource();   }

整体看来代码十分相似【事务&缓存】出自一人之手

XML

当然还有XML配置

由于缓存我们是选择性的使用 而事务基本都是全部Service都覆盖

所以我们选择注解模式的缓存

<cache:annotation-driven cache-manager="cacheManager"/>

查看xml parse

@Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {    builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));    CacheNamespaceHandler.parseKeyGenerator(element, builder.getBeanDefinition());      List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);    if (cacheDefs.size() >= 1) {       // Using attributes source.       List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);       builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);    } else {       // Assume annotations source.       builder.addPropertyValue("cacheOperationSources", new RootBeanDefinition(             AnnotationCacheOperationSource.class));    } }

和事务不一样当元素大于一个可以返回多个 NameMatchCacheOperationSource 当没有配置 这边可以直接返回AnnotationCacheOperationSource

这边注意一下cacheOperationSources可以塞一个List<RootBeanDefinition>也可以塞一个RootBeanDefinition 当然是由于最终cacheOperationSources是一个可变参数

/**  * Set one or more cache operation sources which are used to find the cache  * attributes. If more than one source is provided, they will be aggregated using a  * {@link CompositeCacheOperationSource}.  * @param cacheOperationSources must not be {@code null}  */ public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {    Assert.notEmpty(cacheOperationSources);    this.cacheOperationSource = (cacheOperationSources.length > 1 ?          new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]); }

虽然最终也会组合成CompositeCacheOperationSource

本文发表于2018年01月18日 16:32
(c)注:本文转载自https://my.oschina.net/qixiaobo025/blog/1609015,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2562 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1