Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力

为什么要使用Redis

  • 及时响应:Redis是一个基于内存的缓存系统,查询、响应的速度快
  • 减少服务调用

开发环境

  • JDK8+
  • Gradle4+
  • Redis 3.2.100
  • Apache HttpClient 4.5.3
  • Spring Boot Web Starter
  • Spring Boot Data Redis Starter

新建项目

复制之前的micro-weather-basic项目,将副本改名为micro-weather-redis
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力

修改源码

修改build.gradle配置,加入redis的依赖:

//依赖关系
dependencies {

    //该依赖用于编译阶段
	compile('org.springframework.boot:spring-boot-starter-web')
	
	//HttpClient
	compile('org.apache.httpcomponents:httpclient:4.5.6')

    //Redis
    compile('org.springframework.boot:spring-boot-starter-data-redis')

    //该依赖用于测试阶段
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

修改WeatherDataServiceImpl.java

package com.study.spring.cloud.weather.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.study.spring.cloud.weather.vo.WeatherResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
public class WeatherDataServiceImpl implements WeatherDataService {

	//在应用中添加日志
	private final static Logger logger=LoggerFactory.getLogger(WeatherDataService.class);

	private static final String WEATHER_URI="http://wthrcdn.etouch.cn/weather_mini?";

	private static final long TIME_OUT=10L;

	@Autowired
	//对rest客户端的封装
	private RestTemplate restTemplate;

	@Autowired
	//对redis api的封装
	private StringRedisTemplate stringRedisTemplate;

	@Override
	public WeatherResponse getDataByCityId(String cityId) {
		
		String uri=WEATHER_URI + "citykey=" + cityId;
		return this.doGetWeather(uri);
	}

	@Override
	public WeatherResponse getDataByCityName(String cityName) {
		
		String uri=WEATHER_URI + "city=" + cityName;
		return this.doGetWeather(uri);
	}
	
	private WeatherResponse doGetWeather(String uri) {

		String key=uri;
		String strBody=null;
		ObjectMapper mapper=new ObjectMapper();
		WeatherResponse resp=null;
		//ValueOperations类可通过get()获取缓存中的数据
		ValueOperations<String,String> ops = stringRedisTemplate.opsForValue();

		//先查缓存,缓存有的取缓存中的数据
		if(stringRedisTemplate.hasKey(key)){
			logger.info("Redis has data");
			strBody = ops.get(key);
		}else{
			logger.info("Redis doesn't have data");
			//缓存没有,再调用服务接口来获取
			//得到json字符串
			ResponseEntity<String> respString = restTemplate.getForEntity(uri, String.class);

			//判断ResponseEntity的状态码是否为200,为200时取出strBody
			if(respString.getStatusCodeValue()==200) {
				strBody=respString.getBody();
			}

			//数据写入缓存
			ops.set(key, strBody, TIME_OUT, TimeUnit.SECONDS);
		}

		//用json反序列化成我们想要的数据
		try {
			/*
			 * strBody:要解析的参数内容,从respString获取
			 * WeatherResponse.class:要转成的对象类型
			 */
			resp=mapper.readValue(strBody,WeatherResponse.class);
		}catch(IOException e) {
			logger.error("Error!",e);
		}
		
		return resp;
	}

}

运行

运行Redis
进入Redis的安装目录:
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
运行结果如下:
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
启动应用:
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
运行结果如下:
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
访问http://localhost:8080/weather/cityId/101020100页面:
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
刷新几次,观察日志输出:
Spring Cloud学习笔记3——天气预报系统(2)用redis提升应用的并发访问能力
证明设置的超时时间10秒是有效的,接下来将测试时使用的10秒改为正式使用时的半小时(即1800秒):

	//在应用中添加日志
	private final static Logger logger=LoggerFactory.getLogger(WeatherDataService.class);

	private static final String WEATHER_URI="http://wthrcdn.etouch.cn/weather_mini?";

	private static final long TIME_OUT=1800L;