一文讲清楚SpringBoot项目打包jar后运行报错template might not exist - 第514篇
idea springboot woff/woff2/eot/ttf/svg等小图标不显示的问题 - 第515篇
Noisee AI中文站网页版 AI 音乐生成视频全新登场,快来抢先体验——国内第一个登场的中文站来袭 - 516篇
Spring的SmartLifecycle可以没用过,但没听过就不好了!- 第517篇
SpringBoot异常处理机制之自定义404、500错误提示页面 - 518篇
悟纤:师傅,你看看,我写了一个Redis的阻塞队列的通用服务,一开始一个开发接入我这个服务的时候,运行的很正常;当有另外一个开发也接入的时候,就会出现一些数据被另外一个改的现象。
师傅:你这个应该是在服务当中定义了一些配置的属性,这些属性对于某个场景是不变的;当另外一个场景是其它的配置了。
悟纤:师傅,不要这样子,感觉你就像我肚子里的蛔虫,怎么我还没告诉你,你就都不知道了。
师傅:你这个不用是蛔虫,都能猜到,这里说明你对于Spring Boot有些知识还了解的不够透彻。要回来深造下了,O(∩_∩)O哈哈~
悟纤:那师傅赶紧给我深造深造~,我要钱多多,我要买车车,我要变美变瘦变酷酷…
导读
最近在开发一个AI音乐项目(地址在下面)的时候,有个场景应用到了Redis的阻塞队列,一开始只在一个地方进行使用,后来有增加了一个新的应用场景,又引入了一下,就导致里面的属性信息,比如队列名称,阻塞队列对象,比较Comparator构造器,在两个业务上数据就被共用了,但是这又不是我所期望的发生的,那么这个时候要怎么办呢?
有粉丝会有疑问:阻塞队列,Java中不是有并发编程的各种队列,
ConcurrentLinkedDeque、LinkedBlockingQueue、DelayQueue,如果你的数据不牵涉到集群的问题,那么你用java提供的这些库进行开发就好了,但是如果数据要集群问题的,那么就不能这么干了。
回到上面一开始提出的问题,我们要怎么办以及要怎么思考呢?带着疑问和博主一起来探讨和学习一下。
项目体验地址:
https://suno4.cn/#/?i=8NCBS8_WXTT
一、SpringBoot的单例模式
Spring Boot的bean默认注入是单例的,它在Spring容器初始化的时候创建对象;
每次调用单例类的实例对象时,都获得同一个对象。
为什么用单例多例:
之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;可以保证系统中一个类只有一个实例而且该实例和外界通信,解约资源,便于维护;当前需要频繁访问一个对象,可以用单例,避免创建过多的垃圾
二、SpringBoot的多例模式
多例模式:每次调用多例类的实例对象时,会获取到不同的对象(会自建新的对象)。
为什么用多例模式:
之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理。
用单例和多例的标准只有一个:当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;
单例和多例的最大的区别:每次获取的美女是同一个就是单例,每次获取的美女都不一样,那么就是多例。
三、多例模式的使用和失效分析
对于Spring Boot默认情况下是单例的,也就是说,你使用了Spring Boot的注解,@Service、@Componment等注解注入的bean都是单例的,那么这个时候要设置为多例的,只需要在类上添加一个注册@Scope,属性值为:prototype,如下代码:
public class MyService {
但我更希望你这么使用:
public class MyService {
对于这里的value值,可配置的值如下:
(1)ConfigurableBeanFactory.SCOPE_PROTOTYPE,即“prototype”: singleton代表多例。
(2)ConfigurableBeanFactory.SCOPE_SINGLETON,即“singleton” : singleton代表单例。
(3)WebApplicationContext.SCOPE_REQUEST,即“request”: request表示请求,即在一次http请求中,被注解的Bean都是同一个Bean,不同的请求是不同的Bean。
(4)WebApplicationContext.SCOPE_SESSION,即“session”: session表示会话,即在同一个会话中,被注解的Bean都是使用的同一个Bean,不同的会话使用不同的Bean。
为什么我的多例不好使?
为什么明明设置了@Scope(value=”prototype”)的属性,仍然不好使呢?这个就和一些用法上有关系了。
多例模式在进行注入时,不能使用 @Autowired,否则注入的还是单例模式,实现多例模式需要使用工厂模式;
@Autowired 在项目启动时已经将bean实例注入到引用类的成员变量中,因此在调用时是直接引用了已被初始化的成员变量,不会再从bean工厂中获取,因此没办法实现多例。也就是说多例模式,必须从bean工厂获取bean才能够实现。
多例获取方式
注入BeanFactory对象,调用其getBean方法即可:
private BeanFactory factory;
// 此时得到的对象即为多例
MyService myService = factory.getBean(MyService.class);
三、我的情况
那这个单例和多例和我们一开始提出的问题有何关联关系呢?
我们的代码是定义了一些属性属性,如下:
public class RedisBlockingService {
private RedissonClient redissonClient;
private String queueName;
private RBlockingQueue blockingQueue;
private Comparator comparator;
}
这些属性信息,针对不同的业务场景应该会有不同的配置信息,比如针对音乐场景,那么就是音乐创作的队列信息,如果是视频创作,那么就是视频的队列信息。
那么这个时候,第二个后创建的就会把第一个创建的属性给覆盖掉,因为默认是单例的,也是在创建的时候,这些信息会随着单例一起构造出来。
所以这个时候就要使用多例来进行创建,以此来确保针对不同的业务场景,属性值不一样,如下代码:
public class RedisBlockingService {
private RedissonClient redissonClient;
private String queueName;
private RBlockingQueue blockingQueue;
private Comparator comparator;
}
四、灵魂拷问
如下代码:
@Autowired
private RedisBlockingService redisBlockingService;
@Autowired
private RedisBlockingService redisBlockingService1;
以上两个对象是否是同一个对象?(测试对应的Spring Boot版本2.5+)
ES 深度分页问题及针对不同需求下的解决方案[ES系列] - 第509篇
抖音主播/电商人员有福了,利用Suno创作产品宣传,让产品动起来-小米Su7 - 第510篇
Spring Boot整合ElasticSearch实战 - 第511篇
Transaction rolled back because it has been marked as - 第512篇
一文讲清楚SpringBoot项目打包jar后运行报错template might not exist - 第514篇
idea springboot woff/woff2/eot/ttf/svg等小图标不显示的问题 - 第515篇
Noisee AI中文站网页版 AI 音乐生成视频全新登场,快来抢先体验——国内第一个登场的中文站来袭 - 516篇
Spring的SmartLifecycle可以没用过,但没听过就不好了!- 第517篇
SpringBoot异常处理机制之自定义404、500错误提示页面 - 518篇