Der Inhalt dieses Artikels befasst sich mit dem Verständnis des Spring Boot-Cache-Quellcodes. Er hat einen gewissen Referenzwert. Ich hoffe, dass er für Sie hilfreich ist.
Ich möchte dem Projekt einen Anwendungscache hinzufügen. Ich habe ursprünglich darüber nachgedacht, wie ich ehcache und springboot integrieren kann, und bin bereit, diese und jene Konfiguration zu konfigurieren. Am Ende muss ich nur drei Dinge tun:
pom-Abhängigkeit
Schreiben Sie eine Ehcache-Konfigurationsdatei
Fügen Sie die Anmerkung @EnableCaching zur Boot-Anwendung hinzu
Das ist es nicht magisch.
POM-Abhängigkeit
<dependency> <groupid>net.sf.ehcache</groupid> <artifactid>ehcache</artifactid> <version>2.10.5</version> </dependency>
Konfigurationsdatei
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <!-- 设定缓存的默认数据过期策略 --> <defaultcache></defaultcache> </ehcache>
EnableCaching-Anmerkung zur Anwendung hinzufügen
@SpringBootApplication @EnableCaching public class EhCacheApplication { public static void main(String[] args) { SpringApplication.run(EhCacheApplication.class, args); } }
Dann können Sie Cache-Anmerkungen wie folgt im Code verwenden.
@CachePut(value = "fish-ehcache", key = "#person.id") public Person save(Person person) { System.out.println("为id、key为:" + person.getId() + "数据做了缓存"); return person; } @CacheEvict(value = "fish-ehcache") public void remove(Long id) { System.out.println("删除了id、key为" + id + "的数据缓存"); } @Cacheable(value = "fish-ehcache", key = "#person.id") public Person findOne(Person person) { findCount.incrementAndGet(); System.out.println("为id、key为:" + person.getId() + "数据做了缓存"); return person; }
Es ist sehr praktisch, oder? Lassen Sie uns als nächstes etwas tiefer graben und sehen, wie der Frühling es macht. Es ist hauptsächlich in zwei Teile unterteilt: Der erste ist, was beim Starten getan wird, der zweite ist, was beim Ausführen getan wird, und der dritte ist die Anpassung mit Cache-Komponenten von Drittanbietern
Was wird wann getan? beginnend,
Dies beginnt mit dem @EnableCaching-Tag. Bei Verwendung der Caching-Funktion muss die Annotation @EnableCaching zur Startklasse der Springboot-Anwendung hinzugefügt werden. Dieses Tag führt das
@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; }
/** 由CacheOperationSourcePointcut作为注解切面,会解析 SpringCacheAnnotationParser.java 扫描方法签名,解析被缓存注解修饰的方法,将生成一个CacheOperation的子类并将其保存到一个数组中去 **/ protected Collection<cacheoperation> parseCacheAnnotations(SpringCacheAnnotationParser.DefaultCacheConfig cachingConfig, AnnotatedElement ae) { Collection<cacheoperation> ops = null; //找@cacheable注解方法 Collection<cacheable> cacheables = AnnotatedElementUtils.getAllMergedAnnotations(ae, Cacheable.class); if (!cacheables.isEmpty()) { ops = this.lazyInit(ops); Iterator var5 = cacheables.iterator(); while(var5.hasNext()) { Cacheable cacheable = (Cacheable)var5.next(); ops.add(this.parseCacheableAnnotation(ae, cachingConfig, cacheable)); } } //找@cacheEvict注解的方法 Collection<cacheevict> evicts = AnnotatedElementUtils.getAllMergedAnnotations(ae, CacheEvict.class); if (!evicts.isEmpty()) { ops = this.lazyInit(ops); Iterator var12 = evicts.iterator(); while(var12.hasNext()) { CacheEvict evict = (CacheEvict)var12.next(); ops.add(this.parseEvictAnnotation(ae, cachingConfig, evict)); } } //找@cachePut注解的方法 Collection<cacheput> puts = AnnotatedElementUtils.getAllMergedAnnotations(ae, CachePut.class); if (!puts.isEmpty()) { ops = this.lazyInit(ops); Iterator var14 = puts.iterator(); while(var14.hasNext()) { CachePut put = (CachePut)var14.next(); ops.add(this.parsePutAnnotation(ae, cachingConfig, put)); } } Collection<caching> cachings = AnnotatedElementUtils.getAllMergedAnnotations(ae, Caching.class); if (!cachings.isEmpty()) { ops = this.lazyInit(ops); Iterator var16 = cachings.iterator(); while(var16.hasNext()) { Caching caching = (Caching)var16.next(); Collection<cacheoperation> cachingOps = this.parseCachingAnnotation(ae, cachingConfig, caching); if (cachingOps != null) { ops.addAll(cachingOps); } } } return ops; }</cacheoperation></caching></cacheput></cacheevict></cacheable></cacheoperation></cacheoperation>
Was geschieht, wenn die Methode ausgeführt wird?
Bei der Ausführung wird hauptsächlich die CacheInterceptor-Klasse verwendet.public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable { public CacheInterceptor() { } public Object invoke(final MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); CacheOperationInvoker aopAllianceInvoker = new CacheOperationInvoker() { public Object invoke() { try { return invocation.proceed(); } catch (Throwable var2) { throw new ThrowableWrapper(var2); } } }; try { return this.execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments()); } catch (ThrowableWrapper var5) { throw var5.getOriginal(); } } }
/** CacheAspectSupport.java 执行@CachaEvict @CachePut @Cacheable的主要逻辑代码 **/ private Object execute(final CacheOperationInvoker invoker, Method method, CacheAspectSupport.CacheOperationContexts contexts) { if (contexts.isSynchronized()) { CacheAspectSupport.CacheOperationContext context = (CacheAspectSupport.CacheOperationContext)contexts.get(CacheableOperation.class).iterator().next(); if (this.isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) { Object key = this.generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT); Cache cache = (Cache)context.getCaches().iterator().next(); try { return this.wrapCacheValue(method, cache.get(key, new Callable<object>() { public Object call() throws Exception { return CacheAspectSupport.this.unwrapReturnValue(CacheAspectSupport.this.invokeOperation(invoker)); } })); } catch (ValueRetrievalException var10) { throw (ThrowableWrapper)var10.getCause(); } } else { return this.invokeOperation(invoker); } } else { /** 执行@CacheEvict的逻辑,这里是当beforeInvocation为true时清缓存 **/ this.processCacheEvicts(contexts.get(CacheEvictOperation.class), true, CacheOperationExpressionEvaluator.NO_RESULT); //获取命中的缓存对象 ValueWrapper cacheHit = this.findCachedItem(contexts.get(CacheableOperation.class)); List<cacheaspectsupport.cacheputrequest> cachePutRequests = new LinkedList(); if (cacheHit == null) { //如果没有命中,则生成一个put的请求 this.collectPutRequests(contexts.get(CacheableOperation.class), CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests); } Object cacheValue; Object returnValue; /** 如果没有获得缓存对象,则调用业务方法获得返回对象,hasCachePut会检查exclude的情况 **/ if (cacheHit != null && cachePutRequests.isEmpty() && !this.hasCachePut(contexts)) { cacheValue = cacheHit.get(); returnValue = this.wrapCacheValue(method, cacheValue); } else { returnValue = this.invokeOperation(invoker); cacheValue = this.unwrapReturnValue(returnValue); } this.collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests); Iterator var8 = cachePutRequests.iterator(); while(var8.hasNext()) { CacheAspectSupport.CachePutRequest cachePutRequest = (CacheAspectSupport.CachePutRequest)var8.next(); /** 执行cachePut请求,将返回对象放到缓存中 **/ cachePutRequest.apply(cacheValue); } /** 执行@CacheEvict的逻辑,这里是当beforeInvocation为false时清缓存 **/ this.processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue); return returnValue; } }</cacheaspectsupport.cacheputrequest></object>
Anpassung an Caching-Komponenten von Drittanbietern
Durch die obige Analyse kennen wir die Besonderheiten der Spring-Cache-Funktion. Im Folgenden müssen die Gründe dafür analysiert werden Es ist nur eine Maven-Deklaration erforderlich. Mit nur wenigen Abhängigkeiten kann sich Spring Boot automatisch anpassen. In der obigen Ausführungsmethode sehen wircachePutRequest.apply(cacheValue), das den Cache betreibt. CachePutRequest ist die innere Klasse CacheAspectSupport.
private class CachePutRequest { private final CacheAspectSupport.CacheOperationContext context; private final Object key; public CachePutRequest(CacheAspectSupport.CacheOperationContext context, Object key) { this.context = context; this.key = key; } public void apply(Object result) { if (this.context.canPutToCache(result)) { //从context中获取cache实例,然后执行放入缓存的操作 Iterator var2 = this.context.getCaches().iterator(); while(var2.hasNext()) { Cache cache = (Cache)var2.next(); CacheAspectSupport.this.doPut(cache, this.key, result); } } } }
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."); } else { return caches; } }</cacheoperation>
@Configuration @ConditionalOnClass({Cache.class, EhCacheCacheManager.class}) @ConditionalOnMissingBean({CacheManager.class}) @Conditional({CacheCondition.class, EhCacheCacheConfiguration.ConfigAvailableCondition.class}) class EhCacheCacheConfiguration { ...... static class ConfigAvailableCondition extends ResourceCondition { ConfigAvailableCondition() { super("EhCache", "spring.cache.ehcache", "config", new String[]{"classpath:/ehcache.xml"}); } } }
Das obige ist der detaillierte Inhalt vonGrundlegendes zum Spring Boot-Cache-Quellcode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!