Redis缓存配置

对于缓存管理,其实就是四个步骤

  • 第一,在【cache】组件中的pom.xml中加入redis的第三方java客户端jedis的jar包
  • 第二,通过编写一个缓存配置类,来管理连接池
  • 第三,编写缓存服务,提供缓存操作接口
  • 第四,在需要使用缓存服务的【back】服务中,加入项目依赖,其他任何服务需要使用缓存服务,都可以配置类似的依赖
  • 第五,在【back】服务启动配置中加入缓存配置类,以保障缓存服务能再服务启动的时候初始化

  • 第六,在需要使用缓存服务的模块中,编写业务代码,完成缓存操作。

    1. 加入缓存jar包依赖配置

    [sql] view plain copy
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"  
    3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
    5.     <parent>  
    6.         <artifactId>web</artifactId>  
    7.         <groupId>com.aitongyi.web</groupId>  
    8.         <version>1.0-SNAPSHOT</version>  
    9.     </parent>  
    10.     <modelVersion>4.0.0</modelVersion>  
    11.   
    12.     <artifactId>cache</artifactId>  
    13.   
    14.     <properties>  
    15.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
    16.     </properties>  
    17.   
    18.     <dependencies>  
    19.         <!-- CacheService缓存服务中需要用到的对象依赖    -->  
    20.         <dependency>  
    21.             <groupId>com.aitongyi.web</groupId>  
    22.             <artifactId>bean</artifactId>  
    23.             <version>${project.version}</version>  
    24.         </dependency>  
    25.         <!-- Redis依赖    -->  
    26.         <dependency>  
    27.             <groupId>redis.clients</groupId>  
    28.             <artifactId>jedis</artifactId>  
    29.             <version>2.7.2</version>  
    30.         </dependency>  
    31.     </dependencies>  
    32. </project>  

      

    2. 创建配置对象

    Redis缓存配置

    [sql] view plain copy
    1. import org.springframework.beans.factory.annotation.Value;  
    2. import org.springframework.context.annotation.Bean;  
    3. import org.springframework.context.annotation.ComponentScan;  
    4. import org.springframework.context.annotation.Configuration;  
    5. import org.springframework.context.annotation.EnableAspectJAutoProxy;  
    6.   
    7.   
    8. import redis.clients.jedis.JedisPool;  
    9. import redis.clients.jedis.JedisPoolConfig;  
    10.   
    11. @Configuration  
    12. @EnableAspectJAutoProxy  
    13. @ComponentScan(basePackages = {"com.aitongyi.web.cache"})  
    14. public class CacheConfig {  
    15.     /** redis缓存服务器地址    */  
    16.     @Value("${redis.host}")  
    17.     private String host;  
    18.     /** redis缓存服务器端口    */  
    19.     @Value("${redis.port}")  
    20.     private Integer port;  
    21.     /** redis缓存服务器连接超时时间    */  
    22.     @Value("${redis.timeout}")  
    23.     private Integer timeout;  
    24.   
    25.     @Bean(name = "jedisPool")  
    26.     public JedisPool jedispool() {  
    27.         JedisPoolConfig config = new JedisPoolConfig();  
    28.         config.setMaxWaitMillis(30000); //  最大等待时间  
    29.         config.setMaxTotal(32);         //  最大连接数  
    30.         config.setMinIdle(6);           //  允许最小的空闲连接数  
    31.         config.setTestOnBorrow(false);  //  申请到连接时是否效验连接是否有效,对性能有影响,建议关闭  
    32.         config.setTestOnReturn(false);  //  使用完连接放回连接池时是否效验连接是否有效,对性能有影响,建议关闭  
    33.         config.setTestWhileIdle(true);  //  申请到连接时,如果空闲时间大于TimeBetweenEvictionRunsMillis时间,效验连接是否有效,建议开启,对性能有效不大  
    34.         config.setTimeBetweenEvictionRunsMillis(30000); //TestWhileIdle的判断依据  
    35.         return new JedisPool(config, host, port, timeout);  
    36.     }  
    37. }  


    3. 创建缓存服务

    [sql] view plain copy
    1. /**  
    2.  * 缓存服务  
    3.  * Created by admin on 16/8/18.  
    4.  */  
    5. @Component  
    6. public class CacheService {  
    7.     @Autowired  
    8.     private JedisPool jedisPool;  
    9.   
    10.     /**  
    11.      * 设置缓存对象  
    12.      * @param key  
    13.      * @param value  
    14.      */  
    15.     public void set(String key,String value){  
    16.         Jedis jedis = null;  
    17.         try{  
    18.             jedis = jedisPool.getResource();  
    19.             jedis.set(key, value);  
    20.         }finally{  
    21.             if(jedis != null){  
    22.                 jedis.close();  
    23.             }  
    24.         }  
    25.     }  
    26.   
    27.     /**  
    28.      * 获取缓存对象  
    29.      * @param key  
    30.      * @return  
    31.      */  
    32.     public String get(String key){  
    33.         Jedis jedis = null;  
    34.         try{  
    35.             jedis = jedisPool.getResource();  
    36.             return jedis.get(key);  
    37.         }finally{  
    38.             if(jedis != null){  
    39.                 jedis.close();  
    40.             }  
    41.         }  
    42.     }  
    43.   
    44.     /**  
    45.      * 删除缓存对象  
    46.      * @param key  
    47.      */  
    48.     public void del(String key){  
    49.         Jedis jedis = null;  
    50.         try{  
    51.             jedis = jedisPool.getResource();  
    52.             jedis.del(key);  
    53.         }finally{  
    54.             if(jedis != null){  
    55.                 jedis.close();  
    56.             }  
    57.         }  
    58.     }  
    59.   
    60. }  

    4. 对缓存服务的依赖管理

    在【back】服务中的pom.xml中加入【cache】模块的依赖

    [sql] view plain copy
    1. <dependencies>  
    2.         <dependency>  
    3.             <groupId>com.aitongyi.web</groupId>  
    4.             <artifactId>dao</artifactId>  
    5.             <version>${project.version}</version>  
    6.         </dependency>  
    7.         <dependency>  
    8.             <groupId>com.aitongyi.web</groupId>  
    9.             <artifactId>bean</artifactId>  
    10.             <version>${project.version}</version>  
    11.         </dependency>  
    12.         <dependency>  
    13.             <groupId>com.aitongyi.web</groupId>  
    14.             <artifactId>service</artifactId>  
    15.             <version>${project.version}</version>  
    16.         </dependency>  
    17.         <dependency>  
    18.             <groupId>com.aitongyi.web</groupId>  
    19.             <artifactId>task</artifactId>  
    20.             <version>${project.version}</version>  
    21.         </dependency>  
    22.         <!--  缓存模块  -->  
    23.         <dependency>  
    24.             <groupId>com.aitongyi.web</groupId>  
    25.             <artifactId>cache</artifactId>  
    26.             <version>${project.version}</version>  
    27.         </dependency>  

    5. 缓存配置加入项目启动配置中

    在【back】项目中的com.aitongyi.web.back.conf.WebApplicationInitializer类中加入缓存项目的配置类【CacheConfig.class】

    [sql] view plain copy
    1. import com.aitongyi.web.cache.conf.CacheConfig;  
    2. import com.aitongyi.web.dao.conf.DatabaseConfig;  
    3. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;  
    4.   
    5. import javax.servlet.Filter;  
    6.   
    7. /**  
    8.  * 项目启动基类  
    9.  * -- 整个项目的入口  
    10.  */  
    11. public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {  
    12.     /**  
    13.      * 获取配置信息  
    14.      * @return  
    15.      */  
    16.     @Override  
    17.     protected Class<?>[] getRootConfigClasses() {  
    18.         return new Class[] { BackConfig.class, DatabaseConfig.class, SecurityConfig.class, CacheConfig.class};  
    19.     }  
    20.     @Override  
    21.     protected Class<?>[] getServletConfigClasses() {  
    22.         return new Class[] { MvcConfig.class };  
    23.     }  
    24.   
    25.     @Override  
    26.     protected String[] getServletMappings() {  
    27.         return new String[] { "/" };  
    28.     }  
    29.   
    30.     @Override  
    31.     protected Filter[] getServletFilters() {  
    32.         return null;  
    33.     }  
    34. }  


    6. 缓存业务操作代码

    在操作业务代码时,需要一些工具类,比如json操作的fastjson,需要在pom.xml中加入依赖,

    [sql] view plain copy
    1. <dependency>  
    2.     <groupId>com.alibaba</groupId>  
    3.     <artifactId>fastjson</artifactId>  
    4.     <version>1.2.6</version>  
    5. </dependency>  

    然后在用户控制器中加入处理逻辑

    [sql] view plain copy
    1. import com.aitongyi.web.bean.User;  
    2. import com.aitongyi.web.cache.CacheService;  
    3. import com.aitongyi.web.service.UserService;  
    4. import com.alibaba.fastjson.JSON;  
    5. import org.slf4j.Logger;  
    6. import org.slf4j.LoggerFactory;  
    7. import org.springframework.beans.factory.annotation.Autowired;  
    8. import org.springframework.security.access.prepost.PreAuthorize;  
    9. import org.springframework.stereotype.Controller;  
    10. import org.springframework.web.bind.annotation.RequestMapping;  
    11. import org.springframework.web.bind.annotation.RequestMethod;  
    12.   
    13. /**  
    14.  * 用户请求处理器  
    15.  * Created by admin on 16/8/6.  
    16.  */  
    17. @Controller  
    18. public class UserController {  
    19.     private static final Logger logger = LoggerFactory.getLogger(UserController.class);  
    20.   
    21.     @Autowired  
    22.     private UserService userService;  
    23.   
    24.     @Autowired  
    25.     private CacheService cacheService;  
    26.   
    27.     @RequestMapping(value = "/home", method = RequestMethod.GET)  
    28.     @PreAuthorize("isAuthenticated()")// isAuthenticated 如果用户不是匿名用户就返回true  
    29.     public String showHomePage() {  
    30.         try {  
    31.               
    32.             User user = userService.loadUserByUsername("admin");  
    33.   
    34. //            测试缓存服务  
    35. //            缓存用户对象到redis,以用户ID区分  
    36.             cacheService.set("LOGIN_USER_" + user.getId(), JSON.toJSONString(user));  
    37. //            从缓存中取出  
    38.             String userStr = cacheService.get("LOGIN_USER_" + user.getId());  
    39. //            进行反序列化  
    40.             User u = JSON.parseObject(userStr, User.class);  
    41.             if(u != null){  
    42.                 logger.info("user:{}", u);  
    43.             }  
    44.             logger.info("load user ");  
    45.         }catch (Exception e){  
    46.             logger.error(e.getLocalizedMessage(), e);  
    47.         }  
    48.   
    49.         return "/index/index";  
    50.     }  
    51. }  

    当然,直接打印user会出现 @45sd3sdf这样的情况,需要重写User的toString方法

    [sql] view plain copy
    1. import java.util.Date;  
    2.   
    3. /**  
    4.  * Created by admin on 16/8/8.  
    5.  */  
    6. public class User {  
    7.     private Integer id;  
    8.     private String username;  
    9.     private String password;  
    10.     private boolean enabled;  
    11.     private Date createDate;  
    12.   
    13.     public Date getCreateDate() {  
    14.         return createDate;  
    15.     }  
    16.   
    17.     public void setCreateDate(Date createDate) {  
    18.         this.createDate = createDate;  
    19.     }  
    20.   
    21.     public boolean isEnabled() {  
    22.         return enabled;  
    23.     }  
    24.   
    25.     public void setEnabled(boolean enabled) {  
    26.         this.enabled = enabled;  
    27.     }  
    28.   
    29.     public Integer getId() {  
    30.         return id;  
    31.     }  
    32.   
    33.     public void setId(Integer id) {  
    34.         this.id = id;  
    35.     }  
    36.   
    37.     public String getPassword() {  
    38.         return password;  
    39.     }  
    40.   
    41.     public void setPassword(String password) {  
    42.         this.password = password;  
    43.     }  
    44.   
    45.     public String getUsername() {  
    46.         return username;  
    47.     }  
    48.   
    49.     public void setUsername(String username) {  
    50.         this.username = username;  
    51.     }  
    52.   
    53.     @Override  
    54.     public String toString() {  
    55.         final StringBuffer sb = new StringBuffer("User{");  
    56.         sb.append("id=").append(id);  
    57.         sb.append(", username='").append(username).append('\'');  
    58.         sb.append(", password='").append(password).append('\'');  
    59.         sb.append(", enabled=").append(enabled);  
    60.         sb.append(", createDate=").append(createDate);  
    61.         sb.append('}');  
    62.         return sb.toString();  
    63.     }  
    64. }  

    7. 加入数据库配置

    在【back】项目的back.properties中,增加redis和mysql的连接配置

    [sql] view plain copy
    1. #redis  
    2. redis.host = 127.0.0.1  
    3. redis.port = 6380  
    4. redis.timeout = 2000  
    5.   
    6. #========= Mysql ============  
    7. jdbc.driver = com.mysql.jdbc.Driver  
    8. db.url = jdbc:mysql://127.0.0.1/web?useUnicode=true&characterEncoding=UTF-8  
    9. db.username = web  
    10. db.password = 123456  
    11. db.maxtotal = 150  
    12. db.minidle = 40  
    13. db.maxidle = 60  
    这两个配置意味着你需要在本机安装一个redis服务器(默认端口6379),端口是6380,本机安装一个mysql,并创建一个名称为web的库,使用utf-8这个字符集,并且创建一个web的用户,密码是123456,另外需要在数据库中创建两张表,一个是【users】表,用来存储用户信息,另外一个是【authorities】表,用来存储权限信息

    [sql] view plain copy
    1. /*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */;  
    2. /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;  
    3. /*!40101 SET @[email protected]@COLLATION_CONNECTION */;  
    4. /*!40101 SET NAMES utf8 */;  
    5. /*!40014 SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;  
    6. /*!40101 SET @[email protected]@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;  
    7. /*!40111 SET @[email protected]@SQL_NOTES, SQL_NOTES=0 */;  
    8.   
    9.   
    10. # Dump of table authorities  
    11. ------------------------------------------------------------  
    12.   
    13. DROP TABLE IF EXISTS `authorities`;  
    14.   
    15. CREATE TABLE `authorities` (  
    16.   `username` varchar(50) NOT NULL,  
    17.   `authority` varchar(50) NOT NULL,  
    18.   UNIQUE KEY `ix_auth_username` (`username`,`authority`),  
    19.   CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)  
    20. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
    21.   
    22. LOCK TABLES `authorities` WRITE;  
    23. /*!40000 ALTER TABLE `authorities` DISABLE KEYS */;  
    24.   
    25. INSERT INTO `authorities` (`username`, `authority`)  
    26. VALUES  
    27.     ('admin','ROLE_ADMIN');  
    28.   
    29. /*!40000 ALTER TABLE `authorities` ENABLE KEYS */;  
    30. UNLOCK TABLES;  
    31.   
    32.   
    33. # Dump of table users  
    34. ------------------------------------------------------------  
    35.   
    36. DROP TABLE IF EXISTS `users`;  
    37.   
    38. CREATE TABLE `users` (  
    39.   `id` int(11) NOT NULL AUTO_INCREMENT,  
    40.   `username` varchar(50) NOT NULL,  
    41.   `passwordvarchar(50) NOT NULL,  
    42.   `enabled` tinyint(1) NOT NULL,  
    43.   `create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  
    44.   PRIMARY KEY (`id`),  
    45.   UNIQUE KEY `ix_username` (`username`)  
    46. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
    47.   
    48. LOCK TABLES `users` WRITE;  
    49. /*!40000 ALTER TABLE `users` DISABLE KEYS */;  
    50.   
    51. INSERT INTO `users` (`id`, `username`, `password`, `enabled`, `create_date`)  
    52. VALUES  
    53.     (1,'admin','e10adc3949ba59abbe56e057f20f883e',1,'2016-08-18 14:51:06');  
    54.   
    55. /*!40000 ALTER TABLE `users` ENABLE KEYS */;  
    56. UNLOCK TABLES;  

    表创建完成,数据写入完成,启动服务器,运行back这个web项目,就可以看到登录页面,输入用户名admin,密码123456,登录,完成我们的操作。

    然后看看日志,就可以看到存储缓存和打印缓存数据的日志了。如果你有兴趣,还可以在代码上打上断点,用debug模式启动,然后一步步的看运行状态!

    Redis缓存配置


    8. 缓存KEY管理最佳实践

    到此,缓存就说完了,这里要提一下这个redis的key,很多时候我们开发,定义redis中的缓存key很随意,也不规范,结果导致最终key管理混乱,代码管理难度加大。通过我们的项目,可以看到,每个功能基本是分模块的,在缓存中,需要定义一个公共的KEY管理类,所有的key都通过这个公共类来声明,如果要看缓存中定义了那些Key,就可以从这个类中一目了然。

    下面我们就用【UserController】中的一个缓存KEY来做例子说明一下:

    原来的key是这样的:

    [sql] view plain copy
    1. //            缓存用户对象到redis,以用户ID区分  
    2.             cacheService.set("LOGIN_USER_" + user.getId(), JSON.toJSONString(user));  
    3. //            从缓存中取出  
    4.             String userStr = cacheService.get("LOGIN_USER_" + user.getId());  


    通过统一管理,我们要再【cache】模块下创建一个CacheKey:

    [sql] view plain copy
    1. /**  
    2.  * 缓存Key统一管理类  
    3.  * Created by admin on 16/8/18.  
    4.  */  
    5. public class CacheKey {  
    6.   
    7.     /**  
    8.      * <pre>  
    9.      * 登录用户缓存Key  
    10.      * 格式 :  str.login.user.{userId}  
    11.      * </pre>  
    12.      */  
    13.     public static final String LOGIN_USER_KEY = "str.login.user.";  
    14. }  

    然后将原来的代码改为:


    [sql] view plain copy
    1. //            缓存用户对象到redis,以用户ID区分  
    2.             cacheService.set(CacheKey.LOGIN_USER_KEY + user.getId(), JSON.toJSONString(user));  
    3. //            从缓存中取出  
    4.             String userStr = cacheService.get(CacheKey.LOGIN_USER_KEY + user.getId());  

    通过这样的管理,所有用户都统一的缓存Key的使用,如果要查看redis中用了那些缓存key,缓存中的key代表什么意思,就一目了然了。