SpringBoot integrate Redis

In 2021, when artificial intelligence is spreading fast and spaceship capitalists are talking about settling on Mars.

Most of our daily Java backend development is tied to SpringBoot, and Redis is no exception. Let’s take a look at how SpringBoot integrates Redis.

The preparatory work

The first is the dependency problem, when creating the project we need to check the NoSQL column Redis, other can depend on the mood;

After Redis is checked, the project is created and you can see the Redis initiator in the pom.xml file

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

Click on the initiator and pull it to the bottom. The bottom layer has been replaced with Jedis, not SpringBoot 2.x. (if you want to change back to Jedis in your configuration file)

<dependency>
  <groupId>io.lettuce</groupId>
  <artifactId>lettuce-core</artifactId>
  <version>6.0.2. RELEASE</version>
  <scope>compile</scope>
</dependency>
Copy the code

It’s 2021, after all, and it’s no surprise that technology is iterating like crazy

Well, why SpringBoot uses lettuce as the underlying layer instead of Jedis?

First, Jedis is implemented as a directly connected Redis Server. If it is not thread-safe in a multi-threaded environment, the only solution is to use connection pooling and add physical connections to each Jedis instance

And the Lettuce connection is based on Netty, connection instances can be shared among multiple threads, there is no thread insecurity. I’ve avoided connection pooling, but I’ve had a few bugs that I haven’t found that I’m interested in looking for. Okay


Auto-configuration class

With no confusion on the dependency side, let’s go to Redis’ auto-configuration class and see what SpringBoot has auto-configured for us

Click on the auto-configuration class to find the properties configuration class we need

By looking at the Properties configuration class, we can clearly see what automatic configuration SpringBoot does for us and what prefix to use if we want to customize it

As mentioned above, by reading this class, we can get some key information as

  • It is no surprise that the custom configuration uses the prefix “spring.redis”
  • The default database used is a database with subscript 0
  • The default host is localhost
  • The default port is 6379
  • .

This means that basically we don’t need to make these changes if we don’t need to change the port and the server is local


Going back to the auto-configuration class from the beginning, let’s take a look at the redisTemplate, the most critical part of Redis that we used SpringBoot to integrate

@Bean
// First comes the annotation, which means that the Bean will only work if the "redisTemplate" does not exist
In other words, if we write a redisTemplate class ourselves and inject it into Spring then the bean will be invalidated
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    // Generics are all Object, which means that we will probably need a strong cast when we use this Object, but we can also write an override Bean for convenience
    // There is no serialization, we need to serialize manually
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}
Copy the code

In addition, because String is the most frequently used data type in Redis, a separate bean is proposed: stringRedisTemplate

@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
   StringRedisTemplate template = new StringRedisTemplate();
   template.setConnectionFactory(redisConnectionFactory);
   return template;
}
Copy the code

test

I have to say, as soon as I get to SpringBoot, I can say less….. Deep not shallow, speak little Then how to water articles ( ̄ _  ̄ | | |)

Using SpringBoot to manipulate Redis is not too difficult, just inject the RedisTemplate mentioned above in the test class

@SpringBootTest
class RedisSpringbootApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
   @Test
   void contextLoads(a) {}}Copy the code

After injection, we can use this instance directly to perform operations on Redis, starting with the simplest String access

	@Test
	void contextLoads(a) {
	    redisTemplate.opsForValue().set("user:1:name"."moluu");
        System.out.println(redisTemplate.opsForValue().get("user:1:name"));
    }
Copy the code

We use the opsForValue().set method in this example to do a String store, where Value is a String

There are seven other data types that you can manipulate in the form of opsForXXX

Switching to the redisTemplate will also work as long as you can remember some of the Redis commands. Just in a different form, its essence is still command

When we run the test class, we can find that we have fetched the String data whose key is “user:1:name”

(Of course, make sure your Redis service is running at runtime; Connect to your local or remote Redis Server using the default configuration in the auto-configuration class or your own custom configuration. If you can’t access it, you can’t access it.)


Although access can be carried out, but we use the local client provided by Redis official query operation will find some problems

There seems to be something wrong with the saved data. In this case, it is just like saving Chinese, with a bunch of escape characters in front; Why is that? Well, it’s very simple serialization

Is JdkSerializationRedisSerializer RedisTemplate used by default, this kind of serialization way will be the key and the value is serialized to an array of bytes, which creates a returns a heap of don’t understand something


Now that serialization is mentioned here are some things to be aware of when storing entity-class objects in Redis

First we create a new entity class

@Component
public class User {
    private String name;
    private int age;
    private int sex;
}    
Copy the code

At this point we create a User object in our test class and pass it in as the value of opsForValue().set()

@Test
void contextLoads(a) {
    User user = new User("moluu".18.1);
    redisTemplate.opsForValue().set("user",user);
    System.out.println(redisTemplate.opsForValue().get("user"));
}
Copy the code

Running the test class at this point gives us an error caused by the fact that our entity class was not serialized

There are two solutions. One is to make the entity class inherit the Serializable interface and serialize it. The other is to serialize an object before its value is passed in through a third-party serialization method

Let’s look at the first one

// Implement Serializable interface
public class User implements Serializable {
    private String name;
    private int age;
    private int sex;
}
Copy the code

After the Serializable interface is implemented by the entity class, our operations will no longer report errors and our entity class objects will be stored in Redis normally


We can also use Json to serialize an entity-class object before its value is passed in; And that’s OK

@Test
void contextLoads(a) throws JsonProcessingException {
    User user = new User("moluu".18.1);
    String jsonUser = new ObjectMapper().writeValueAsString(user);
    // Pass the serialized JSON object as value
    redisTemplate.opsForValue().set("user",jsonUser);
    System.out.println(redisTemplate.opsForValue().get("user"));
}
Copy the code


Custom redisTemplate

Earlier in the comments we said that the default RedisTemplate will only work if the Bean of the same name is not injected;

Writing a RedisTemplate by hand and injecting it into the container will override the default one, so it’s necessary to write the RedisTemplate yourself

As you can see, the default RedisTemplate is both Object; In this way, we often need strong rotation when using the RedisTemaplate

This is unnecessary, so we can rewrite the generic to suit our needs when overriding the RedisTemplate

Serialization is also something we have to deal with, which we don’t seem to need in the JDK


There is nothing to write a custom redisTemplate, you can copy the homework or write something to meet your own needs; Here is an example

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // Change the generic type to String Object for our convenience
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // Json serialization configuration
        // Use JSON to parse objects
        Jackson2JsonRedisSerializer objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        // Escape with ObjectMapper
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectJackson2JsonRedisSerializer.setObjectMapper(om);
        // Serialization of String
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // Key uses String serialization
        template.setKeySerializer(stringRedisSerializer);
        // The hash key also uses String serialization
        template.setHashKeySerializer(stringRedisSerializer);
        // The serialization of Value is jackSon
        template.setValueSerializer(objectJackson2JsonRedisSerializer);
        // The hash value serialization also uses jackSon
        template.setHashValueSerializer(objectJackson2JsonRedisSerializer);
        template.setConnectionFactory(redisConnectionFactory);
        template.afterPropertiesSet();
        returntemplate; }}Copy the code

After the RedisTemplate is written, we remove the Serializable interface inherited from the entity class and test again:

@Test
void contextLoads(a) throws JsonProcessingException {
    User user = new User("moluu".18.1);
    redisTemplate.opsForValue().set("user",user);
    System.out.println(redisTemplate.opsForValue().get("user"));
}
Copy the code

At this point, the test class runs without an error because it has already been serialized; The key and its value will no longer have escaped characters in the local client (not counting quotes).

Here SpringBoot integration Redis is nothing to talk about, not so high level too deep; If you are still confused, please refer to another article


Relax your eyes

Original picture P station address

Painters home page