zoukankan      html  css  js  c++  java
  • 替换Spring Boot 的EnableCaching注解

    SpringBoot 中可使用@Cacheable注解来更方便的使用redis,这个注解是通过拦截器工作的,使用了@Cacheable的方法执行时,执行到CglibAopProxy.java中的 DynamicAdvisedInterceptor.intercept方法中如下图位置时,会发现CacheInterceptor:

            CacheInterceptor是由EnableCaching注解引入的:

            CachingConfigurationSelector:

            注意上图中的ProxyCachingConfiguration:

            方法的返回值如果缓存中存在直接返回缓存中结果,缓存中没有才会实际执行方法这个功能的实现就是在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();
    		}
    	}

            具体读取数据在protected的execute方法中的private的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);
    			Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
    			if (!CollectionUtils.isEmpty(operations)) {
    				return execute(invoker, method, new CacheOperationContexts(operations, method, args, target, targetClass));
    			}
    		}
    
    		return invoker.invoke();
    	}

            首先下面代码第一行findCachedItem方法判断缓存中是否有数据,然后在后面的那个判断中判断,有就取缓存并直接返回结果,不再执行被拦截方法;否则else执行被拦截方法,被拦截方法中一般就是读数据库了,不过这就和这部分没啥关系了。

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

            我这是用redis做缓存的,通过上面代码可以发现,一旦redis挂了,findCachedItem方法报异常,被拦截的方法就不能正常使用了,那么我需要redis出异常了,正常走数据库该怎么办呢。我首先考虑的是重写protected的那个execute方法,然而发现有一个private的内部类绕不过去,全都自己实现一遍,完全没必要,因为懒得细调了于是我就新建了一个拦截器,继承CacheInterceptor:

        @Override
        protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) {
            try {
                return super.execute(invoker, target, method, args);
            }catch (Exception e){
                return invokeOperation(invoker);
            }
        }

            然后就是让新拦截器起作用,我讨厌SpringBoot的注解就讨厌在这部分。如果还用EnableCaching注解这问题就复杂了,于是简单粗暴新建注解代替EnableCaching,然后CachingConfigurationSelector也需要替换掉。接着是ProxyCachingConfiguration以及它的基类AbstractCachingConfiguration:

            重写这个方法,用新建的注解替换掉方法中的EnableCaching就可以了,由于用的是线上代码测试的就不好往这贴了,不过亲测成功,虽然方法比较粗糙,但是SpringBoot里的代码留的扩展余地就那样,也不想太费工夫了。

    ==========================================================

    咱最近用的github:https://github.com/saaavsaaa

    微信公众号:

                          

  • 相关阅读:
    基于windows的mysql读写分离和amoeba配置
    windows环境下mysql主从配置
    Mysql主从报错锦集
    Nginx流控
    windows_windows下的rsync
    Kafka+ZooKeeper高可用集群部署
    通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布
    Redis性能指标监控
    MongoDB用户权限管理
    ZooKeeper原理详解及常用操作
  • 原文地址:https://www.cnblogs.com/saaav/p/7246219.html
Copyright © 2011-2022 走看看