Статьи

Руководство по абстракции кэша Spring 3.1

Одной из новых функций, представленных в следующей версии Spring 3.1, является абстракция кеша .

Spring Framework обеспечивает поддержку прозрачного добавления кэширования в существующее приложение Spring. Подобно поддержке транзакций , абстракция кэширования позволяет последовательно использовать различные решения для кэширования с минимальным воздействием на код.

По своей сути абстракция применяет кеширование к методам Java, уменьшая, таким образом, количество выполнений на основе информации, доступной в кеше. То есть каждый раз, когда вызывается целевой метод, абстракция будет применять поведение кэширования, проверяя, был ли метод уже выполнен для заданных аргументов. Если это так, то кэшированный результат возвращается без необходимости выполнения фактического метода; если это не так, то метод выполняется, результат кэшируется и возвращается пользователю, так что при следующем вызове метода возвращается кэшированный результат.

Эта концепция, конечно, не является чем-то новым. Вы можете проверить Spring, AspectJ, Ehcache, метод кэширования Aspect. Очень интересный пост от Brian Du Preez , одного из наших партнеров по JCG , в котором используется Aspect Oriented Programming .

Как следует из названия, абстракция кэша не является реальной реализацией, поэтому для хранения данных кэша требуется фактическое хранилище. Как вы уже догадались, поддержка Ehcache предоставляется «из коробки». Существует также реализация, основанная на ConcurrentMap JDK, и вы можете подключить различные внутренние кэши .

Теперь давайте посмотрим пример кода по кешированию абстракции. Для этой цели я буду использовать очень информативную статью Cache Abstraction в Spring 3.1.0.M1 Джеймса Карра , другого нашего партнера по JCG . Обязательно добавьте Javadocs в пакет Spring Cache .

(ПРИМЕЧАНИЕ: оригинальный пост был слегка отредактирован для улучшения читабельности)

Еще одна новая функция, выпущенная вчера, появилась параллельно со мной, пробуя некоторые стратегии кэширования на основе аннотаций. Абстракция кэширования в основном берет соглашение из существующего проекта и делает его частью ядра Spring.

По сути, он представляет новый интерфейс CacheManager , который может быть реализован с помощью конкретной реализации кэша. Оттуда он добавляет несколько новых аннотаций, чтобы сделать методы кешируемыми. Вот пример использования моих предыдущих постов объектов .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.jamescarr.example;
 
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import javax.annotation.PostConstruct;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
 
@Repository
public class MemoryMessageRepository implements MessageRepository {
 
    private static final Logger LOG =
           LoggerFactory.getLogger(MemoryMessageRepository.class);
 
    private final Map<String, Message> messages =
           new ConcurrentHashMap<String, Message>();
 
    @Cacheable("message")
    public Message getMessage(String title){
        LOG.info("Fetching message");
        return messages.get(title);
    }
    @CacheEvict(value="message", key="message.title")
    public void save(Message message){
        LOG.info("Saving message");
        messages.put(message.getTitle(), message);
    }
    public Collection<Message> findAll() {
        return messages.values();
    }
     
    @PostConstruct
    public void addSomeDefaultMessages(){
        save(new Message("Hello", "Hello World"));
        save(new Message("Appointment", "Remember the milk!"));
    }
     
}

Здесь вы заметите, что метод поиска имеет аннотацию @Cachable с именем, которое указывает кэш для хранения. Он также может использовать дополнительные атрибуты, например, ключ, который использует язык выражений для определения ключа из переданных аргументов. Значением по умолчанию является значение всех аргументов метода. В методе сохранения я использую @CacheEvict для удаления кэшированного элемента из кэша, если он уже существует.

Это, конечно, не будет работать само по себе, поэтому вам придется включить его самостоятельно (что хорошо… последнее, что вам нужно, это обнаружить, что производственное приложение кэширует вещи, которые не должны кэшироваться). К сожалению, на момент написания этой статьи я не обнаружил, как это сделать в не-xml, поэтому вот весенний xml-файл, чтобы включить его и использовать ehcache в качестве реализации.

01
02
03
04
05
06
07
08
09
10
11
12
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:cache="http://www.springframework.org/schema/cache"
        xmlns:p="http://www.springframework.org/schema/p"
  <cache:annotation-driven />
   
        <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
        <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
                p:config-location="classpath:com/jamescarr/example/ehcache.xml"/>
 </beans>

Конфигурация ehcache:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <cache name="message"
       maxElementsInMemory="100"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"/>
     
</ehcache>

И, наконец, добавление этого в AppConfiguration, что включает в себя создание простого @ImportResource .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.jamescarr.configuration;
import javax.annotation.PostConstruct;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
 
import com.jamescarr.example.MessagePrinter;
 
@Configuration
@ComponentScan("com.jamescarr.example")
@ImportResource("classpath:com/jamescarr/example/cache-context.xml")
public class AppConfig {
        @Autowired
        private MessagePrinter messagePrinter;
        @PostConstruct
        public void doSomething(){
                messagePrinter.printMessage("Hello");
                messagePrinter.printMessage("Hello");
                 
        }
        public static void main(String[] args) {
                new AnnotationConfigApplicationContext(AppConfig.class);
        }
}

При запуске этого примера должно быть сообщение журнала в первый раз, когда метод вызывается, затем он не виден во второй раз (так как он извлекается из кэша. Это определенно довольно здорово для реализации Memoization для методов, которые могут просто у меня есть некоторые интенсивные вычисления процессора (но дают точные ожидаемые результаты с учетом набора входных данных). Я взволнован, чтобы сделать некоторую дополнительную работу в этой области … Я делал кэширование на уровне метода раньше (это распространено), но это здорово иметь возможность использовать его без необходимости DIY.

Вот и все, ребята. Простое руководство для начала работы с Spring Cache Abstraction от Джеймса Карра . Не забудьте поделиться!

Статьи по Теме: