使用Spring Data Redis进行缓存

在下面的示例中,我将向您展示如何使用Spring Data – Redis项目作为Spring 3.1中引入的Spring Cache Abstraction的缓存提供程序。 我对如何使用Spring的基于Java的配置有很多疑问,因此我将同时提供基于XML和Java的配置供您查看。

依存关系

在此示例中使用了以下依赖关系:

<?xml version='1.0' encoding='UTF-8'?>
<project xmlns='http://maven.apache.org/POM/4.0.0'
    xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd'
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.joshuawhite.example</groupId>
    <artifactId>spring-redis-example</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Spring Redis Example</name>
    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.0.2.RELEASE</version>
        </dependency>        
        <!-- required for @Configuration annotation -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.0.0</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

代码和配置

下面的HelloService示例非常简单。 正如您将在实现中看到的那样,它只返回一个字符串,该字符串的前缀是“ Hello”,该字符串在传入的名称之前。

package com.joshuawhite.example.service;

public interface HelloService {

    String getMessage(String name);

}

查看一下HelloServiceImpl类(如下),您可以看到我正在利用Spring的@Cacheable批注为getMessage方法添加缓存功能。 有关此批注功能的更多详细信息,请参阅Cache Abstraction文档 。 为了娱乐,我使用Spring Expression Language(SpEL)定义条件。 在此示例中,仅当传入的名称为“ Joshua”时才缓存方法响应。

package com.joshuawhite.example.service;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service('helloService')
public class HelloServiceImpl implements HelloService {

    /**
     * Using SpEL for conditional caching - only cache method executions when
     * the name is equal to 'Joshua'
     */
    @Cacheable(value='messageCache', condition=''Joshua'.equals(#name)')
    public String getMessage(String name) {
        System.out.println('Executing HelloServiceImpl' +
                        '.getHelloMessage(\'' + name + '\')');

        return 'Hello ' + name + '!';
    }

}

下面的App类包含我们的main方法,用于在基于XML和Java的配置之间进行选择。 每个System.out.println都用于演示何时进行缓存。 提醒一下,我们只希望传入“ Joshua”的方法执行将被缓存。 当我们稍后查看程序输出时,这将更加清楚。

package com.joshuawhite.example;

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.joshuawhite.example.config.AppConfig;
import com.joshuawhite.example.service.HelloService;

public class App {

    public static void main(String[] args) {

        boolean useJavaConfig  = true;
        ApplicationContext ctx = null;

        //Showing examples of both Xml and Java based configuration
        if (useJavaConfig ) {
                ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        }
        else {
                ctx = new GenericXmlApplicationContext('/META-INF/spring/app-context.xml');
        }

        HelloService helloService = ctx.getBean('helloService', HelloService.class);

        //First method execution using key='Josh', not cached
        System.out.println('message: ' + helloService.getMessage('Josh'));

        //Second method execution using key='Josh', still not cached
        System.out.println('message: ' + helloService.getMessage('Josh'));

        //First method execution using key='Joshua', not cached
        System.out.println('message: ' + helloService.getMessage('Joshua'));

        //Second method execution using key='Joshua', cached
        System.out.println('message: ' + helloService.getMessage('Joshua'));

        System.out.println('Done.');
    }

}

请注意,在使用基于XML的配置时,仍使用组件扫描。 您可以看到我在上面的HelloServiceImpl.java第6行上使用@Service批注。 接下来,我们将看看如何配置jedisConnectionFactoryredisTemplatecacheManager

配置JedisConnectionFactory

在此示例中,我选择使用Jedis作为我们的Java客户端,因为它在Redis站点上被列为Java的“推荐”客户端库。 如您所见,设置非常简单。 当我显式设置use-pool = true时,它的源代码指示这是默认设置。 如果未显式设置,则JedisConnectionFactory还提供以下默认值:

  • hostName =” localhost”
  • 端口= 6379
  • 超时= 2000毫秒
  • 数据库= 0
  • usePool = true

注意:尽管数据库索引是可配置的,但是JedisConnectionFactory仅支持一次连接到一个Redis数据库。 由于Redis是单线程的,因此建议您设置Redis的多个实例,而不是在单个进程中使用多个数据库。 这使您可以获得更好的CPU /资源利用率。 如果计划使用redis-cluster,则仅支持单个数据库。 有关连接池中使用的默认值的更多信息,请查看JedisPoolConfig或Apache Commons Pool org.apache.commons.pool.impl.GenericObjectPool.Config以及其中的实现。 org.apache.commons.pool.impl.GenericObjectPool类。

配置RedisTemplate

正如您从Spring“模板”类中所期望的那样, RedisTemplate负责序列化和连接管理,并且( RedisTemplate您正在使用连接池)是线程安全的。 默认情况下,RedisTemplate使用Java序列化( JdkSerializationRedisSerializer )。 请注意,将数据序列化为Redis实质上使Redis成为“不透明”缓存。 虽然其他序列化程序允许您将数据映射到Redis,但我发现序列化(尤其是在处理对象图时)使用起来更快,更简单。 就是说,如果您要求其他非Java应用程序能够访问此数据,则映射是您最好的即用型选择。 我在使用HessianGoogle Protocol Buffers / proststuff方面有丰富的经验。 我将在以后的文章中分享RedisSerializer一些示例实现。

配置RedisCacheManager

配置RedisCacheManager很简单。 提醒一下, RedisCacheManager依赖于RedisTemplate ,后者依赖于连接工厂(在我们的情况下为JedisConnectionFactory ,该连接工厂一次只能连接到一个数据库。 解决方法是,RedisCacheManager可以为您的缓存键设置前缀。

警告:在处理其他缓存解决方案时,Spring的CacheManger通常包含一个由单独的缓存支持的Cache映射(每个实现类似功能的映射)的实现。 使用默认的RedisCacheManager配置,情况并非如此。 根据RedisCacheManager上的javadoc注释,不清楚这是错误还是仅是不完整的文档。

“ ...默认情况下,通过添加前缀(用作名称空间)来保存密钥。”

虽然RedisCacheManager配置的DefaultRedisCachePrefix当然支持此功能,但默认情况下未启用它。 结果,当您向RedisCacheManager询问给定名称的Cache时,它只是创建一个指向相同数据库的新Cache实例。 结果, Cache实例完全相同。 相同的键将在所有Cache实例中检索相同的值。

正如javadoc注释所暗示的那样,前缀可用于设置客户端管理的名称空间(Redis本身不支持此功能),这些名称空间实际上在同一数据库内创建“虚拟”缓存。 您可以通过使用Spring XML或Java配置调用redisCacheManager.setUsePrefix(true)redisCacheManager.setUsePrefix(true)此功能。

<?xml version='1.0' encoding='UTF-8'?>
<beans
    xmlns='http://www.springframework.org/schema/beans'
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns:context='http://www.springframework.org/schema/context'
    xmlns:c='http://www.springframework.org/schema/c'
    xmlns:p='http://www.springframework.org/schema/p'
    xmlns:cache='http://www.springframework.org/schema/cache'
    xsi:schemaLocation='

http://www.springframework.org/schema/beansvhttp://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd'>

    <context:component-scan base-package='com.joshuawhite.example.service' />
    <context:property-placeholder location='classpath:/redis.properties'/>

    <!-- turn on declarative caching -->
    <cache:annotation-driven />

    <!-- Jedis ConnectionFactory -->
    <bean
        id='jedisConnectionFactory'
        class='org.springframework.data.redis.connection.jedis.JedisConnectionFactory'
        p:host-name='${redis.host-name}'
        p:port='${redis.port}'
        p:use-pool='true'/>

    <!-- redis template definition -->
    <bean
        id='redisTemplate'
        class='org.springframework.data.redis.core.RedisTemplate'
        p:connection-factory-ref='jedisConnectionFactory'/>

    <!-- declare Redis Cache Manager -->
    <bean
        id='cacheManager'
        class='org.springframework.data.redis.cache.RedisCacheManager'
        c:template-ref='redisTemplate'/>

</beans>

下面的Java配置与上面的XML配置等效。 人们通常会习惯使用PropertySourcesPlaceholderConfigurer 。 要做到这一点,你需要使用两个 @PropertySource注释和定义PropertySourcesPlaceholderConfigurer豆。 PropertySourcesPlaceholderConfigurer是不够的。

package com.joshuawhite.example.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
@ComponentScan('com.joshuawhite.example')
@PropertySource('classpath:/redis.properties')
public class AppConfig {

 private @Value('${redis.host-name}') String redisHostName;
 private @Value('${redis.port}') int redisPort;

 @Bean
 public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
     return new PropertySourcesPlaceholderConfigurer();
 }

 @Bean
 JedisConnectionFactory jedisConnectionFactory() {
     JedisConnectionFactory factory = new JedisConnectionFactory();
     factory.setHostName(redisHostName);
     factory.setPort(redisPort);
     factory.setUsePool(true);
     return factory;
 }

 @Bean
 RedisTemplate<Object, Object> redisTemplate() {
     RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
     redisTemplate.setConnectionFactory(jedisConnectionFactory());
     return redisTemplate;
 }

 @Bean
 CacheManager cacheManager() {
     return new RedisCacheManager(redisTemplate());
 }

}

这是两种配置都使用的属性文件。 将下面的值替换为您使用的主机和端口。

redis.host-name=yourHostNameHere
redis.port=6379

输出量

最后,这是我们简短的示例应用程序的输出。 请注意,无论我们调用getHelloMessage('Josh')多少次,方法响应都不会被缓存。 这是因为我们定义了一个条件(请参见HelloServiceImpl.java ,第13行),其中仅当名称等于“ Joshua”时才缓存方法响应。 当我们第一次调用getHelloMessage('Joshua')时,将执行该方法。 但是,第二次不是。

Executing HelloServiceImpl.getHelloMessage('Josh')
message: Hello Josh!
Executing HelloServiceImpl.getHelloMessage('Josh')
message: Hello Josh!
Executing HelloServiceImpl.getHelloMessage('Joshua')
message: Hello Joshua!
Executing HelloServiceImpl.getHelloMessage('Joshua')
message: Hello Joshua!
Done.

到此,我们简要概述了使用Spring Data Redis进行缓存的过程。

参考: Joshua White博客博客中来自JCG合作伙伴 Joshua White的Spring Data Redis缓存

翻译自: https://www.javacodegeeks.com/2013/02/caching-with-spring-data-redis.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值