最清晰、最实用的Java + Spring 双版本的单例 / 多例模式
·
一、原生 Java 自己控制:单例 / 多例
1)单例模式(整个项目只有 1 个对象)
写法 1:饿汉式(最常用、最简单)
public class UserUtil {
// 自己创建一个唯一实例
private static final UserUtil INSTANCE = new UserUtil();
// 私有构造!禁止外面 new
private UserUtil() {}
// 提供获取方法
public static UserUtil getInstance() {
return INSTANCE;
}
}
✅ 特点
- 绝对单例
- 类加载就创建
- 无线程安全问题
写法 2:懒汉式(用的时候才创建)
public class UserUtil {
private static UserUtil instance;
private UserUtil() {}
public static synchronized UserUtil getInstance() {
if (instance == null) {
instance = new UserUtil();
}
return instance;
}
}
2)多例模式(每次获取都是新对象)
多例 = 不限制构造方法,随便 new
public class UserUtil {
// 构造方法 public
public UserUtil() {}
}
使用:
UserUtil u1 = new UserUtil();
UserUtil u2 = new UserUtil();
// u1 和 u2 不是同一个对象 → 多例
二、Spring 中控制单例 / 多例(最常用!)
Spring 默认 所有 Bean 都是单例
你可以用 @Scope 注解控制!
1)单例(默认,可不写)
@Component
// 等价于 @Scope("singleton")
public class UserService {
}
✅ 整个 Spring 容器只有 1 个实例
2)多例(每次获取都创建新对象)
@Component
@Scope("prototype") // 关键!多例
public class UserService {
}
✅ 每次 @Autowired / getBean() 都会创建新对象
三、Spring 的 5 种作用域(你只用记 2 个)
| 注解 | 作用 | 说明 |
|---|---|---|
| singleton(默认) | 单例 | 全局一个 |
| prototype | 多例 | 每次获取都新建 |
| request | 一次请求一个 | Web 专用 |
| session | 一个会话一个 | Web 专用 |
| application | 一个 Web 应用一个 | 很少用 |
四、最关键:怎么判断当前是单例还是多例?
直接看对象地址:
@Autowired
private UserService service1;
@Autowired
private UserService service2;
System.out.println(service1 == service2);
输出 true → 单例
输出 false → 多例
五、你什么时候用单例?什么时候用多例?
✅ 单例(95% 场景)
- Service
- Dao
- Util 工具类
- 无状态、线程安全的类
✅ 多例(少数场景)
- 有成员变量状态的类
- 每次调用都需要独立数据
- 线程不安全的类
六、在 Spring 中,@Bean 方法上也可以加 @Scope 控制单例 / 多例!
✔ @Bean 上 完全可以加 @Scope 控制单例 / 多例
✔ 效果和写在类上 一模一样
1)@Bean 方式控制单例 / 多例(超级常用)
1. @Bean 默认也是 单例
@Configuration
public class BeanConfig {
// 默认单例:整个项目只会创建一次
@Bean
public UserService userService() {
return new UserService();
}
}
2. 想变成 多例 → 加 @Scope("prototype")
@Configuration
public class BeanConfig {
// 多例:每次获取都创建新对象
@Bean
@Scope("prototype")
public UserService userService() {
return new UserService();
}
}
2)@Scope 两个最常用值
| 注解 | 效果 |
|---|---|
| @Scope("singleton") | 单例(默认) |
| @Scope("prototype") | 多例 |
3)@Bean + @Scope 完整示例
@Configuration
public class MyConfig {
// 单例(默认)
@Bean
public UserService singletonBean() {
return new UserService();
}
// 多例
@Bean
@Scope("prototype")
public UserService prototypeBean() {
return new UserService();
}
}
七、为什么 @Bean 默认是单例?
1、因为 Spring 所有 Bean 默认作用域都是 singleton
不管你是:
@Service@Component@Controller@Bean
全部都是单例!
2、多例 = 每次获取都创建新实例
什么时候叫 “获取”?
- @Autowired 注入时
- context.getBean () 时
- AOP 调用时
- 被其他单例 Bean 依赖时(只会注入一次!)
八、超级大坑:单例注入多例 → 多例会变成单例!
@Component
public class A {
// B 是多例
@Autowired
private B b;
}
@Bean
@Scope("prototype")
public B b() {
return new B();
}
结果:
A 是单例 → 只会注入一次 B →B 虽然是多例,但永远只有一个对象!
这就是著名的:
单例注入多例 = 多例失效!
九、那 Controller 能不能是多例?
✔ 答案:能,但绝对不推荐!
为什么?
-
Controller 是单例性能最好
-
多例每次请求都创建销毁,浪费内存
-
如果 Controller 有成员变量,会线程不安全
-
Spring MVC 设计就是单例
结论:
Controller 永远用单例,不要改多例!
十、什么时候必须用多例?(企业真实场景)
这些场景必须用多例:
-
Bean 有状态(有成员变量)
-
线程不安全的类(如 SimpleDateFormat)
-
每次调用都需要独立副本
-
动态创建、用完即销毁的对象
工具类、Service、DAO、Manager 全部单例!
十一、Spring 5 种作用域(你只记 2 个就够)
- singleton(默认) 单例
- prototype 多例
- request 一次请求一个
- session 一个会话一个
- application 全局单例
更多推荐




所有评论(0)