Кэш Spring Boot не работает

Я пытаюсь настроить кеш Spring, но метод все еще выполняется. У меня есть приведенный ниже код, и кеш CivilStatus не работает. Метод getCivilStatus() выполняется всегда. Кто-нибудь знает причину?

@Configuration
@EnableCaching
public class ApplicationConfig {

@Autowired
private SocioDemographicInfoService socioDemographicInfo;


@Bean
public CacheManager cacheManager() {
    SimpleCacheManager cacheManager = new SimpleCacheManager();
    cacheManager.setCaches(Arrays.asList(           
            new ConcurrentMapCache("civilStatus");

    return cacheManager;
}
}   



@Service
public class SocioDemographicInfoService {



@Cacheable(value="civilStatus")
public Map<String, String> getCivilStatus(){
    log.info("Retrieving civilStatus");
    Map<String, String> civilStatus = new HashMap<String, String>();
    BufferedReader br = null;
    String line = "";
    String cvsSplitBy = ",";
    try {
        ClassLoader classLoader = getClass().getClassLoader();
        File file = new File(classLoader.getResource("CatalogoEstadoCivil.csv").getFile());
        br = new BufferedReader(new FileReader(file));
        while ((line = br.readLine()) != null) {
            String[] cod = line.split(cvsSplitBy);
            civilStatus.put(cod[0].trim(), cod[1]);
        }

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    return civilStatus;
}
}

}


person nole    schedule 13.12.2014    source источник
comment
Проблема кроется в вашей конфигурации. Вы автоматически связываете свой компонент с кэшированием в конфигурации. Это жадно создает экземпляр bean-компонента и не обрабатывает его для кэширования.   -  person M. Deinum    schedule 13.12.2014
comment
большое спасибо за ответ. Я хочу загрузить файл в начале и кэшировать его. Вы знаете, как я могу его развить?   -  person nole    schedule 13.12.2014
comment
Зачем вам кеширование для этого? Вы можете просто сделать это самостоятельно, не включая кеширование. Добавьте в свой SocioDemographicInfoService метод с аннотацией @PostConstruct, который загружает файл и заполняет карту. Для этого не нужно использовать абстракцию кэширования Springs.   -  person M. Deinum    schedule 13.12.2014
comment
Мне нужен кеш, потому что мне нужно вызывать getCivilStatus несколько раз, и я подумал, что кэширование getCivilStatus() будет лучшим вариантом.   -  person nole    schedule 13.12.2014
comment
вам это не нужно. Просто загрузите файл при запуске, чтобы заполнить карту, и пусть getCivilStatus вернет эту карту. Вам не нужна дополнительная сложность кэша или АОП.   -  person M. Deinum    schedule 13.12.2014


Ответы (2)


Вам не нужен АОП, а сложность кэширования вашего варианта использования намного проще. Просто создайте метод, который загружает файл при запуске, и пусть ваш getCivilStatus возвращает эту карту. Намного проще.

@Service
public class SocioDemographicInfoService implements ResourceLoaderAware {

    private final Map<String, String> civilStatus = new HashMap<String, String>();

    private ResourceLoader loader;

    @PostConstruct
    public void init() {
        log.info("Retrieving civilStatus");
        Map<String, String> civilStatus = new HashMap<String, String>();
        BufferedReader br = null;
        String line = "";
        String cvsSplitBy = ",";
        Resource input = loader.getResource("classpath:CatalogoEstadoCivil.csv"));
        if (input.isReadable() ) {
            File file = input.getFile();
            br = new BufferedReader(new FileReader(file));
            try {
                while ((line = br.readLine()) != null) {
                    String[] cod = line.split(cvsSplitBy);
                    civilStatus.put(cod[0].trim(), cod[1]);
                }
            } catch (IOException e) {
                logger.error("Error reading file", e_;
            } finally {
                if (br != null) {
                    try { br.close() } catch( IOException e) {}
                }               
            }   
        }   
    }

    public Map<String, String> getCivilStatus() {
        return this.civilStatus;
    }

    public void setResourceLoader(ResourceLoader loader) {
        this.loader=loader;
    }

}

Что-то вроде этого должно работать. Он загружает ваш после того, как bean-компонент создан (этот код, вероятно, можно оптимизировать, используя что-то вроде commons-io). Примечание. Я использовал Springs ResourceLoader для загрузки файла.

person M. Deinum    schedule 13.12.2014
comment
Я с уважением не согласен с этим подходом, потому что он служит цели сегодня, но ограничивает будущие улучшения, такие как время жизни, переполнение на диск и другие функции, обычно предоставляемые фреймворком кэширования. Также это будет связано с большим количеством нежелательного кода шаблона, который можно было бы обработать путем кэширования фреймворка. - person kamoor; 13.12.2014
comment
Там нет шаблонного кода, код такой же, как вы написали. Так что шаблона нет. Кроме того, если вам что-то не нужно сейчас, не усложняйте то, что вам может понадобиться через 10 лет. Вместо использования метода @PostConstruct вы также можете сделать свой геттер ленивым, однако мне действительно не нравится геттер, который делает больше, чем просто получает. - person M. Deinum; 14.12.2014
comment
Спасибо M.Deinum, я проверил ваш код. Но я загружаю более одного файла в свой проект, и по этой причине я думаю, что лучше использовать кеш. Вы правы, я должен оптимизировать свой код с помощью commons-io. Еще раз спасибо. - person nole; 15.12.2014
comment
Или используйте java8, это еще проще. Я до сих пор не вижу причины, по которой вам может понадобиться сложная стратегия кэширования, поскольку это только усложнит ситуацию, в этом случае будет достаточно ленивого геттера. Что касается всех других аспектов кэширования, это не работает с используемым вами решением для кэширования. - person M. Deinum; 15.12.2014

Я полагаю, что вы используете весеннюю загрузку и настраиваете сервер, используя класс, подобный этому (приведенный ниже). Добавьте аннотацию EnableCaching к тому же классу и определите CacheManager, как указано ниже, вместо отдельного класса конфигурации. Это гарантирует, что кеширование будет включено до того, как ваш класс будет инициализирован.

@Configuration
@EnableAutoConfiguration
@ComponentScan
@EnableCaching
@PropertySource(ignoreResourceNotFound = true, value = {"classpath:application.properties"})
@ImportResource(value = { "classpath*:spring/*.xml" })
public class MyBootServer{

public static void main(String args[]){
    ApplicationContext ctx = SpringApplication.run(MyBootServer.class, args);
}

@Bean(name="cacheManager")
public CacheManager getCacheManager() {
...// Your code
}
}

В вашем коде нет ничего плохого. Я проверил вашу конфигурацию в моем примере кода весенней загрузки, и она работает

person kamoor    schedule 13.12.2014
comment
Большое спасибо, вы правы. проблема была в моей конфигурации, я изменил cacheManager и работает нормально. - person nole; 15.12.2014