Spring Boot 集成Redis实现缓存机制

275 阅读7分钟

实现步骤: 1、新建maven项目 2、在pom.xml 文件中添加响应的依赖包 3、编写 Spring Boot 启动类 4、配置 application.properties 5、编写 RedisCacheConfig 配置类 6、编写 DemoInfo 测试实体类 7、编写DemoInfoRespository 持久化类 8、编写DemoInfoService 类 9、编写DemoInfoController 类 10、测试代码是否正常运行了 11、自定义缓存 key

具体实现步骤: 1、新建简单的 maven 项目 2、pom.xml 中添加依赖包,主要有:springboot 父节点依赖,springboot web 支持,缓存服务 spring- context- support,添加redis 支持,JPA操作数据库,MySql 数据库驱动:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven 4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.kfit</groupId>
     <artifactId>spring-boot-redis</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <packaging>jar</packaging>
     <name>spring-boot-redis</name>
     <url>http://maven.apache.org</url>
     <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <!--配置JDK编译版本. -->
           <java.version>1.8</java.version>
     </properties>
     <!-- spring boot父节点依赖,
                 引入这个之后相关的引入就不需要添加version配置,
                   spring boot会自动选择最合适的版本进行添加。
           -->
           <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>1.3.3.RELEASE</version>
           </parent>
     <dependencies>
              <dependency>
                         <groupId>junit</groupId>
                         <artifactId>junit</artifactId>
                         <scope>test</scope>
                  </dependency>
                  <!-- springboot web支持:mvc,aop... -->
                  <dependency>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-web</artifactId>
                  </dependency>
                  <!--
                        包含支持UI模版(Velocity,FreeMarker,JasperReports),
                        邮件服务,
                        脚本服务(JRuby),
                        缓存Cache(EHCache),
                        任务计划Scheduling(uartz)。
                   -->
                  <dependency>
                 <groupId>org.springframework</groupId>
                 <artifactId>spring-context-support</artifactId>
               </dependency>
                  <!-- 添加redis支持-->
                  <dependency>
                <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-redis</artifactId>
            </dependency>
                  <!-- JPA操作数据库. -->
                  <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-data-jpa</artifactId>
               </dependency>
                  <!-- mysql数据库驱动. -->
                  <dependency>
                 <groupId>mysql</groupId>
                 <artifactId>mysql-connector-java</artifactId>
               </dependency>
               <!-- 单元测试. -->
                  <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
     </dependencies>
    </project>

3、编写SpringBoot 启动类

package com.kfit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * Spring Boot启动类;
 * @version v.0.1
 */
@SpringBootApplication
public class App {
       /**
        *-javaagent:.\lib\springloaded-1.2.4.RELEASE.jar -noverify
        * @param args
        */
       public static void main(String[] args) {
              SpringApplication.run(App.class,args);
       }
}

4、配置 application.properties 
主要配置三个资源:
a、数据库基本信息
b、redis 配置
c、JPA的配置

###datasource 配置MySQL数据源;
    spring.datasource.url=jdbc:mysql://localhost:3306/test
    spring.datasource.username= root
    spring.datasource.password= root
    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.max-active=20
    spring.datasource.max-idle=8
    spring.datasource.min-idle=8
    spring.datasource.initial-size=10
    ###REDIS (RedisProperties) redis基本配置;
     #database name
    spring.redis.database=0
    #server host1
    spring.redis.host=127.0.0.1  
    #server password
    #spring.redis.password=
    #connection port
    spring.redis.port=6379
    #pool settings ...
    spring.redis.pool.max-idle=8
    spring.redis.pool.min-idle=0
    spring.redis.pool.max-active=8
    spring.redis.pool.max-wait=-1
    #name of Redis server
    #spring.redis.sentinel.master=
    #comma-separated list of host:portpairs
    #spring.redis.sentinel.nodes=
    ###Java Persistence Api自动进行建表
    #Specify the DBMS
    spring.jpa.database= MYSQL
    #Show or not log for each sqlquery
    spring.jpa.show-sql= true
    #Hibernate ddl auto (create,create-drop, update)
    spring.jpa.hibernate.ddl-auto= update
    #Naming strategy
    spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
    #stripped before adding them tothe entity manager)
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

5、编写 RedisCacheConfig 配置类 缓存主要有几个要实现的类:a、 CacheManager 缓存管理器,b、具体操作实现类 ,c、CacheManager 工厂类 (这个可以使用配置文件配置的进行注入,也可以通过编码的方式进行实现),d、缓存key生产策略 (当然Spring自带生成策略,但是在Redis 客户端 进行查看的话是序列化的key,这里我们使用自带的缓存策略)

 
    package com.kfit.config;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    /**
     *redis 缓存配置;
     *注意:RedisCacheConfig这里也可以不用继承 :CachingConfigurerSupport,也就是直接一个普通的Class就好了;
     *这里主要我们之后要重新实现 key的生成策略,只要这里修改KeyGenerator,其它位置不用修改就生效了。
     *普通使用普通类的方式的话,那么在使用@Cacheable的时候还需要指定KeyGenerator的名称;这样编码的时候比较麻烦。
     *@version v.0.1
     */
    @Configuration
    @EnableCaching //启用缓存,这个注解很重要;
    public class RedisCacheConfig extends CachingConfigurerSupport {
           /**
            *缓存管理器.
            *@param redisTemplate
            *@return
            */
           @Bean
           public CacheManager cacheManager(RedisTemplate<?,?>redisTemplate) {
                  CacheManager cacheManager = new RedisCacheManager(redisTemplate);
                  return cacheManager;
           }
           /**
            *redis模板操作类,类似于jdbcTemplate的一个类;
            *虽然CacheManager也能获取到Cache对象,但是操作起来没有那么灵活;
            *这里在扩展下:RedisTemplate这个类不见得很好操作,我们可以在进行扩展一个我们
            *自己的缓存类,比如:RedisStorage类;
            *@param factory :通过Spring进行注入,参数在application.properties进行配置;
            *@return
            */
           @Bean
           public RedisTemplate<String, String> redisTemplate(RedisConnectionFactoryfactory) {
                  RedisTemplate<String,String> redisTemplate = new RedisTemplate<String, String>();
                  redisTemplate.setConnectionFactory(factory);
                  //key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误;
                  //所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer
                  //或者JdkSerializationRedisSerializer序列化方式;
    //           RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
    //           redisTemplate.setKeySerializer(redisSerializer);
    //           redisTemplate.setHashKeySerializer(redisSerializer);
                  return redisTemplate;
           }
    }

注释: RedisCacheConfig 可以不用继承 CacheConfigurerSupport,直接一个普通的Class就可以了。这里主要我们实现之后要重新实现key的生成策略,只要这里修改 KeyGenerator , 其他位置不用修改就生效了。普通使用普通类的方式的话,那么在使用 @Cache 注解的时候还需要指定 keyGenerator 的名称,这样编码的话比较麻烦。

6、编写 DemoInfo 测试实体类


    import java.io.Serializable;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    /**
     *测试实体类,这个随便;
     *@version v.0.1
     */
    @Entity
    public class DemoInfo  implements Serializable{
           private static final long serialVersionUID = 1L;
           @Id @GeneratedValue
           private long id;
           private String name;
           private String pwd;
           public long getId() {
                  returnid;
           }
           public void setId(long id) {
                  this.id = id;
           }
           public String getName() {
                  returnname;
           }
           public void setName(String name) {
                  this.name = name;
           }
           public String getPwd(){
                  returnpwd;
           }
           public void setPwd(String pwd) {
                  this.pwd = pwd;
           }
           @Override
           public String toString() {
                  return "DemoInfo [id=" + id + ",name=" + name + ", pwd=" + pwd + "]";
           }
    }

7、编写 DemoInfoRespository 持久化类:使用SpringDataJPA实现

 import org.springframework.data.repository.CrudRepository;
        import com.kfit.bean.DemoInfo;
        /**
         * DemoInfo持久化类
         *@version v.0.1
         */
        public interface DemoInfoRepository extends CrudRepository<DemoInfo,Long> {
        }

8、编写 DemoInfoService类 有两个技术方面: a、使用Spring @Cacheable 直接方式和 RedisTemplate 对象进行操作。 DemoInfoService:



   import com.kfit.bean.DemoInfo;
    /**
     * demoInfo服务接口
     *@version v.0.1
     */
    public interface DemoInfoService{
        public DemoInfo findById(longid);
        public void deleteFromCache(longid);
        void test();
    }
    DemoInfoImpl:
    import javax.annotation.Resource;
    import org.springframework.cache.annotation.CacheEvict;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.stereotype.Service;
    import com.kfit.bean.DemoInfo;
    import com.kfit.repository.DemoInfoRepository;
    import com.kfit.service.DemoInfoService;
    /**
     *DemoInfo数据处理类
     *@version v.0.1
     */
    @Service
    publicclass DemoInfoServiceImpl implements DemoInfoService{
           @Resource
           private DemoInfoRepository demoInfoRepository;
           @Resource
           private RedisTemplate<String,String> redisTemplate;
           @Override
           public void test(){
                  ValueOperations<String,String> valueOperations = redisTemplate.opsForValue();
                  valueOperations.set("mykey4", "random1="+Math.random());
                  System.out.println(valueOperations.get("mykey4"));
           }
           //keyGenerator="myKeyGenerator"
           @Cacheable(value="demoInfo") //缓存,这里没有指定key.
           @Override
           public DemoInfo findById(longid) {
                  System.err.println("DemoInfoServiceImpl.findById()=========从数据库中进行获取的....id="+id);
                  return demoInfoRepository.findOne(id);
           }
           @CacheEvict(value="demoInfo")
           @Override
           publicvoid deleteFromCache(longid) {
                  System.out.println("DemoInfoServiceImpl.delete().从缓存中删除.");
           }
    }

9、编写 DemoInfoController 类


    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import com.kfit.bean.DemoInfo;
    import com.kfit.service.DemoInfoService;
    /**
     *测试类.
     *@version v.0.1
     */
    @Controller
    public class DemoInfoController {
           @Autowired
           DemoInfoService demoInfoService;
           @RequestMapping("/test")
           public @ResponseBody String test(){
               DemoInfo loaded = demoInfoService.findById(1);
               System.out.println("loaded="+loaded);
               DemoInfo cached = demoInfoService.findById(1);
               System.out.println("cached="+cached);
               loaded = demoInfoService.findById(2);
               System.out.println("loaded2="+loaded);
               return"ok";
           }
           @RequestMapping("/delete")
           public @ResponseBody String delete(longid){
               demoInfoService.deleteFromCache(id);
               return"ok";
           }
           @RequestMapping("/test1")
           public @ResponseBody String test1(){
               demoInfoService.test();
               System.out.println("DemoInfoController.test1()");
               return"ok";
           }
    }

10、测试代码是否正常运行了 启动程序,访问地址:http://127.0.0.1:8080/test 查看控制台(如果显示如下,即表示成功):

 DemoInfoServiceImpl.findById()=========从数据库中进行获取的....id=1
        loaded=DemoInfo [id=1, name=张三, pwd=123456]
        cached=DemoInfo [id=1, name=张三, pwd=123456]
        DemoInfoServiceImpl.findById()=========从数据库中进行获取的....id=2
        loaded2=DemoInfo [id=2, name=张三, pwd=123456]

11、自定义缓存 key 在RedisCacheConfig 类中重写 CacheConfigurerSupport 中的 keyGenerator ,具体实现:


      /**
        *自定义key.
        *此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一 
        *样,key也会不一样。
      */
      @Override
      public KeyGeneratorkeyGenerator() {
         System.out.println("RedisCacheConfig.keyGenerator()");
         return new KeyGenerator(){
              @Override
              public Objectgenerate(Object o, Method method, Object... objects) {
                 // This willgenerate a unique key of the class name, the method name
                 //and allmethod parameters appended.
                 StringBuilder sb = new StringBuilder();
                 sb.append(o.getClass().getName());
                 sb.append(method.getName());
                 for (Object obj : objects) {
                      sb.append(obj.toString());
                 }
                 System.out.println("keyGenerator=" + sb.toString());
                 return sb.toString();
                     }
              };
       }

这时候在 redis 的客户端查看 key 的话还是序列化的乱码,那么我们可以改变 key 的序列化方式, redis 底层已经有具体的实现类了,我们只需要配置下: //key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误; //所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer //或者JdkSerializationRedisSerializer序列化方式; RedisSerializerredisSerializer =newStringRedisSerializer();//Long类型不可以会出现异常信息; redisTemplate.setKeySerializer(redisSerializer); redisTemplate.setHashKeySerializer(redisSerializer);

综上:RedisCacheConfig 类的方法更改为:

 import java.lang.reflect.Method;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.interceptor.KeyGenerator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    /**
     *redis 缓存配置;
     *注意:RedisCacheConfig这里也可以不用继承 :CachingConfigurerSupport,也就是直接一个普通        
     *的Class就好了;
     *这里主要我们之后要重新实现 key的生成策略,只要这里修改KeyGenerator,其它位置不用修改就生 
     *效了。
     *普通使用普通类的方式的话,那么在使用@Cacheable的时候还需要指定KeyGenerator的名称;这样编码 
     *的时候比较麻烦。
     *@version v.0.1
     */
    @Configuration
    @EnableCaching//启用缓存,这个注解很重要;
    public class RedisCacheConfig extends CachingConfigurerSupport {
           /**
            *缓存管理器.
            *@param redisTemplate
            *@return
            */
           @Bean
           public CacheManager cacheManager(RedisTemplate<?,?>redisTemplate) {
                  CacheManager cacheManager = new RedisCacheManager(redisTemplate);
                  returncacheManager;
           }
 
           /**
            * RedisTemplate缓存操作类,类似于jdbcTemplate的一个类;
            *虽然CacheManager也能获取到Cache对象,但是操作起来没有那么灵活;
            *这里在扩展下:RedisTemplate这个类不见得很好操作,我们可以在进行扩展一个我们
            *自己的缓存类,比如:RedisStorage类;
            *@param factory :通过Spring进行注入,参数在application.properties进行配置;
            *@return
            */
           @Bean
           public RedisTemplate<String, String> redisTemplate(RedisConnectionFactoryfactory) {
                  RedisTemplate<String,String> redisTemplate = new RedisTemplate<String, String>();
                  redisTemplate.setConnectionFactory(factory);
                  //key序列化方式;(不然会出现乱码;),但是如果方法上有Long等非String类型的话,会报类型转换错误;
                  //所以在没有自己定义key生成策略的时候,以下这个代码建议不要这么写,可以不配置或者自己实现ObjectRedisSerializer
                  //或者JdkSerializationRedisSerializer序列化方式;
                  RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
                  redisTemplate.setKeySerializer(redisSerializer);
                  redisTemplate.setHashKeySerializer(redisSerializer);
                  returnredisTemplate;
           }
 
           /**
            *自定义key.
            *此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样,key也会不一样。
            */
           @Override
           public KeyGenerator keyGenerator() {
                  System.out.println("RedisCacheConfig.keyGenerator()");
                  return new KeyGenerator(){
                         @Override
                         public Object generate(Object o, Method method, Object... objects) {
                                // This willgenerate a unique key of the class name, the method name
                                //and allmethod parameters appended.
                                StringBuilder sb = new StringBuilder();
                                sb.append(o.getClass().getName());
                                sb.append(method.getName());
                                for (Object obj : objects) {
                                      sb.append(obj.toString());
                                }
                                System.out.println("keyGenerator=" + sb.toString());
                                return sb.toString();
                         }
                  };
           }
    }  

再访问地址:http:127.0.0.1:8080/test 这时候看到的 key 就是 :com.kfit.service.impl.DemoInfoServiceImplfindById1

我是进阶的球儿,大家一起2019年的爬坑历程。感觉分享很给力的话给个赞,谢谢!!!有问题也可以下方留言沟通。