Pull to refresh

Кэширование данных в приложениях с Spring 3, размещенных в AppEngine

Reading time7 min
Views6.4K
В этой статье я расскажу как можно кэшировать в memcache значения, возвращаемые методами bean'ов. Для этого не потребуется писать код, достаточно добавить конфигурации в xml файлы Spring'а и разметить код с помощью аннотаций.

Итак поредставим что у нас есть DAO с тремя методами — двумя для поиска сущностей и одним для сохранения сущностей. Для правильного функционирования нам нужен интерфейс и реализующий его класс (чтобы можно было добавить dynamic proxy на реализацию)


public interface SampleDAO {
    public Sample findById(int id);

    public Sample findByUrl(String url);

    public void save(Sample sample);
}

public class SampleDAOImpl  implements SampleDAO {
    public Sample findById(int id) { /* какой-то код */ }

    public Sample findByUrl(String url) { /* какой-то код */ }

    public void save(Sample sample) { /* какой-то код */ }
}


* This source code was highlighted with Source Code Highlighter.


И описание bean'а в конфигурации Spring'а

<bean id="sampleDAO" class="SampleDAOImpl">
    <property name="persistenceManagerFactory" ref="persistenceManagerFactory"/>
</bean>


* This source code was highlighted with Source Code Highlighter.


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

Необходимо скачать последнюю версию исходников отсюда http://github.com/abashev/spring-modules и собрать их.

$ git clone git://github.com/abashev/spring-modules.git
$ cd spring-modules/projects
$ mvn install                        // Тут будет много ошибок, но нужный xml файл установится
$ cd spring-modules-cache
$ mvn install -DskipTests


* This source code was highlighted with Source Code Highlighter.


А теперь начинается уличная магия :) Добавляем аннотации в реализацию DAO

public class SampleDAOImpl {
    @Cacheable(modelId = "findByOldId")
    public Sample findById(int id) { /* какой-то код */ }

    @Cacheable(modelId = "findByUrl")
    public Sample findByUrl(String url) { /* какой-то код */ }

    @CacheFlush(modelId = "save")
    public void save(Sample sample) { /* какой-то код */ }
}


* This source code was highlighted with Source Code Highlighter.


Добавляем менеджер кэша в Spring context

<!-- Cache manager for Jsr107 cache -->
<bean id="cacheManager" class="org.springmodules.cache.provider.jsr107.Jsr107CacheManagerFactoryBean"/> 


* This source code was highlighted with Source Code Highlighter.


Объект cacheFacade используется для создания кэшей и настройки их параметров. Для того чтобы добавить специальные свойства для кэшей (для GAE это может быть настройка namespace и expire) необходимо переопределить свойство «cacheProperties».

<bean id="cacheProviderFacade" class="org.springmodules.cache.provider.jsr107.Jsr107CacheFacade">
    <property name="cacheManager" ref="cacheManager" />
    <property name="cacheProperties">
        <map>
            <entry key="findByOldId">
                <map>
                    <entry key="com.google.appengine.api.memcache.jsr107cache.NAMESPACE" value="findByOldId"/>
                </map>
            </entry>
            <entry key="findByUrl">
                <map>
                    <entry key="com.google.appengine.api.memcache.jsr107cache.NAMESPACE" value="findByUrl"/>
                </map>
            </entry>
        </map>
    </property>
</bean>


* This source code was highlighted with Source Code Highlighter.


Для того Spring корректно обработал аннотации необходимы три bean'а — один attribute collector, один caching interception и один caching advisor. Для обработки аннотации @Cachable

<bean id="cachingAttributeSource" class="org.springmodules.cache.annotations.AnnotationCachingAttributeSource"/>

<bean id="cachingInterceptor" class="org.springmodules.cache.interceptor.caching.MetadataCachingInterceptor">
    <property name="cacheProviderFacade" ref="cacheProviderFacade" />
    <property name="cachingAttributeSource" ref="cachingAttributeSource" />
    <property name="cachingModels">
        <map>
            <!-- Установка соответствия между значением modelId в аннотации и именем кэша -->
            <entry key="findByOldId">
                <bean class="org.springmodules.cache.provider.jsr107.Jsr107CacheCachingModel">
                    <constructor-arg value="findByOldId"/>
                </bean>
            </entry>
            <entry key="findByUrl">
                <bean class="org.springmodules.cache.provider.jsr107.Jsr107CacheCachingModel">
                    <constructor-arg value="findByUrl"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>

<bean id="cachingAttributeSourceAdvisor" class="org.springmodules.cache.interceptor.caching.CachingAttributeSourceAdvisor">
    <constructor-arg ref="cachingInterceptor" />
</bean>


* This source code was highlighted with Source Code Highlighter.


Для обработки @CacheFlush

<bean id="flushingAttributeSource" class="org.springmodules.cache.annotations.AnnotationFlushingAttributeSource"/>

<bean id="flushingInterceptor" class="org.springmodules.cache.interceptor.flush.MetadataFlushingInterceptor">
    <property name="cacheProviderFacade" ref="cacheProviderFacade" />
    <property name="flushingAttributeSource" ref="flushingAttributeSource" />
    <property name="flushingModels">
        <map>
            <!-- Установка соответствия между значением modelId и именем кэша -->
            <entry key="save">
                <bean class="org.springmodules.cache.provider.jsr107.Jsr107CacheFlushingModel">
                    <constructor-arg value="findByOldId, findByUrl"/>
                </bean>
            </entry>
        </map>
    </property>
</bean>

<bean id="flushingAttributeSourceAdvisor" class="org.springmodules.cache.interceptor.flush.FlushingAttributeSourceAdvisor">
    <constructor-arg ref="flushingInterceptor" />
</bean>


* This source code was highlighted with Source Code Highlighter.


И последний штрих

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

* This source code was highlighted with Source Code Highlighter.
Tags:
Hubs:
+23
Comments26

Articles

Change theme settings