Jedis Experience under Docker

Posted by kristalys on Tue, 17 Sep 2019 03:49:32 +0200

Jedis is a client implementation of the java version of redis. This article shows the basic usage of jedis through some web request-response ex amp les.

Before we start coding, we'll prepare the environment for two server s, two docker containers:

  1. Redis, using redis version 3.2.8, this is a single-machine redis;
  2. tomcat, version 7.0.77-jre8, tomcat mirrors have been slightly customized to official images to support online deployment, see Actual docker, Write Dockerfile Custom tomcat Mirror for Online Deployment of web Applications Instead of doing it yourself, download the bolingcavalry/online_deploy_tomcat:0.0.1 image at hub.docker.com. To support online deployment, add a server node to the servers node in the settings.xml of the local maven environment, as follows:
<server>
       <id>tomcat7</id>
       <username>bolingcavalry</username>
       <password>bolingcavalrypswd</password>
     </server>

The above is just an introduction to the environment. Instead of building one by one, a docker-compose.yml can be built successfully. The docker-compose.yml file contains the following:

version: '2'
services:
  redis001: 
    image: daocloud.io/library/redis:3.2.8
    restart: always
  tomcat001: 
    image: bolingcavalry/online_deploy_tomcat:0.0.1
    links: 
      - redis001:redishost
    ports: 
      - "8080:8080"
    environment:
      TOMCAT_SERVER_ID: tomcat_server_001
    restart: always

Open the console and execute the following commands in the directory where the docker-compose.yml file is located:

docker-compose up -d

When the execution is complete, the environment is successfully set up and you can see the familiar tomcat home page by typing "localhost:8080" into the browser:

[Img-dXCPA2Gd-15682376493)]

Now that the environment is OK, you can start coding. The git address of the source code is git@github.com:zq2599/blog_demos.git. There are several projects in it. The project used in this article is redisdemo, as shown in the red box below:

This is a maven project. First, look at the maven dependencies. In addition to jedis, the dependencies in pom include common libraries such as spring, jstl, common, etc.

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <!-- Indicates that the package was introduced during development and not loaded when published -->
            <scope>test</scope>
        </dependency>
        <!-- spring Core Package -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- Import java ee jar package -->
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
        </dependency>
        <!-- JSTL Label class -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- Images JSON -->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.13</version>
        </dependency>
        <!-- Upload Component Package -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>

        <!-- redis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

Then there is the configuration in web.xml, including the spring mvc configuration and the extension configuration file (spring-extends.xml):

<!-- Spring Profile -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-extends.xml</param-value>
    </context-param>

    <!-- Coding filter -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <async-supported>true</async-supported>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- Spring Monitor -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Prevent Spring Memory Overflow Monitor -->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

    <!-- Spring MVC servlet -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

The next step is java coding, because web requests are multithreaded and concurrent, and multiple threads use redis services at the same time, so we use JedisPool, a connection pool for jedis, to provide instances of jedis services for concurrent requests.

One connection pool is enough, so here's a singleton class, RedisPool, that does the following:

Instantiate a Jedis resource pool object, JedisPool;
Provides services for business threads to acquire and return Jedis;

Next, let's look at the key code for RedisPool, including instantiation, JedisPool creation, getting Jedis, and returning Jedis in four parts:

Instantiation of RedisPool:

public static RedisPool getInstance(){
        if(null==instance) {
            synchronized (RedisPool.class){
                if(null==instance){
                    instance = new RedisPool();
                }
            }
        }

        return instance;
    }

The following is the initialization code for the resource pool. Note that the ADDR parameter in the red box is the ip of the redis server. In this case, the docker container is connected, so the ADDR value is "redishost", which is the same alias the redis container in the link parameter of the tomcat container when it starts:

The following is the getJedis method, which takes a Jedis instance from the resource pool and gives it to the business thread. Since the jedisPool.getResource method is thread-safe, getJedis() can be called by multiple threads simultaneously without locking:

public Jedis getJedis(){
        try {
            if(null!=jedisPool){
                Jedis jedis = jedisPool.getResource();
                return jedis;
            }else{
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

The following is the method that the business thread calls when it returns to the resource pool when it runs out of the Jedis instance. Note that the jedis used this time is version 2.9.0, so continue using jedisPool.returnResource, which will be returned to the resource pool in a new way after version 3.0:

public void returnResource(final Jedis jedis){
        if(jedis!=null){
            //jedis.close() replaces the jedisPool.returnResource(jedis) method to start with version 3.0
            jedisPool.returnResource(jedis);
        }
    }

Once you've finished writing RedisPool, you've solved the source of Jedis. Let's see how to use Jedis:

This article is just an introductory study, so it shows only a few Jedis services that are available through the RedisService interface with the following API s:

/**
     * string Operation, general set key-value
     * @param key
     * @param value
     */
    void strSet(String key, String value);

    /**
     * string Operation, typically get value through key
     * @param key
     * @return
     */
    String setGet(String key);

    /**
     * list Operation, append data to tail
     * @param key
     * @param value
     */
    void listAppend(String key, String value);

    /**
     * list Operations, get said to have data
     */
    List<String> listGetAll(String key);

    /**
     * Specifies whether the key value exists in redis
     * @param key
     * @return
     */
    boolean exists(String key);

Specific implementation In RedisServiceImpl, let's take a look at a few:

@Override
    public void strSet(String key, String value) {
        Jedis jedis = borrowJedis();

        if(null!=jedis){
            jedis.set(key, value);
        }

        returnJedis(jedis);
    }

    @Override
    public String setGet(String key) {
        Jedis jedis = borrowJedis();

        if(null!=jedis){
            String value = jedis.get(key);
            returnJedis(jedis);
            return value;
        }

        return null;
    }

    @Override
    public void listAppend(String key, String value) {
        Jedis jedis = borrowJedis();

        if(null!=jedis){
            jedis.rpush(key, value);
            returnJedis(jedis);
        }
    }

    @Override
    public List<String> listGetAll(String key) {
        List<String> list = null;

        Jedis jedis = borrowJedis();

        if(null!=jedis){
            list = jedis.lrange(key, 0, -1);
            returnJedis(jedis);
        }

        return null==list ? new ArrayList() : list;
    }

You can see that the api provided by Jedis is very similar to the commands on the redis client, such as jedis.get, jedis.lrange, and so on. You can basically find the api by manipulating the command line.

Looking at the last call to RedisService, in this case spring mvc, so let's look at RedisController:

The following four methods represent four url entries:

@RequestMapping("/simpleset")
    public String simpleset(HttpServletRequest request, Model model) {
        addCommon(model);
        return "simple_set";
    }

    @RequestMapping("/simpleget")
    public String simpleget(HttpServletRequest request, Model model) {
        addCommon(model);
        return "simple_get";
    }

    @RequestMapping("/listappend")
    public String listappend(HttpServletRequest request, Model model) {
        addCommon(model);
        return "list_append";
    }

    @RequestMapping("/listgetall")
    public String listgetall(HttpServletRequest request, Model model) {
        addCommon(model);
        return "list_get_all";
    }

For the first simpleset example, enter http://localhost:8080/redisdemo/simpleset in the browser, and the corresponding simpleset method will be called, open simple_get.jsp, as shown below:

After clicking Submit, RedisController's get method is called because the submit address is strget specified in the form:

@RequestMapping("/strget")
    public String get(HttpServletRequest request, Model model) {
        String key = request.getParameter("key");

        String rlt;

        //Determine if key exists in redis
        if(redisService.exists(key)){
            rlt = "simple_get_success";
            String value = redisService.setGet(key);

            model.addAttribute("value", value);
        }else{
            rlt = "check";
            model.addAttribute("exists", "Non-existent");
        }

        model.addAttribute("key", key);

        addCommon(model);
        return rlt;
    }

If key exists, take out the data and jump to the simple_get_success.jsp page; otherwise, jump to the check.jsp page to show different content.

This is an introduction to the basic usage of jedis, see the redisdemo source code for details.

In addition, when deploying a project, use the command mvn clean package -U -Dmaven.test.skip=true tomcat7:redeploy to deploy the project compilation package to tomcat.

Welcome to my public number: programmer Xin Chen

Topics: Java Jedis Spring Redis Docker