Redis缓存配置
对于缓存管理,其实就是四个步骤
- 第一,在【cache】组件中的pom.xml中加入redis的第三方java客户端jedis的jar包
- 第二,通过编写一个缓存配置类,来管理连接池
- 第三,编写缓存服务,提供缓存操作接口
- 第四,在需要使用缓存服务的【back】服务中,加入项目依赖,其他任何服务需要使用缓存服务,都可以配置类似的依赖
- 第五,在【back】服务启动配置中加入缓存配置类,以保障缓存服务能再服务启动的时候初始化
-
第六,在需要使用缓存服务的模块中,编写业务代码,完成缓存操作。
1. 加入缓存jar包依赖配置
- <?xml version="1.0" encoding="UTF-8"?>
- <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">
- <parent>
- <artifactId>web</artifactId>
- <groupId>com.aitongyi.web</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cache</artifactId>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <!-- CacheService缓存服务中需要用到的对象依赖 -->
- <dependency>
- <groupId>com.aitongyi.web</groupId>
- <artifactId>bean</artifactId>
- <version>${project.version}</version>
- </dependency>
- <!-- Redis依赖 -->
- <dependency>
- <groupId>redis.clients</groupId>
- <artifactId>jedis</artifactId>
- <version>2.7.2</version>
- </dependency>
- </dependencies>
- </project>
2. 创建配置对象
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.ComponentScan;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.EnableAspectJAutoProxy;
- import redis.clients.jedis.JedisPool;
- import redis.clients.jedis.JedisPoolConfig;
- @Configuration
- @EnableAspectJAutoProxy
- @ComponentScan(basePackages = {"com.aitongyi.web.cache"})
- public class CacheConfig {
- /** redis缓存服务器地址 */
- @Value("${redis.host}")
- private String host;
- /** redis缓存服务器端口 */
- @Value("${redis.port}")
- private Integer port;
- /** redis缓存服务器连接超时时间 */
- @Value("${redis.timeout}")
- private Integer timeout;
- @Bean(name = "jedisPool")
- public JedisPool jedispool() {
- JedisPoolConfig config = new JedisPoolConfig();
- config.setMaxWaitMillis(30000); // 最大等待时间
- config.setMaxTotal(32); // 最大连接数
- config.setMinIdle(6); // 允许最小的空闲连接数
- config.setTestOnBorrow(false); // 申请到连接时是否效验连接是否有效,对性能有影响,建议关闭
- config.setTestOnReturn(false); // 使用完连接放回连接池时是否效验连接是否有效,对性能有影响,建议关闭
- config.setTestWhileIdle(true); // 申请到连接时,如果空闲时间大于TimeBetweenEvictionRunsMillis时间,效验连接是否有效,建议开启,对性能有效不大
- config.setTimeBetweenEvictionRunsMillis(30000); //TestWhileIdle的判断依据
- return new JedisPool(config, host, port, timeout);
- }
- }
3. 创建缓存服务
- /**
- * 缓存服务
- * Created by admin on 16/8/18.
- */
- @Component
- public class CacheService {
- @Autowired
- private JedisPool jedisPool;
- /**
- * 设置缓存对象
- * @param key
- * @param value
- */
- public void set(String key,String value){
- Jedis jedis = null;
- try{
- jedis = jedisPool.getResource();
- jedis.set(key, value);
- }finally{
- if(jedis != null){
- jedis.close();
- }
- }
- }
- /**
- * 获取缓存对象
- * @param key
- * @return
- */
- public String get(String key){
- Jedis jedis = null;
- try{
- jedis = jedisPool.getResource();
- return jedis.get(key);
- }finally{
- if(jedis != null){
- jedis.close();
- }
- }
- }
- /**
- * 删除缓存对象
- * @param key
- */
- public void del(String key){
- Jedis jedis = null;
- try{
- jedis = jedisPool.getResource();
- jedis.del(key);
- }finally{
- if(jedis != null){
- jedis.close();
- }
- }
- }
- }
4. 对缓存服务的依赖管理
在【back】服务中的pom.xml中加入【cache】模块的依赖
- <dependencies>
- <dependency>
- <groupId>com.aitongyi.web</groupId>
- <artifactId>dao</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>com.aitongyi.web</groupId>
- <artifactId>bean</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>com.aitongyi.web</groupId>
- <artifactId>service</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>com.aitongyi.web</groupId>
- <artifactId>task</artifactId>
- <version>${project.version}</version>
- </dependency>
- <!-- 缓存模块 -->
- <dependency>
- <groupId>com.aitongyi.web</groupId>
- <artifactId>cache</artifactId>
- <version>${project.version}</version>
- </dependency>
5. 缓存配置加入项目启动配置中
在【back】项目中的com.aitongyi.web.back.conf.WebApplicationInitializer类中加入缓存项目的配置类【CacheConfig.class】
- import com.aitongyi.web.cache.conf.CacheConfig;
- import com.aitongyi.web.dao.conf.DatabaseConfig;
- import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
- import javax.servlet.Filter;
- /**
- * 项目启动基类
- * -- 整个项目的入口
- */
- public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
- /**
- * 获取配置信息
- * @return
- */
- @Override
- protected Class<?>[] getRootConfigClasses() {
- return new Class[] { BackConfig.class, DatabaseConfig.class, SecurityConfig.class, CacheConfig.class};
- }
- @Override
- protected Class<?>[] getServletConfigClasses() {
- return new Class[] { MvcConfig.class };
- }
- @Override
- protected String[] getServletMappings() {
- return new String[] { "/" };
- }
- @Override
- protected Filter[] getServletFilters() {
- return null;
- }
- }
6. 缓存业务操作代码
在操作业务代码时,需要一些工具类,比如json操作的fastjson,需要在pom.xml中加入依赖,
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.6</version>
- </dependency>
然后在用户控制器中加入处理逻辑
- import com.aitongyi.web.bean.User;
- import com.aitongyi.web.cache.CacheService;
- import com.aitongyi.web.service.UserService;
- import com.alibaba.fastjson.JSON;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.prepost.PreAuthorize;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- /**
- * 用户请求处理器
- * Created by admin on 16/8/6.
- */
- @Controller
- public class UserController {
- private static final Logger logger = LoggerFactory.getLogger(UserController.class);
- @Autowired
- private UserService userService;
- @Autowired
- private CacheService cacheService;
- @RequestMapping(value = "/home", method = RequestMethod.GET)
- @PreAuthorize("isAuthenticated()")// isAuthenticated 如果用户不是匿名用户就返回true
- public String showHomePage() {
- try {
- User user = userService.loadUserByUsername("admin");
- // 测试缓存服务
- // 缓存用户对象到redis,以用户ID区分
- cacheService.set("LOGIN_USER_" + user.getId(), JSON.toJSONString(user));
- // 从缓存中取出
- String userStr = cacheService.get("LOGIN_USER_" + user.getId());
- // 进行反序列化
- User u = JSON.parseObject(userStr, User.class);
- if(u != null){
- logger.info("user:{}", u);
- }
- logger.info("load user ");
- }catch (Exception e){
- logger.error(e.getLocalizedMessage(), e);
- }
- return "/index/index";
- }
- }
当然,直接打印user会出现 @45sd3sdf这样的情况,需要重写User的toString方法- import java.util.Date;
- /**
- * Created by admin on 16/8/8.
- */
- public class User {
- private Integer id;
- private String username;
- private String password;
- private boolean enabled;
- private Date createDate;
- public Date getCreateDate() {
- return createDate;
- }
- public void setCreateDate(Date createDate) {
- this.createDate = createDate;
- }
- public boolean isEnabled() {
- return enabled;
- }
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- @Override
- public String toString() {
- final StringBuffer sb = new StringBuffer("User{");
- sb.append("id=").append(id);
- sb.append(", username='").append(username).append('\'');
- sb.append(", password='").append(password).append('\'');
- sb.append(", enabled=").append(enabled);
- sb.append(", createDate=").append(createDate);
- sb.append('}');
- return sb.toString();
- }
- }
7. 加入数据库配置
在【back】项目的back.properties中,增加redis和mysql的连接配置
- #redis
- redis.host = 127.0.0.1
- redis.port = 6380
- redis.timeout = 2000
- #========= Mysql ============
- jdbc.driver = com.mysql.jdbc.Driver
- db.url = jdbc:mysql://127.0.0.1/web?useUnicode=true&characterEncoding=UTF-8
- db.username = web
- db.password = 123456
- db.maxtotal = 150
- db.minidle = 40
- db.maxidle = 60
- /*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */;
- /*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;
- /*!40101 SET @[email protected]@COLLATION_CONNECTION */;
- /*!40101 SET NAMES utf8 */;
- /*!40014 SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
- /*!40101 SET @[email protected]@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
- /*!40111 SET @[email protected]@SQL_NOTES, SQL_NOTES=0 */;
- # Dump of table authorities
- # ------------------------------------------------------------
- DROP TABLE IF EXISTS `authorities`;
- CREATE TABLE `authorities` (
- `username` varchar(50) NOT NULL,
- `authority` varchar(50) NOT NULL,
- UNIQUE KEY `ix_auth_username` (`username`,`authority`),
- CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- LOCK TABLES `authorities` WRITE;
- /*!40000 ALTER TABLE `authorities` DISABLE KEYS */;
- INSERT INTO `authorities` (`username`, `authority`)
- VALUES
- ('admin','ROLE_ADMIN');
- /*!40000 ALTER TABLE `authorities` ENABLE KEYS */;
- UNLOCK TABLES;
- # Dump of table users
- # ------------------------------------------------------------
- DROP TABLE IF EXISTS `users`;
- CREATE TABLE `users` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `username` varchar(50) NOT NULL,
- `password` varchar(50) NOT NULL,
- `enabled` tinyint(1) NOT NULL,
- `create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`id`),
- UNIQUE KEY `ix_username` (`username`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- LOCK TABLES `users` WRITE;
- /*!40000 ALTER TABLE `users` DISABLE KEYS */;
- INSERT INTO `users` (`id`, `username`, `password`, `enabled`, `create_date`)
- VALUES
- (1,'admin','e10adc3949ba59abbe56e057f20f883e',1,'2016-08-18 14:51:06');
- /*!40000 ALTER TABLE `users` ENABLE KEYS */;
- UNLOCK TABLES;
表创建完成,数据写入完成,启动服务器,运行back这个web项目,就可以看到登录页面,输入用户名admin,密码123456,登录,完成我们的操作。
然后看看日志,就可以看到存储缓存和打印缓存数据的日志了。如果你有兴趣,还可以在代码上打上断点,用debug模式启动,然后一步步的看运行状态!
8. 缓存KEY管理最佳实践
到此,缓存就说完了,这里要提一下这个redis的key,很多时候我们开发,定义redis中的缓存key很随意,也不规范,结果导致最终key管理混乱,代码管理难度加大。通过我们的项目,可以看到,每个功能基本是分模块的,在缓存中,需要定义一个公共的KEY管理类,所有的key都通过这个公共类来声明,如果要看缓存中定义了那些Key,就可以从这个类中一目了然。
下面我们就用【UserController】中的一个缓存KEY来做例子说明一下:
原来的key是这样的:
- // 缓存用户对象到redis,以用户ID区分
- cacheService.set("LOGIN_USER_" + user.getId(), JSON.toJSONString(user));
- // 从缓存中取出
- String userStr = cacheService.get("LOGIN_USER_" + user.getId());
通过统一管理,我们要再【cache】模块下创建一个CacheKey:
- /**
- * 缓存Key统一管理类
- * Created by admin on 16/8/18.
- */
- public class CacheKey {
- /**
- * <pre>
- * 登录用户缓存Key
- * 格式 : str.login.user.{userId}
- * </pre>
- */
- public static final String LOGIN_USER_KEY = "str.login.user.";
- }
然后将原来的代码改为:- // 缓存用户对象到redis,以用户ID区分
- cacheService.set(CacheKey.LOGIN_USER_KEY + user.getId(), JSON.toJSONString(user));
- // 从缓存中取出
- String userStr = cacheService.get(CacheKey.LOGIN_USER_KEY + user.getId());
通过这样的管理,所有用户都统一的缓存Key的使用,如果要查看redis中用了那些缓存key,缓存中的key代表什么意思,就一目了然了。