This article is a sub-chapter of the personal development framework for SpringBoot2.1. Please read the personal development framework for SpringBoot2.1

Project address: SpringBoot2.1 personal application development framework

Front-end project address: yWH-vuE-admin

Why Redis?

Why Redis cache in a project? In fact, I used Redis cache in my internship, but I just know that I used Redis, how I used it, why I used it, I don’t know anything about it. To quote a sentence on the Internet, THIS integration is Redis for the sake of Redis, not to use Redis to solve actual problems, but I think only after learning the first, can I know under what circumstances I can use Redis to solve problems.

Why redis? Quotes from the Internet

2. Redis is used in projects from two main perspectives: performance and concurrency. 3. Caching is especially suitable for SQL that takes a long time to execute and whose results do not change frequently. Subsequent requests are then read from the cache, allowing the request to respond quickly. 4. In the case of large concurrency, all requests directly access the database, and the database will be abnormal. At this point, you need to do a buffer operation using Redis so that the request accesses Redis first, rather than directly accessing the database. 5. Leaderboards and related issues. The leader Board is sorted by score. The zadd command can do this directly, while the Zrevrange command can be used to obtain the top 100 users by score, and the Zrank command can be used to obtain the user ranking, which is very straightforward and easy to use. 6. Counting problems, such as the number of likes and retweets, are kept counting by atomic increment; Getset resets the counter; The expiration attribute is used to confirm when a keyword should be deleted.

My study notes:

  • Win10 install redis and liunx install redis

  • Redis learns the introduction and implementation of RDB and AOF persistence

Moreover, Redis can backup data in master-slave mode. In distributed system, data backup can be guaranteed well. Redis will automatically back up the data in the master database to the slave database. In addition to reasons in their own projects; For the rest, there are many reasons to learn knowledge and experience on the Internet in advance.

Caching support for SpringBoot

  • Spring Data Redis official documentation

We integrated the cache into the yWH-starter-cache module and introduced the spring-boot-starter-data-redis dependency in the cache pop. XML file

<! -- redis dependency -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.1.1. RELEASE</version>
</dependency>
Copy the code

The cache project structure is divided into

  • Config – Puts configuration classes
  • Serializer – Holds serialized classes
  • Utils – Puts utility classes

Source level analysis

Why do users need to create their own redis configuration class?

SpringBoot provides automatic configuration of Redis. In the RedisAutoConfiguration class, we have client connection (Lettuce and Jedis) configured by default. And data manipulation templates (StringRedisTemplate and RedisTemplate), annotated with @conditionAlonmissingBean and @bean, ConditionalOnMissingBean the @conditionalonmissingBean annotation determines whether the initialization code is executed, meaning that if the user has already created the bean, the relevant initialization code is no longer executed. This results in the redisTemplate method being executed by default.

public class RedisAutoConfiguration {
    public RedisAutoConfiguration(a) {}@Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"})public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        returntemplate; }}Copy the code

RedisTemplate is a data manipulation template class that we can click on and take a look at, and there’s a piece of code in that class

if (this.defaultSerializer == null) {
    this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader ! =null ? this.classLoader : this.getClass().getClassLoader());
}
Copy the code

If the default serialization is NULL, use the JDK to serialize our data. DefaultSerializer is a private property that defaults to NULL. That’s why you need to create a Redis configuration class that overrides the default serialization.

Simple connection

After the analysis, the connection is made in two ways. First: Use StringRedisTemplate and RedisTemplate without changing the default configuration

Before we write the code to test, we need to configure the application-redis.yml file in the cache module. And add the active property in the application.yml file under core with redis separated by commas so that application-redis.yml can be read at runtime. Change the cache module application. Properties file to application-redis. Yml.

spring:
  redis:
    # Redis database index (default 0)
    database: 0
    # Redis server address
    host: 127.0. 01.
    # Redis server connection port
    port: 6379
    # Redis server connection password (default blank) Do not write this property if no password is configured
    password: 123456
    # connection pool
    lettuce:
      pool:
        # maximum number of connections in the pool (use negative values to indicate no limit)
        max-active: 8
        Maximum connection pool blocking wait time (negative value indicates no limit)
        max-wait: 60000
        The maximum number of free connections in the connection pool
        max-idle: 8
        Minimum free connection in connection pool
        min-idle: 0
    Connection timeout (ms)
    timeout: 10000
Copy the code

Write code in the SpringBoot test class and run add data.

@Autowired
private StringRedisTemplate stringRedisTemplate;

/** * test connection to Redis and store data */
@Test
public void redisTest(a){
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    stringRedisTemplate.opsForValue().set("abc"."Test");
    stringRedisTemplate.opsForList().leftPushAll("ywh",list);

}
Copy the code

We’re adding data with StringRedisTemplate and it’s fine, and it’s readable by our human eyes, so let’s add data to Redis using the class RedisTemplate to see what the data looks like, The default serialization JdkSerializationRedisSerializer way of binary data serialization, code as above.

@Autowired
private RedisTemplate<String,Object> redisTemplate;

@Test
public void redisTest1(a){
    List<String> list = new ArrayList<>();
    list.add("y");
    list.add("w");
    list.add("h");
    redisTemplate.opsForValue().set("redisTemplate"."Connection made.");
    redisTemplate.opsForList().leftPushAll("redis",list);
}
Copy the code

The human eye can’t tell what it is, so we’ll override the default configuration and customize our own serialization.

Override the default configuration to connect

Spring provides us with a variety of serialization forms, are all in the org. Springframework. Data. Redis. Serializer package, commonly used are:

  • JdkSerializationRedisSerializer
  • GenericJackson2JsonRedisSerializer
  • StringRedisSerializer
  • Jackson2JsonRedisSerializer

We only use StringRedisSerializer to serialize Key values. Value values are our own serializer class. In the Serializer package, we create our own FastJsonRedisSerializer class. RedisSerializer interface needs to be implemented to realize the serialization method and deserialization method in the interface, using Alibaba Fastjson implementation.

package com.ywh.cache.serializer;

/** * CreateTime: 2018-12-19 16:51 * ClassName: FastJsonRedisSerializer * Package: com.ywh.cache.serializer * Describe: * Custom serialized classes *@author YWH
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    private ObjectMapper objectMapper = new ObjectMapper();
 
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
    private Class<T> clazz;
 
    public FastJsonRedisSerializer(Class<T> clazz) {
        super(a);this.clazz = clazz;
    }
 
    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }
 
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
 
        return JSON.parseObject(str, clazz);
    }
    public void setObjectMapper(ObjectMapper objectMapper) {
        Assert.notNull(objectMapper, "'objectMapper' must not be null");
        this.objectMapper = objectMapper;
    }
 
    protected JavaType getJavaType(Class
        clazz) {
        returnTypeFactory.defaultInstance().constructType(clazz); }}Copy the code

After creating the custom serialized class, override the default configuration. Next, create the RedisCacheConfig class in the Config package. After configuring the Redis configuration class, re-run the test class and find that the values are no longer garble.

package com.ywh.cache.config;
 
/** * CreateTime: 2018-12-18 23:34 * ClassName: RedisCacheConfig * Package: com.ywh.cache.config * Describe: * Redis cache configuration@EnableCachingEnable declarative cache support. Then you can use it@Cacheable/@CachePut/@CacheEvictAnnotations cache data. *@author YWH
 */
@Configuration
@EnableCaching
public class RedisCacheConfig {
 
 
    private RedisConnectionFactory redisConnectionFactory;
 
    @Autowired
    public void setRedisConnectionFactory(RedisConnectionFactory redisConnectionFactory){
        this.redisConnectionFactory = redisConnectionFactory;
    }
 
    /** * override the default configuration *@return RedisTemplate
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(a){
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
 
 
        // Set the serialization rules for value and key
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        template.setDefaultSerializer(fastJsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
 
    /** * Resolve the situation where the values stored in redis by annotations are garbled *@paramFactory Connection factory *@return CacheManager
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
 
        // Configure annotation serialization
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        RedisCacheConfiguration redisCacheConfiguration =
                config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer))
                        // Configure the default expiration time for annotations
                        .entryTtl(Duration.ofDays(1));
        / / to join white list https://github.com/alibaba/fastjson/wiki/enable_autotype
        ParserConfig.getGlobalInstance().addAccept("com.ywh");
        ParserConfig.getGlobalInstance().addAccept("com.baomidou");
        returnRedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build(); }}Copy the code

Redis tools

Redis can operate on five types, and can be extended by itself. Utility classes we put in the cache module utils package, create RedisUtil utility class, add @Component annotation to the class, give Spring to manage, we can directly fetch @atuowired in other methods.

package com.ywh.cache.utils;
/** * CreateTime: 2018-12-19 17:45 * ClassName: RedisUtil * Package: com.ywh.cache.utils * Describe: * Redis tool class **@author YWH
 */
@Component
public class RedisUtil {
 
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
 
    //---------------------- common --------------------------
 
    /** * specifies the cache expiration time *@param* the key key values@paramTime Cache time *@returnTime <=0 failed */
    public void expire(String key, long time){
        if(time > 0){
            redisTemplate.expire(key,time,TimeUnit.SECONDS);
        }else{
            throw MyExceptionUtil.mxe("The set time cannot be 0 or less than 0!!"); }}/** * Check whether the key exists *@param key
     * @returnTrue Exists false Does not exist */
    public Boolean existsKey(String key){
        returnredisTemplate.hasKey(key); }... Omit the code, the specific code can be viewed at Github}Copy the code