Skip to content

Bean 的作用域与生命周期

一、Bean 的 6 种作用域

┌─────────────────────────────────────────────────────────────────┐
│                    Spring Bean Scopes                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    singleton                                  │
│  │             │    ──────────────────                         │
│  │   ┌───┐     │    整个容器只有一个实例                        │
│  │   │ A │     │    默认作用域,Spring 默认使用                 │
│  │   └───┘     │                                               │
│  └─────────────┘                                               │
│                                                                 │
│  ┌─────────────┐    prototype                                 │
│  │   ┌───┐     │    ──────────────────                         │
│  │   │ A │     │    每次注入创建新实例                         │
│  │   └───┘     │                                               │
│  └─────────────┘    ┌─────────────┐                            │
│                     │   ┌───┐     │                            │
│                     │   │ A'│     │                            │
│                     │   └───┘     │                            │
│                     └─────────────┘                            │
│                                                                 │
│  ┌─────────────┐    request (Web)                             │
│  │   ┌───┐     │    ──────────────────                         │
│  │   │ A │     │    每次 HTTP 请求创建新实例                    │
│  │   └───┘     │                                               │
│  └─────────────┘                                               │
│                                                                 │
│  ┌─────────────┐    session (Web)                              │
│  │   ┌───┐     │    ──────────────────                         │
│  │   │ A │     │    每次 HTTP 会话创建新实例                    │
│  │   └───┘     │                                               │
│  └─────────────┘                                               │
│                                                                 │
│  ┌─────────────┐    application (Web)                          │
│  │             │    ──────────────────                         │
│  │   ┌───┐     │    ServletContext 生命周期内单例              │
│  │   └───┘     │                                               │
│  └─────────────┘                                               │
│                                                                 │
│  ┌─────────────┐    websocket (Web)                           │
│  │   ┌───┐     │    ──────────────────                         │
│  │   └───┘     │    WebSocket 生命周期内单例                    │
│  └─────────────┘                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

二、作用域详解

1. singleton(单例)

java
@Service
public class UserService {
    // 默认单例,整个容器只有一个实例
}

@Configuration
public class AppConfig {
    @Bean
    @Scope("singleton")  // 默认值
    public UserService userService() {
        return new UserService();
    }
}

特点

  • 容器启动时创建(饿加载)或第一次使用时创建(懒加载)
  • 整个容器共享一个实例
  • 适合无状态的 Bean

线程安全问题

java
@Service
public class UnsafeService {
    private int count = 0;  // 共享变量,多线程不安全!
    
    public void increment() {
        count++;  // 非原子操作
    }
}

// 解决方案:使用 ThreadLocal
@Service
public class SafeService {
    private final ThreadLocal<Integer> count = ThreadLocal.withInitial(() -> 0);
    
    public void increment() {
        count.set(count.get() + 1);
    }
}

// 或使用 prototype(每次创建新实例)
@Service
@Scope("prototype")
public class PrototypeService {
    private int count = 0;  // 每个线程有自己的实例
}

2. prototype(原型)

java
@Service
@Scope("prototype")
public class OrderService {
    private final String orderId = UUID.randomUUID().toString();
    
    public String getOrderId() {
        return orderId;
    }
}

// 测试
OrderService o1 = ctx.getBean(OrderService.class);
OrderService o2 = ctx.getBean(OrderService.class);
o1.getOrderId() != o2.getOrderId();  // true

特点

  • 每次注入或 getBean() 创建新实例
  • Spring 不管理原型 Bean 的生命周期
  • 适合有状态的 Bean

生命周期差异

java
@Service
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean 创建");
    }
    
    @PreDestroy
    public void destroy() {
        System.out.println("PrototypeBean 销毁");  // 不会调用!
    }
}

// 单例 Bean 中注入原型 Bean
@Service
public class SingletonBean {
    private final PrototypeBean prototypeBean;
    
    public SingletonBean(PrototypeBean prototypeBean) {
        this.prototypeBean = prototypeBean;  // 注入时创建一次
    }
    
    public PrototypeBean getPrototype() {
        return prototypeBean;  // 永远是同一个!
    }
    
    // 正确做法:使用 ObjectFactory 延迟获取
    @Autowired
    private ObjectFactory<PrototypeBean> prototypeFactory;
    
    public PrototypeBean getPrototypeBean() {
        return prototypeFactory.getObject();  // 每次获取新实例
    }
}

3. request(请求域)

java
@Controller
@RequestScope
public class RequestController {
    private final Map<String, Object> requestAttrs = new HashMap<>();
    
    public void setAttribute(String key, Object value) {
        requestAttrs.put(key, value);
    }
}

// 或 XML 配置
<bean id="requestBean" class="com.example.RequestBean" scope="request">
    <aop:scoped-proxy />  <!-- 代理以便注入到单例 -->
</bean>

特点

  • 每个 HTTP 请求有独立的 Bean 实例
  • 请求结束实例销毁
  • 需要 Web 环境支持

4. session(会话域)

java
@Controller
@SessionScope
public class UserSessionController {
    private User currentUser;
    
    public void setCurrentUser(User user) {
        this.currentUser = user;
    }
    
    public User getCurrentUser() {
        return currentUser;
    }
}

特点

  • 每个 HTTP 会话有独立的 Bean 实例
  • 会话超时或失效时销毁
  • 适合存储用户登录信息

5. application(应用域)

java
@Service
@ApplicationScope
public class AppStatistics {
    private final AtomicInteger visitCount = new AtomicInteger();
    
    public void increment() {
        visitCount.incrementAndGet();
    }
    
    public int getCount() {
        return visitCount.get();
    }
}

特点

  • ServletContext 生命周期内单例
  • 整个应用共享
  • 与普通 singleton 的区别:singleton 是 Spring 容器的单例

6. websocket(WebSocket 域)

java
@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketSessionBean {
    private WebSocket session;
    
    public void setSession(WebSocket session) {
        this.session = session;
    }
}

三、自定义作用域

实现 Scope 接口

java
public class ThreadScope implements Scope {
    
    private final ThreadLocal<Map<String, Object>> threadLocal = 
        new ThreadLocal<>() {
            @Override
            protected Map<String, Object> initialValue() {
                return new HashMap<>();
            }
        };
    
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = threadLocal.get();
        if (!scope.containsKey(name)) {
            scope.put(name, objectFactory.getObject());
        }
        return scope.get(name);
    }
    
    @Override
    public Object remove(String name) {
        Map<String, Object> scope = threadLocal.get();
        return scope.remove(name);
    }
    
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // 线程结束时调用
    }
    
    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }
    
    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }
}

注册自定义作用域

java
@Configuration
public class ScopeConfig {
    
    @Bean
    public CustomScopeConfigurer customScopeConfigurer() {
        CustomScopeConfigurer configurer = new CustomScopeConfigurer();
        configurer.addScope("thread", new ThreadScope());
        return configurer;
    }
}

// 使用
@Service
@Scope("thread")
public class ThreadScopedService {
    // 每个线程有独立的实例
}

四、Bean 的生命周期

完整生命周期流程

┌─────────────────────────────────────────────────────────────────────┐
│                        Bean 生命周期                                │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  1. 实例化 (Instantiation)                                          │
│     └─▶ new UserService()  ← 构造函数调用                          │
│                                                                     │
│  2. 属性填充 (Populate)                                             │
│     └─▶ @Autowired 依赖注入                                          │
│     └─▶ setXxx() 属性 setter 调用                                    │
│                                                                     │
│  3. 初始化前 (Initialization - Aware)                               │
│     └─▶ BeanNameAware.setBeanName()                                 │
│     └─▶ BeanFactoryAware.setBeanFactory()                          │
│     └─▶ ApplicationContextAware.setApplicationContext()             │
│                                                                     │
│  4. 初始化 (Initialization)                                         │
│     └─▶ @PostConstruct 标注的方法                                    │
│     └─▶ InitializingBean.afterPropertiesSet()                      │
│     └─▶ @Bean(initMethod = "init")                                  │
│                                                                     │
│  5. BeanPostProcessor.postProcessAfterInitialization()              │
│                                                                     │
│  ════════════════════════════════════════════════════════════════  │
│                                                                     │
│  [ Bean 就绪,可以使用 ]                                            │
│                                                                     │
│  ════════════════════════════════════════════════════════════════  │
│                                                                     │
│  6. 销毁前 (Destruction - Aware)                                   │
│     └─▶ @PreDestroy 标注的方法                                      │
│     └─▶ DisposableBean.destroy()                                   │
│     └─▶ @Bean(destroyMethod = "cleanup")                            │
│                                                                     │
│  7. 销毁 (Destruction)                                              │
│     └─▶ 自定义销毁逻辑                                               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

各阶段代码示例

java
@Service
public class UserService implements BeanNameAware, 
                                    BeanFactoryAware,
                                    ApplicationContextAware,
                                    InitializingBean,
                                    DisposableBean {
    
    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;
    
    // ==================== Aware 回调 ====================
    
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("[Aware] BeanName: " + name);
    }
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        System.out.println("[Aware] BeanFactory: " + beanFactory.getClass());
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        System.out.println("[Aware] ApplicationContext: " + applicationContext);
    }
    
    // ==================== 初始化 ====================
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("[@PostConstruct] 初始化后");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("[InitializingBean] afterPropertiesSet()");
    }
    
    public void init() {
        System.out.println("[@Bean(initMethod)] init()");
    }
    
    // ==================== 销毁 ====================
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("[@PreDestroy] 销毁前");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("[DisposableBean] destroy()");
    }
    
    public void cleanup() {
        System.out.println("[@Bean(destroyMethod)] cleanup()");
    }
}

XML 配置方式

xml
<bean id="userService" 
      class="com.example.UserService"
      init-method="init"
      destroy-method="cleanup">
    <property name="userDao" ref="userDao"/>
</bean>

五、BeanPostProcessor 后置处理器

执行时机

┌─────────────────────────────────────────────────────────┐
│                  BeanPostProcessor 流程                   │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  new UserService()  ← 实例化                            │
│         │                                            │
│         ▼                                            │
│  populateBean()  ← 属性填充(@Autowired)              │
│         │                                            │
│         ▼                                            │
│  ┌─────────────────────────────────────────────┐       │
│  │ postProcessBeforeInitialization()           │       │
│  │                                             │       │
│  │  Aware回调 → @PostConstruct → initMethod    │       │
│  │                                             │       │
│  │ postProcessAfterInitialization()            │       │
│  └─────────────────────────────────────────────┘       │
│         │                                            │
│         ▼                                            │
│   就绪状态 Bean 使用                                    │
│         │                                            │
│         ▼                                            │
│  容器关闭 → destroy() → @PreDestroy                   │
│                                                          │
└─────────────────────────────────────────────────────────┘

内置后置处理器

java
// 1. AutowiredAnnotationBeanPostProcessor
//    处理 @Autowired, @Value, @Inject

// 2. CommonAnnotationBeanPostProcessor
//    处理 @PostConstruct, @PreDestroy, @Resource

// 3. RequiredAnnotationBeanPostProcessor
//    处理 @Required(已废弃)

// 4. AnnotationAwareAspectJAutoProxyCreator
//    处理 AOP 自动代理

// 5. ApplicationContextAwareProcessor
//    处理各种 Aware 接口

自定义后置处理器

java
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) 
            throws BeansException {
        if (bean instanceof UserService) {
            System.out.println("[Before] " + beanName + " 初始化前");
        }
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) 
            throws BeansException {
        if (bean instanceof UserService) {
            System.out.println("[After] " + beanName + " 初始化后");
        }
        return bean;
    }
}

应用:生成代理对象

java
@Component
public class InjectProxyBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof UserService) {
            return createProxy((UserService) bean);
        }
        return bean;
    }
    
    private UserService createProxy(UserService target) {
        return (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                System.out.println("代理逻辑 before");
                Object result = method.invoke(target, args);
                System.out.println("代理逻辑 after");
                return result;
            }
        );
    }
}

六、初始化与销毁顺序

多 Bean 依赖情况

java
public class BeanA {
    @PostConstruct
    public void init() { System.out.println("A init"); }
}

public class BeanB {
    @PostConstruct
    public void init() { System.out.println("B init"); }
}

public class BeanC {
    private BeanA beanA;
    
    public BeanC(BeanA beanA) { this.beanA = beanA; }  // 构造注入
    
    @PostConstruct
    public void init() { System.out.println("C init"); }
}

// 依赖顺序决定初始化顺序
BeanC(BeanA) → 先创建BeanA → 再创建BeanC

@Order 控制同类型 Bean 顺序

java
@Service
@Order(2)
public class OneService { }

@Service
@Order(1)  // 数字越小越先执行
public class TwoService { }

// 或使用 Priority
@Service
@Priority(1)
public class PriorityService { }

@DependsOn 显式依赖

java
@Service
@DependsOn({"beanA", "beanB"})
public class MyService {
    // 确保 beanA, beanB 先初始化
}

七、延迟初始化 Bean

@Lazy 注解

java
@Service
@Lazy  // 第一次使用时才创建
public class LazyService {
    public LazyService() {
        System.out.println("LazyService 创建");
    }
}

全局懒加载

yaml
# Spring Boot 2.x
spring.main.lazy-initialization: true

# Spring Boot 3.x
spring.main.include-lazy-init: true

优点

  • 加快应用启动速度
  • 减少内存占用(按需加载)

缺点

  • 第一次请求响应慢
  • 错误延迟暴露

八、面试高频问题

Q1: Bean 生命周期有哪些阶段?

  1. 实例化(构造函数)
  2. 属性填充(依赖注入)
  3. Aware 回调(BeanName、BeanFactory 等)
  4. 初始化(@PostConstruct、InitializingBean)
  5. BeanPostProcessor 后置处理
  6. 就绪状态
  7. 销毁(@PreDestroy、DisposableBean)

Q2: @PostConstruct vs InitializingBean vs @Bean(initMethod) 区别?

方式来源执行时机推荐度
@PostConstructJSR-250构造器 + 属性填充后⭐⭐⭐⭐⭐
InitializingBeanSpringafterPropertiesSet⭐⭐⭐
@Bean(initMethod)Spring同上⭐⭐⭐⭐

执行顺序

@PostConstruct → InitializingBean.afterPropertiesSet() → @Bean(initMethod)

Q3: singleton Bean 如何注入 prototype Bean?

  1. ObjectFactory 方式(推荐)
java
@Autowired
private ObjectFactory<PrototypeBean> prototypeFactory;

public PrototypeBean getPrototype() {
    return prototypeFactory.getObject();
}
  1. Provider 方式(标准 JSR330)
java
@Inject
private Provider<PrototypeBean> prototypeProvider;

public PrototypeBean getPrototype() {
    return prototypeProvider.get();
}
  1. @Scope + proxyMode
java
@Bean
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public PrototypeBean prototypeBean() {
    return new PrototypeBean();
}

Q4: Spring 如何解决循环依赖?

  • 构造器循环依赖:无法解决,启动失败
  • setter 循环依赖:通过三级缓存解决
    • 一级缓存:成品 Bean
    • 二级缓存:早期引用
    • 三级缓存:ObjectFactory

Q5: 什么是三级缓存?

java
// DefaultSingletonBeanRegistry 源码简化
public class DefaultSingletonBeanRegistry {
    
    // 一级缓存:完全初始化好的 Bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    
    // 二级缓存:早期暴露的 Bean(未完成属性填充和方法调用)
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    
    // 三级缓存:Bean 工厂,用于创建早期引用
    private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>();
}

九、下一章预告

下一章我们将学习 SpringBoot 快速开发

  • Spring Boot 入门与自动配置原理
  • starter 起步依赖
  • YAML 配置文件详解
  • 常用注解与条件装配

基于 MIT 许可发布