微服务项目中众多服务需要集成Feign和Redis的解决办法

初始想法

在一个完整的项目中,可能有许多微服务需要集成Feign和Redis来提高效率。
我们正常的想法就是,哪个服务需要就去那个服务集成,这样我们会发现那样不好,大量的重复代码,造成了性能下降,也不便于管理

有要重复使用的代码,抽取成公共方法;
有重复使用的类,抽取成为公共类;
微服务也一样
总结一个字--

我们将Redis和Feign抽取出来,成为一个redis-server模块。需要集成那么直接依赖redis-server服务即可

原理图

微服务项目中众多服务需要集成Feign和Redis的解决办法_第1张图片Redis是需要用Tomcat跑起来的,所以需要添加端口;而feign则不需要

那么有一个问题!

Feign配置中需要自定义接口,那微服务怎么使用Feign呢?

真正的是微服务(如课程服务)集成feign,我们只是抽取接口成为公共模块
配置类上打feign客户端标签@EnableFeignClients(“填接口所在包”) 开启feign即可 (哪个服务需要谁就开启)

集成步骤

  • 注册到Eureka注册中心
  • 集成Config配置中心客户端
  • 集成Jedis操作Redis
  • zuul配置微服务的路由

步骤略过,这里有详细集成步骤
Eureka集成和集群:
https://blog.csdn.net/weixin_45561263/article/details/104347501
Ribbon负载均衡器/Feign/Hystrix断路器/Zuul网关/config 分布式配置:
https://blog.csdn.net/weixin_45561263/article/details/104349726

以我自己练习的项目来集成Redis

redis-server模块中准备RedisUtils工具类



import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.io.IOException;
import java.util.Properties;

/**
 * 获取连接池对象
 */
public enum RedisUtils {
    INSTANCE;
    static JedisPool jedisPool = null;

    static {
        //1 创建连接池配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        //2 进行配置-四个配置
        config.setMaxIdle(1);//最小连接数
        config.setMaxTotal(11);//最大连接数
        config.setMaxWaitMillis(10 * 1000L);//最长等待时间
        config.setTestOnBorrow(true);//测试连接时是否畅通
        //3 通过配置对象创建连接池对象
        Properties properties = null;
        try {
            properties = new Properties();
            properties.load(RedisUtils.class.getClassLoader().getResourceAsStream("redis.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        String host = properties.getProperty("redis.host");
        String port = properties.getProperty("redis.port");
        String password = properties.getProperty("redis.password");
        String timeout = properties.getProperty("redis.timeout");

        jedisPool = new JedisPool(config, host, Integer.valueOf(port),Integer.valueOf(timeout), password);
    }

    //获取连接
    public Jedis getSource() {
        return jedisPool.getResource();
    }

    //关闭资源
    public void closeSource(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }

    }

    /**
     * 设置字符值
     *
     * @param key
     * @param value
     */
    public void set(String key, String value) {
        Jedis jedis = getSource();
        jedis.set(key, value);
        closeSource(jedis);
    }

    /**
     * 设置
     * @param key
     * @param value
     */
    public void set(byte[] key, byte[] value) {
        Jedis jedis = getSource();
        jedis.set(key, value);
        closeSource(jedis);
    }

    /**
     *
     * @param key
     * @return
     */
    public byte[]  get(byte[] key) {
        Jedis jedis = getSource();
        try {
            return jedis.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeSource(jedis);
        }
        return null;

    }

    /**
     * 设置字符值
     *
     * @param key
     */
    public String get(String key) {
        Jedis jedis = getSource();
        try {
            return jedis.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeSource(jedis);
        }

        return null;

    }
}

在resources文件夹中创建redis.properties文件

redis.host=127.0.0.1
redis.port=6379
redis.password=123456
redis.timeout=10000

编写RedisController:实现set,和get方法



import cn.itsource.hrm.util.AjaxResult;
import cn.itsource.redis.utils.RedisUtils;
import org.springframework.web.bind.annotation.*;

@RequestMapping("/redis")
@RestController
public class RedisController {

   
    @PostMapping("/set")//  从请求中获取值,将值设置给对应参数key
    public AjaxResult set(@RequestParam("key") String key,@RequestParam("value") String value){
        RedisUtils.INSTANCE.set(key,value );
        return AjaxResult.me();
    }

    
	@GetMapping("/get/{key}")//PathVariable:将参数key值设置给uri中的key
    public AjaxResult get(@PathVariable("key") String key){
        String result = RedisUtils.INSTANCE.get(key);
        //通过setResultObj方法返回到前台对象
        return AjaxResult.me().setResultObj(result);
    }

}

课程集成Feign实现课程缓存

  • 依赖Feign的模块
<dependency>
                <groupId>cn.itsourcegroupId>
                <artifactId>hrm-redis-feignartifactId>
                <version>1.0-SNAPSHOTversion>
            dependency>
  • 配置类开启Feign
@EnableFeignClients("cn.xxx.redis.feignclients")//开启服务集成feign

通过Redis实现课程缓存(具体思路和步骤)

  1. 查询课程分类的时候先查询Redis
  2. 如果Redis有就组装数据,直接返回(使用Fastjson操作json,即string和json对象之间的转换)
  3. 如果Reids没有就从Mysql中查
  4. Mysql查到之后同步一份到Redis
  5. 返回结果

缓存更新
思路:
在添加,修改,删除的时候重置缓存
即操作完数据之后同步一份到Redis

具体实现代码

/**
 * 

* 课程目录 服务实现类 *

* * @author rjm * @since 2020-02-17 */
@Service public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService { @Autowired private RedisFeignClient redisFeignClient; //操作也使用Redis //controller用什么方法就覆写什么方法 //覆写删除、修改、添加方法 @Override public boolean insert(CourseType entity) { //先对数据库执行操作 boolean result = super.insert(entity); //重置Redis resetRedis(); return result; } @Override public boolean deleteById(Serializable id) { boolean result= super.deleteById(id); //重置Redis resetRedis(); return result; } @Override public boolean updateById(CourseType entity) { boolean result = super.updateById(entity); //重置Redis resetRedis(); return result; } //自定义重置Redis的方法 public List<CourseType> resetRedis(){ //Redis没数据,从数据库中查询 List<CourseType> courseTypes = baseMapper.selectList(null); //将courseTypes数据转换成string类型,同步一份到Redis redisFeignClient.set("course_type", JSON.toJSONString(courseTypes)); return courseTypes; } @Override public List<CourseType> treeData() { //查询使用Redis //集成feign使用Redis List<CourseType> courseTypes = null; //先查询Redis, AjaxResult result = redisFeignClient.get("course_type"); if (result.isSuccess() && result.getResultObj() != null) {//存在数据且不为空 //获取json的数据字符串 String coursetypes = result.getResultObj().toString(); //返回CourseType类型的数据 courseTypes = JSON.parseArray(coursetypes, CourseType.class); } else { courseTypes = resetRedis(); } //先查所有课程分类 wrapper:条件 //在通用impl里有basemapper,上面泛型放什么就是谁的basemapper,直接调用里面的方法 // List courseTypes = baseMapper.selectList(null); /*---------------下面是获取课程多级分类的代码-------------------*/ //准备集合装所有 顶级父亲 List<CourseType> topLevelParentCourseTypes = new ArrayList<>(); //遍历所有课程分类 for (CourseType courseType : courseTypes) { //判断pid,为0即为顶级父亲 //Java里面定义的id是Long包装类型,转成long来和0比较是最准确的 if(courseType.getPid().longValue() == 0){ //将顶级课程分类放入集合中的CourseType中 topLevelParentCourseTypes.add(courseType); } else {//非顶级课程分类,即pid不为0 //遍历非顶级课程分类 //核心思路:各自找各自的父,找到后装进各自父课程类型中的children中 for (CourseType currentCourseTypes : courseTypes) { //当前分类的id和某个分类的pid相等那么这一对就是父子 if(currentCourseTypes.getId().longValue() == courseType.getPid().longValue()){ //父 currentCourseTypes 子 courseType //将子装进父中children里 currentCourseTypes.getChildren().add(courseType); //成功找到一对父子并装好结构,结束该循环。 break; } } } //break后,开始下一次循环找其他的父子并组装 } //返回已经组装好的结构 return topLevelParentCourseTypes; } }

你可能感兴趣的:(微服务项目中众多服务需要集成Feign和Redis的解决办法)