首页 > 解决方案 > Spring 可缓存异步更新,同时返回旧缓存

问题描述

有休息控制器,它@Cacheable@Service. 我的CacheManagerexpireAfterWrite超时,所以当超时后使用rest->服务方法时,必须重写缓存。但问题是,如果同时有许多 rest 调用,所有调用的线程都会转到服务方法并重写缓存。我需要通过 进行服务方法同步@Cacheable(sync=true),但其他调用必须在第一次调用创建新缓存时返回旧缓存。

package application.system.config;

import com.google.common.cache.CacheBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class CacheManagerConfiguration {

    @Value("${cache.timer.timeout}")
    private int cacheTimeout;

    @Bean("timeOutCacheManager")
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager() {
            @Override
            protected Cache createConcurrentMapCache(String name) {
                return new ConcurrentMapCache(
                        name,
                        CacheBuilder.newBuilder()
                                .expireAfterWrite(cacheTimeout, TimeUnit.SECONDS)
                                .build().asMap(), false);
            }
        };
    }
}

@GetMapping(RestEndpoints.GET_SCHEDULE)
public ResponseEntity<SummaryReport> getSchedule(@RequestParam(required = false) String department,
                                                 @RequestParam(required = false) Long group) throws InterruptedException {
    
    return ResponseEntity.ok(scheduleService.getSummaryReport(department, group));
}
    @Transactional
    @Cacheable(value = Caches.SUMMARY_REPORT, condition = "#root.target.isCacheEnable", sync = true)
    public SummaryReport getSummaryReport(String department, Long group) {

        SummaryReport report = new SummaryReport() {{
            setDepartments(new ArrayList<>());
        }};
        
        List<DepartmentTable> departmentEntities = getDepartmentsData(department);
        List<ScheduleTable> scheduleEntities = getSchedulesData(department, group);
        List<ConstraintTable> constraintEntities = getConstraintsData(department, group);

        departmentEntities.forEach(departmentEntity -> {

            List<ScheduleTable> departmentsSchedules = scheduleEntities
                    .stream()
                    .filter(schedule -> schedule.getEnable() == 1)
                    .filter(schedule -> schedule.getDepartmentTableRef().getId().equals(departmentEntity.getId()))
                    .collect(Collectors.toList());

            List<ConstraintTable> departmentsConstraintsEntities = constraintEntities
                    .stream()
                    .filter(entity -> entity.getDepartmentTableRef().getId().equals(departmentEntity.getId()))
                    .collect(Collectors.toList());

            reportHandler.addDepartmentToReport(report, departmentEntity, departmentsSchedules, departmentsConstraintsEntities);
        });

        LOGGER.info("Caches were expired, actual data was obtained by {}", getCurrentApp());
        return report;
    }

标签: javaspringspring-bootspring-cache

解决方案


推荐阅读