SpringDI方式及Redis应用场景的分享

2024-05-03 07:20

本文主要是介绍SpringDI方式及Redis应用场景的分享,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、为什么Spring和IDEA 都不推荐使用 @Autowired 注解

        大家在使用IDEA开发的时候有没有注意到过一个提示,在字段上使用Spring的依赖注入注解@Autowired后会出现如下警告Field injection is not recommended (字段注入是不被推荐的)但是使用@Resource却不会出现此提示,那这是为什么呢??

        我们都知道Spring常见的DI方式:

  1. 构造器注入:利用构造方法的参数注入依赖
  2. Setter注入:调用Setter的方法注入依赖
  3. 字段注入:在字段上使用@Autowired/Resource注解

        @Autowired VS @Resource

        事实上,他们的基本功能都是通过注解实现依赖注入,只不过@AutowiredSpring定义的,而@ResourceJSR-250定义的。大致功能基本相同,但是还有一些细节不同:

  1. 依赖识别方式:@Autowired默认是byType,可以使用@Qualifier指定Name,@Resource默认ByName,如果找不到则ByType
  2. 适用对象:@Autowired可以对构造器、方法、参数、字段使用,@Resource只能对方法、字段使用
  3. 提供方:@Autowired是Spring提供的,@Resource是JSR-250提供的

        各种DI方式的优缺点

        参考Spring官方文档,建议了如下的使用场景:

  1. 构造器注入:强依赖性(即必须使用此依赖),不变性(各依赖不会经常变动)
  2. Setter注入:可选(没有此依赖也可以工作),可变(依赖会经常变动)
  3. Field注入:大多数情况下尽量少使用字段注入,一定要使用的话,@Resource相对@Autowired对IoC容器的耦合更低

        Field注入的缺点

  1. 不能像构造器那样注入不可变的对象
  2. 依赖对外部不可见,外界可以看到构造器和setter,但无法看到私有字段,自然无法了解所需依赖
  3. 会导致组件与IoC容器紧耦合(这是最重要的原因,离开了IoC容器去使用组件,在注入依赖时就会十分困难)
  4. 导致单元测试也必须使用IoC容器,原因同上
  5. 依赖过多时不够明显,比如我需要10个依赖,用构造器注入就会显得庞大,这时候应该考虑一下此组件是不是违反了单一职责原则

        为什么IDEA只对@Autowired警告

        Field注入虽然有很多缺点,但它的好处也不可忽略:那就是太方便了。使用构造器或者setter注入需要写更多业务无关的代码,十分麻烦,而字段注入大幅简化了它们。并且绝大多数情况下业务代码和框架就是强绑定的,完全松耦合只是一件理想上的事,牺牲了敏捷度去过度追求松耦合反而得不偿失。

        那么问题来了,为什么IDEA只对@Autowired警告,却对@Resource视而不见呢?

        @AutowiredSpring提供的,它是特定IoC提供的特定注解,这就导致了应用与框架的强绑定,一旦换用了其他的IoC框架,是不能够支持注入的。而@ResourceJSR-250提供的,它是Java标准,我们使用的IoC容器应当去兼容它,这样即使更换容器,也可以正常工作。

2、工作中常用Redis的十种场景

Redis是一种优秀的基于键值型NoSql数据库非关系型

这里有两个关键字:

其中键值型,是指Redis中存储的数据都是以key、value对的形式存储,而value的形式多种多样,可以是字符串、数值、甚至json

而NoSql则是相对于传统关系型数据库而言,有很大差异的一种数据库。

Redis的优点:

  1. 键值(key-value)型,value支持多种不同数据结构,功能丰富
  2. 单线程,每个命令具备原子性
  3. 低延迟,速度快(基于内存、IO多路复用、良好的编码)
  4. 支持数据持久化
  5. 支持主从集群、分片集群
  6. 支持多语言客户端

Redis在工作中的应用列举:

1、计数器

在很多网站首页,会有一些统计首页访问次数的需求,访问次数只有一个字段,如果存到关系型数据库中,最后做汇总会很麻烦。该业务场景可以使用Redis,定义一个key,例如:WEBSITE_VISITS_NUM。

在Redis里有命令incr,实现给value值加1操作:

incr WEBSITE_VISITS_NUM

当然如果你想一次加的值大于1,可以用incrby命令,例如:

Incrby WEBSITE_VISITS_NUM 10  一次加10。

2、分布式锁(单线程,数据安全)

最常见应用场景之一,相对于例如Zookeeper分布式锁,Redis的分布式锁,有更好的性能。

代码奉上:

@Api(tags = "Redis")
@RestController
@RequestMapping("/testRedis")
@Slf4j
public class TestRedisController {private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNamePrefix("shouhu-").setDaemon(true).build();private static final ScheduledExecutorService daemonPool = Executors.newScheduledThreadPool(5,THREAD_FACTORY);@Resourceprivate RedisTemplate<String ,Object> redisTemplate;@GetMapping("/testSetNX")@ApiOperation("SETNX")public ResultVO<Object> testSetNX(@RequestParam Long goodsId){String key = "lock_" + goodsId;String value = UUID.randomUUID().toString();ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();ScheduledFuture<?> scheduledFuture = null;try {// 加锁Boolean ifAbsent = valueOperations.setIfAbsent(key, value, 30, TimeUnit.SECONDS);log.info("加锁{}返回值:{}",key,ifAbsent);if ((null==ifAbsent) || (!ifAbsent)){log.info("加锁失败,请稍后重试!");return ResultUtils.error("加锁失败,请稍后重试!");}// 模拟看门狗逻辑AtomicInteger count = new AtomicInteger(1);scheduledFuture = daemonPool.scheduleWithFixedDelay(() -> {log.info("看门狗第:{}次执行开始", count.get());Object cache = redisTemplate.opsForValue().get(key);if (Objects.nonNull(cache) && (value.equals(cache.toString()))) {// 重新设置有效时间为30秒redisTemplate.expire(key, 30, TimeUnit.SECONDS);log.info("看门狗第:{}次执行结束,有效时间为:{}", count.get(), redisTemplate.getExpire(key));}else {log.info("看门狗执行第:{}次异常:key:{} 期望值:{} 实际值:{}",count.get(), key, value, cache);}count.incrementAndGet();}, 10, 10, TimeUnit.SECONDS);// 执行业务逻辑TimeUnit.SECONDS.sleep(5);log.info("业务逻辑执行结束");}catch (Exception e){log.error("testSetNX exception:",e);return ResultUtils.sysError();}finally {// 释放锁,判断是否是当前线程加的锁String delVal = valueOperations.get(key).toString();if (value.equals(delVal)){Boolean delete = redisTemplate.delete(key);log.info("释放{}锁结果:{}",key,delete);// 关闭看门狗线程if (Objects.nonNull(scheduledFuture)){boolean cancel = scheduledFuture.cancel(true);log.info("关闭看门狗结果:{}",cancel);}}else {log.info("不予释放,key:{} value:{} delVal:{}",key,value,delVal);}}return ResultUtils.success("success");}}
3、缓存加速

这也是工作中非常常用的一种,例如:大宗采购项目中,如果查询检斤化验单数据,先从Redis缓存中查询,如果缓存里存在,则直接拿出数据进行计算,如果不存在,则再去检斤进行查询数据,将数据保存到缓存里。

对于用户而言,下面的流程图也是常见的:

4、交集差集(Redis的无序集合应用)

例如:共同好友、推荐好友功能,我们可以使用到Redis的无序集合,命令如下:

sadd key val val --->添加
sinter key1 key2 ---->交集
sdiff key1 key2 ----->差集
5、排行榜(Redis的有序集合应用)

很多网站有排行榜的功能,比如:商城中有商品销量的排行榜,游戏网站有玩家获得积分的排行榜。这种情况下,我们可以使用Sorted Set保存排行榜的数据。使用ZADD可以添加排行榜的数据,使用ZRANGE可以获取排行榜的数据。

ZADD rank:score 100 "张三"
ZADD rank:score 90 "李四"
ZADD rank:score 80 "王五"
ZRANGE rank:score 0 -1 WITHSCORES

这篇关于SpringDI方式及Redis应用场景的分享的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/956147

相关文章

PostgreSQL的扩展dict_int应用案例解析

《PostgreSQL的扩展dict_int应用案例解析》dict_int扩展为PostgreSQL提供了专业的整数文本处理能力,特别适合需要精确处理数字内容的搜索场景,本文给大家介绍PostgreS... 目录PostgreSQL的扩展dict_int一、扩展概述二、核心功能三、安装与启用四、字典配置方法

MyBatis-Plus 中 nested() 与 and() 方法详解(最佳实践场景)

《MyBatis-Plus中nested()与and()方法详解(最佳实践场景)》在MyBatis-Plus的条件构造器中,nested()和and()都是用于构建复杂查询条件的关键方法,但... 目录MyBATis-Plus 中nested()与and()方法详解一、核心区别对比二、方法详解1.and()

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,