一、原生 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 能不能是多例?

✔ 答案:能,但绝对不推荐!

为什么?

  1. Controller 是单例性能最好

  2. 多例每次请求都创建销毁,浪费内存

  3. 如果 Controller 有成员变量,会线程不安全

  4. Spring MVC 设计就是单例

结论:

Controller 永远用单例,不要改多例!

十、什么时候必须用多例?(企业真实场景)

这些场景必须用多例:

  1. Bean 有状态(有成员变量)

  2. 线程不安全的类(如 SimpleDateFormat)

  3. 每次调用都需要独立副本

  4. 动态创建、用完即销毁的对象

工具类、Service、DAO、Manager 全部单例!

十一、Spring 5 种作用域(你只记 2 个就够)

  1. singleton(默认) 单例
  2. prototype 多例
  3. request 一次请求一个
  4. session 一个会话一个
  5. application 全局单例

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐