Spring boot (5): redis cache usage posture inventory

Time:2020-8-22

Spring boot (5): redis cache usage posture inventory

1. Introduction to redis

Redis is the most widely used memory data storage in the industry. Compared with memcached, redis supports richer data structures, such as hashes, lists, sets, etc., and supports data persistence. In addition, redis also provides some database like features, such as transaction, ha, master-slave database. It can be said that redis has some characteristics of both cache system and database, so it has rich application scenarios. This paper introduces two typical application scenarios of redis in spring boot.

2. Introduction to lettuce

If redis cache has been used in Java applications, theJedisIt must be no stranger,LettuceandJedisSame, it’s all connectedRedis ServerClient program.JedisIt is directly connected in implementationRedis Server, non thread safe in multi-threaded environment, unless using connection pool, for eachJedisInstance increases physical connection.Lettucebe based onNettyStateful redisconnection can be accessed concurrently among multiple threads. It is thread safe and can meet concurrent access in multi-threaded environment. At the same time, it is a scalable design. If one connection instance is not enough, connection instances can be added as needed.

3. How to use spring boot

  • Directly throughRedisTemplateTo use
  • useSpring CacheintegrateRedis
  • adoptSpring SessiondoSessionshare

4. Engineering practice

4.1 engineering dependence pom.xml As follows:

Code listing: spring boot redis/ pom.xml


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.session</groupId>
        <artifactId>spring-session-data-redis</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  • Spring boot starter data redisSpring Boot 2.xThe back layer is no longer usedJedisInstead ofLettuceAs shown in the figure:
  • Commons-pool2: used asredisIf the connection pool is not introduced, an error will be reported.
  • spring-session-data-redis : Spring SessionBring in for sharingSession

Spring boot (5): redis cache usage posture inventory

4.2 configuration file application.yml

Code listing: spring boot redis / SRC / main / resources/ application.yml


server:
  port: 8080
  servlet:
    session:
      timeout: 30m
spring:
  application:
    name: spring-boot-redis
  cache:
    #After using spring cache, you can specify spring.cache.type Just specify it manually. Although it will automatically adapt to the existing cache dependency, the order of priority will affect the use of redis (jcache > ehcache > redis > guava)
    type: REDIS
  redis:
    host: 192.168.0.128
    port: 6379
    password: 123456
    #Connection timeout (MS)
    timeout: 10000
    #Redis has 16 partitions by default. The specific partition is configured here. The default value is 0
    database: 0
    lettuce:
      pool:
        #The maximum number of connections in the connection pool (using a negative value to indicate no limit) defaults to 8
        max-active: 100
        #Maximum blocking wait time of connection pool (negative value indicates unlimited) default - 1
        max-wait: -1
        #The maximum free connection in the connection pool defaults to 8
        max-idle: 8
        #The minimum free connection in the connection pool defaults to 0
        min-idle: 0

There is not much explanation for the configuration here. Notes have been marked for those that need to be explained.

4.3 how to use redistemplate

4.3.1 create entity class User.java

Code listing: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / model/ User.java


@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = 662692455422902539L;
    private Long id;
    private String name;
    private int age;
}

4.3.2 customize redistemplate

By default, templates can only supportRedisTemplate<String, String>In other words, only strings can be saved, which is unfriendly in development. Therefore, it is necessary to customize the template. When the template is customized, you want to use it againStringStorage is now availableStringRedisTemplateThey do not conflict by adding configuration classesRedisCacheConfig.javaThe code is as follows:

Code listing: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / config/ RedisCacheConfig.java


@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisCacheConfig {

    @Bean
    public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

4.3.3 test interface UserController.java

Code list:


@RestController
@Slf4j
public class UserController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    RedisTemplate<String, Serializable> redisCacheTemplate;

    @Autowired
    UserService userService;

    @GetMapping("/test")
    public void test() {
        stringRedisTemplate.opsForValue().set("geekdigging", "https://www.geekdigging.com/");

        log.info ("current get object: {})", stringRedisTemplate.opsForValue ().get("geekdigging"));

        redisCacheTemplate.opsForValue().set("geekdigging.com", new User(1L, "geekdigging", 18));

        User user = (User) redisCacheTemplate.opsForValue().get("geekdigging.com");

        log.info (current acquisition object: {} ", user);
    }
}

4.3.4 testing

Start the service and open the browser link: http://localhost : 8080 / test, check the console log print, as follows:

2019-09-24 23:49:30.191  INFO 19108 --- [nio-8080-exec-1] c.s.s. controller.UserController           : current get object: https://www.geekdigging.com/
2019-09-24 23:49:30.243  INFO 19108 --- [nio-8080-exec-1] c.s.s. controller.UserController           : current access object: user (id = 1, name = geekdigging, age = 18)

The test was successful.

4.4 integrating redis with spring cache

4.4.1 features of spring cache

Spring 3.1 introduces the exciting annotation based cache technology. It is not a specific cache implementation scheme (such as ehcache or redis), but an abstraction of cache usage. By adding a small amount of annotations defined by it in the existing code, the effect of returning objects of cache methods can be achieved.

Spring cache has good flexibility. It can not only use the spring expression language to define the key and various conditions of the cache, but also provide a temporary cache storage scheme out of the box. It also supports the integration with mainstream professional caches such as ehcache, redis and guava.

  • Based on annotation, the existing code can support caching
  • Out of the box with out of the box caching without installing and deploying additional third-party components
  • It supports spring express language and can use any property or method of an object to define the key and condition of cache
  • Support AspectJ and implement caching support for any method through AspectJ
  • It supports user-defined key and user-defined cache manager, which has considerable flexibility and scalability

4.4.2 defining interfaces UserService.java

Code list: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / service/ UserService.java


public interface UserService {
    User save(User user);

    User get(Long id);

    void delete(Long id);
}

4.4.3 interface implementation UserServiceImpl.java

Code listing: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / service / impl/ UserServiceImpl.java


@Service
@Slf4j
public class UserServiceImpl implements UserService {

    private static final Map<Long, User> USER_MAP = new HashMap<>();

    static {
        USER_MAP.put(1L, new User(1L, "geekdigging.com", 18));
        USER_MAP.put(2L, new User(2L, "geekdigging.com", 19));
        USER_MAP.put(3L, new User(3L, "geekdigging.com", 20));
    }

    @CachePut(value = "user", key = "#user.id")
    @Override
    public User save(User user) {
        USER_MAP.put(user.getId(), user);
        log.info (enter the save method, current storage object: {} ", user);
        return user;
    }

    @Cacheable(value = "user", key = "#id")
    @Override
    public User get(Long id) {
        log.info ("enter get method, currently get object: {}", user_ MAP.get (id));
        return USER_MAP.get(id);
    }

    @CacheEvict(value = "user", key = "#id")
    @Override
    public void delete(Long id) {
        USER_MAP.remove(id);
        log.info ("enter the delete method and delete successfully");
    }
}

To facilitate the demonstration of database operations, aMap<Long, User> USER_MAPThe core of this is three annotations@Cacheable@CachePut@CacheEvict

4.4.3.1 @Cacheable

The result of the method is cached according to its request parameters

  • Key: the cached key, which can be empty. If it is specified to be written according to the spiel expression, if it is not specified, it will be combined according to all parameters of the method by default (for example:@Cacheable(value="user",key="#userName")
  • Value: the name of the cache. At least one must be specified (for example:@Cacheable(value="user")perhaps@Cacheable(value={"user1","use2"})
  • Condition: the condition of cache, which can be empty. It is written with spiel and returns true or false. Only if it is true, the cache will be performed (for example:@Cacheable(value = "user", key = "#id",condition = "#id < 10")
4.4.3.2 @CachePut

The result of a method is cached according to its request parameters. Unlike @ cacheable, it triggers a real method call every time

  • Key: same as above
  • Value: same as above
  • Same as above
4.4.3.3 @CachEvict

Empty the cache according to the condition

  • Key: same as above
  • Value: same as above
  • Same as above
  • Allentries: whether to clear all cache contents. The default is false. If true is specified, all caches will be emptied immediately after the method is called (for example:@CacheEvict(value = "user", key = "#id", allEntries = true)
  • Beforeinvocation: whether to empty the method before execution. The default value is false. If true is specified, the cache will be emptied before the method is executed. By default, if an exception is thrown during method execution, the cache will not be emptied (for example:@CacheEvict(value = "user", key = "#id", beforeInvocation = true)

4.4.4 start main class

Code listing: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / spring BootRedisApplication.java


@SpringBootApplication
@EnableCaching
public class SpringBootRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootRedisApplication.class, args);
    }

}
  • A note needs to be added here@EnableCachingOpen spring session.

4.4.5 add test interface

Code list: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / controller/ UserController.java


@GetMapping("/test1")
public void test1() {
    User user = userService.save(new User(4L, "geekdigging.com", 35));

    log.info (current save object: {} ", user);

    user = userService.get(1L);

    log.info (current get object: {} ", user);

    userService.delete(5L);
}

4.4.6 testing

Start the service and open the browser link: http://localhost : 8080 / test, refresh the page and print the console log as follows:

2019-09-25 00:07:21.887  INFO 21484 --- [nio-8080-exec-1] c.s.s. service.impl.UserServiceImpl        : enter the save method. The current storage object is user (id = 4, name)= geekdigging.com , age=35)
2019-09-25 00:07:21.897  INFO 21484 --- [nio-8080-exec-1] c.s.s. controller.UserController           : current save object: user (id = 4, name= geekdigging.com , age=35)
2019-09-25 00:07:21.899  INFO 21484 --- [nio-8080-exec-1] c.s.s. service.impl.UserServiceImpl        : enter the get method. Currently get the object: user (id = 1, name)= geekdigging.com , age=18)
2019-09-25 00:07:21.900  INFO 21484 --- [nio-8080-exec-1] c.s.s. controller.UserController           : current get object: user (id = 1, name= geekdigging.com , age=18)
2019-09-25 00:07:21.901  INFO 21484 --- [nio-8080-exec-1] c.s.s. service.impl.UserServiceImpl        : enter the delete method and delete successfully

Refresh the page again to view the console log:

2019-09-25 00:08:54.076  INFO 21484 --- [nio-8080-exec-7] c.s.s. service.impl.UserServiceImpl        : enter the save method. The current storage object is user (id = 4, name)= geekdigging.com , age=35)
2019-09-25 00:08:54.077  INFO 21484 --- [nio-8080-exec-7] c.s.s. controller.UserController           : current save object: user (id = 4, name= geekdigging.com , age=35)
2019-09-25 00:08:54.079  INFO 21484 --- [nio-8080-exec-7] c.s.s. controller.UserController           : current get object: user (id = 1, name= geekdigging.com , age=18)
2019-09-25 00:08:54.079  INFO 21484 --- [nio-8080-exec-7] c.s.s. service.impl.UserServiceImpl        : enter the delete method and delete successfully

The results are consistent with our expectations. We can see that in the add, delete, and modify query, there is no log output for the query, because it directly obtains the data from the cache, and the addition, modification, and deletion will enterUserServiceImplMethod to execute specific business code.

4.5 session sharing

4.5.1 introduction to spring session

Spring session provides a solution for creating and managing servlet httpsessions. Spring session provides the cluster sessions (clustered sessions) function. By default, external redis is used to store session data, so as to solve the problem of session sharing.

4.5.2 start the main class spring BootRedisApplication.java

Code listing: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / spring BootRedisApplication.java


@SpringBootApplication
@EnableCaching
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SpringBootRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootRedisApplication.class, args);
    }

}
  • Maxinactive intervalinseconds: set the expiration time of the session. After using spring session, the original spring boot configuration file will be displayedapplication.ymlMediumserver.session.timeoutProperty is no longer valid.

4.5.3 add test interface

Code list: spring boot redis / SRC / main / Java / COM / springboot / springbootredis / controller/ UserController.java


@GetMapping("/getBlogUrl")
public String getSessionId(HttpServletRequest request) {
    String url = (String) request.getSession().getAttribute("url");
    if (StringUtils.isEmpty(url)) {
        request.getSession().setAttribute("url", "https://www.geekdigging.com/");
    }
    log.info ("get session content as: {})", request.getSession ().getAttribute("url"));
    return request.getRequestedSessionId();
}

4.5.4 testing

Start the service and open the browser link: http://localhost : 8080 / getblogurl to view the current storage content of redis, as shown in the following figure:

Spring boot (5): redis cache usage posture inventory

Among them, 156933918000 is the failure time, which means that the session fails after this time, and b2522824-1094-478e-a435-554a551bc8bb is the sessionid.

4.5.6 how to share sessions in multiple services

Follow the above steps to configure it again in another project. After startup, the session will be shared automatically.

Example code 5

Sample code GitHub

Sample code gitee

6. Reference

http://emacoo.cn/backend/spri…
https://blog.battcn.com/2018/…

Spring boot (5): redis cache usage posture inventory

If my article is helpful, please scan the code to pay attention to the official account of the author: get the latest dry cargo push: