《国内最全的Spring Boot系列之一》《国内最全的Spring Boot系列之二》《国内最全的Spring Boot系列之三》《国内最全的Spring Boot系列之四》《国内最全的Spring Boot系列之五》
Noisee AI中文站网页版 AI 音乐生成视频全新登场,快来抢先体验——国内第一个登场的中文站来袭 - 516篇
Spring的SmartLifecycle可以没用过,但没听过就不好了!- 第517篇
SpringBoot异常处理机制之自定义404、500错误提示页面 - 518篇
SpringBoot 中多例模式的神秘世界:用法区别以及应用场景,最后的灵魂拷问会吗?- 第519篇
SpringBoot开发的AI导航站技术架构剖析 —— 技术如何选型 - 第520篇
用AI做个视频:
用AI写首歌:
导读
原本是没有计划编写这么一篇文章的,这还得从… 说起….
话说在五百年前的一篇文章中发起了一个投票,答案竟然这么出乎意料:
这么一种投票结果,让我有点担忧,真的害怕在程序中,写了一个大大的bug出来。
准备工作
为了更清晰的进行讲解,我重新简单搭建了一个框架,Spring Boot版本选择的是 3.3.2,定义了一个多例的MyService和一个请求控制类MyController:
MyController如下:
@RestController
@RequestMapping("/my")
public class MyController {
@Autowired
private MyService myService;
@Autowired
private MyService myService1;
@RequestMapping("/test")
public Boolean test(){
System.out.println("myService:"+myService+",myService1:"+myService1);
return myService == myService1;
}
}
至于MyService多例还不知道怎么编写的小伙伴,或者还不清楚什么是多例的,可以关注公众号「SpringBoot」,回复关键词「476」进行查看。
问题分析
大家看看上面的输出地址是否是同一个呢?
以及==是的结果是true还是false呢?
如果你很坚定这里的答案,那么投票就会毫不犹豫的进行选择了。
输出结果如下:
myService:com.example.demo.MyService@6cdb6397,myService1:com.example.demo.MyService@621c907c
==的结果是:false。
这里地址是不一样的,确实是两个地址。
那有小伙伴会有疑问了,在之前的文章不是说过:
为什么明明设置了@Scope(value=”prototype”)的属性,仍然不好使呢?这个就和一些用法上有关系了。
多例模式在进行注入时,不能使用 @Autowired,否则注入的还是单例模式,实现多例模式需要使用工厂模式;
@Autowired 在项目启动时已经将bean实例注入到引用类的成员变量中,因此在调用时是直接引用了已被初始化的成员变量,不会再从bean工厂中获取,因此没办法实现多例。也就是说多例模式,必须从bean工厂获取bean才能够实现。
这段话有几个注意点:
(1)@Autowired在项目启动的时候就会进行注入。
(2)每次会从bean工厂进行获取,从而实现bean的属性的注入。
对于整体的注入逻辑,大家可以去看看源码。这里我简单的做个分析:
如果你能够看到我标出来的那两个注意点,那么我不解读的话,估计你也能明白什么原因了。
首先使用@Autowired注解的,Spring在项目启动的时候都会进行注入,注入的方式是从bean工厂进行获取到bean进行注入。
如果该bean是单例模式,那么就直接获取到单例的bean就可以完成注入;
如果该bean是多例模式,那么会调用beanFactory进行获取到多例的bean。
所以你如果对于一个多例的bean多次引入或者在多个类中进行引入使用,那么获取到的是多个实例,而不是但实例。
那么这句话要如何解读呐?
多例模式在进行注入时,不能使用 @Autowired,否则注入的还是单例模式,实现多例模式需要使用工厂模式;
这里面的一个意思就是在一个类注入一个属性时是单例的,这么理解就通了,对于上面的测试方法,你在访问一次:
第一次:
myService:com.example.demo.MyService@6cdb6397,myService1:com.example.demo.MyService@621c907c
第二次:
myService:com.example.demo.MyService@6cdb6397,myService1:com.example.demo.MyService@621c907c
这里可以看到第二次访问的时候,确实是同一个实例了。
那到底怎么使用?
博主,你讲这个到底要做什么?我已经让你绕晕了。都不知道这个多例要怎么使用了?
如果你期望每次访问到的都是不同的实例,这种情况下,请使用BeanFactory的方式:
@Autowired
private BeanFactory factory;
@RequestMapping("/test1")
public Boolean test1(){
// 此时得到的对象即为多例
MyService myService2 = factory.getBean(MyService.class);
System.out.println(myService2);
return myService == myService1;
}
两次访问控制台打印(不同的实例):
com.example.demo.MyService@248c86d9
com.example.demo.MyService@3e4e36a5
或者ObjectFactory的方式(更推荐使用):
@Autowired
private ObjectFactory<MyService> myServiceObjectFactory;
@RequestMapping("/test2")
public Boolean test2(){
// 此时得到的对象即为多例
MyService myService3 = myServiceObjectFactory.getObject();
System.out.println(myService3);
return myService == myService1;
}
两次访问控制台打印(不同的实例):
com.example.demo.MyService@23a14ec9
com.example.demo.MyService@2a4b7c38
如果你只是多种的业务场景下,期望多例的话,那么就可以使用@Autowire的方式进行使用。这里我使用最近开发的项目的案例说明一下可能会更好的理解。
一个项目中有两个如下场景:
(1)场景一:AI写歌中要使用Redis的队列服务MyRedisQuqueService;
(1)场景二:AI生成视频中要使用Redis的队列服务MyRedisQuqueService;
如果每个场景使用同一个队列,那么使用单例就可以搞定了,不需要搞这么复杂,我这里是不同场景,使用不同的队列,那么这个队列信息的配置,就会变成这个场景的属性,如果是单例的话,那么两个场景会互相影响,如果是多例下的@Autowired,那么是两个实例,属性的修改不会互相影响。
如果大家对于这两个AI项目感兴趣,想体验的话,可以关注公众号「未来AI视界」 或者直接点击下面公众号一键进入。
抖音主播/电商人员有福了,利用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篇