跳到主要内容

Bean 管理

Bean 是 Spring 容器管理的核心对象。本章详细介绍 Bean 的定义、作用域、生命周期以及高级特性。

Bean 的定义

Spring 提供了多种方式定义 Bean,包括注解、Java 配置和 XML 配置。

使用注解定义 Bean

Spring 提供了一系列注解用于标记组件类:

注解说明典型应用场景
@Component通用组件注解任何 Spring 管理的组件
@Repository持久层组件DAO 类
@Service业务层组件Service 类
@Controller控制层组件MVC 控制器
@Configuration配置类配置类
@Bean方法级注解第三方库的 Bean 定义
@Repository
public class UserDaoImpl implements UserDao {
public User findById(Long id) {
return new User(id, "User-" + id);
}
}

@Service
public class UserService {
private final UserDao userDao;

public UserService(UserDao userDao) {
this.userDao = userDao;
}
}

@Repository@Service@Controller 都是 @Component 的特化版本,语义更明确。它们功能相同,但有助于分层架构的清晰表达。

使用 @Bean 定义 Bean

对于第三方库的类,无法添加注解,可以使用 @Bean 方法定义:

@Configuration
public class DataSourceConfig {

@Bean
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}

@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}

@Bean 方法可以接受其他 Bean 作为参数,Spring 会自动注入。

Bean 的命名

默认情况下,Bean 的名称是类名首字母小写:

@Service
public class UserServiceImpl { } // beanName: userServiceImpl

可以自定义 Bean 名称:

@Service("userService")
public class UserServiceImpl { }

@Bean("myDataSource")
public DataSource dataSource() {
return new HikariDataSource();
}

也可以指定多个名称:

@Service({"userService", "userManager"})
public class UserServiceImpl { }

@Bean(name = {"dataSource", "myDataSource"})
public DataSource dataSource() {
return new HikariDataSource();
}

组件扫描

使用 @ComponentScan 启用组件扫描:

@Configuration
@ComponentScan("com.example.spring")
public class AppConfig {
}

扫描多个包:

@Configuration
@ComponentScan({"com.example.spring.service", "com.example.spring.dao"})
public class AppConfig {
}

@SpringBootApplication 默认包含 @ComponentScan,扫描主类所在包及其子包。

扫描过滤器

可以配置包含或排除特定的组件:

@Configuration
@ComponentScan(
basePackages = "com.example.spring",
includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyAnnotation.class),
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ExcludedService.class)
)
public class AppConfig {
}

过滤器类型:

FilterType说明
ANNOTATION按注解过滤
ASSIGNABLE_TYPE按类型过滤
ASPECTJ使用 AspectJ 表达式
REGEX使用正则表达式
CUSTOM自定义过滤器

Bean 的作用域

Spring 支持多种 Bean 作用域,决定了 Bean 实例的创建和共享方式。

Singleton(单例)

默认作用域,整个容器中只有一个 Bean 实例。

@Service
@Scope("singleton")
public class UserService {
}

单例 Bean 在容器启动时创建(除非配置懒加载),所有请求共享同一个实例。

注意:单例 Bean 中如果有可变状态,需要考虑线程安全问题。

Prototype(原型)

每次获取 Bean 时创建新实例。

@Service
@Scope("prototype")
public class RequestProcessor {
private String requestId;

public void setRequestId(String requestId) {
this.requestId = requestId;
}
}

原型 Bean 在调用 getBean() 时创建,容器只负责创建,不负责销毁。如果需要清理资源,需要手动处理。

Request(请求)

每个 HTTP 请求创建一个 Bean 实例,仅在 Web 应用中有效。

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestContext {
private String userId;

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}
}

proxyMode 用于解决将短生命周期 Bean 注入到长生命周期 Bean 的问题。

Session(会话)

每个 HTTP 会话创建一个 Bean 实例。

@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserPreferences {
private String theme = "default";

public String getTheme() {
return theme;
}

public void setTheme(String theme) {
this.theme = theme;
}
}

Application(应用)

整个 ServletContext 生命周期内一个实例。

@Component
@Scope(value = WebApplicationContext.SCOPE_APPLICATION)
public class ApplicationConfig {
}

WebSocket

每个 WebSocket 会话一个实例。

@Component
@Scope(value = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketSessionData {
}

自定义作用域

可以实现 Scope 接口定义自定义作用域:

public class ThreadScope implements Scope {

private final ThreadLocal<Map<String, Object>> threadScope =
ThreadLocal.withInitial(HashMap::new);

@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
return threadScope.get().computeIfAbsent(name, k -> objectFactory.getObject());
}

@Override
public Object remove(String name) {
return threadScope.get().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();
}
}

注册自定义作用域:

@Configuration
public class ScopeConfig {

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

使用自定义作用域:

@Component
@Scope("thread")
public class ThreadLocalBean {
}

Bean 的生命周期

理解 Bean 的生命周期对于掌握 Spring 至关重要。Bean 的生命周期包括实例化、属性填充、初始化和销毁四个阶段。

生命周期概览

1. 实例化(Instantiation)
- 创建 Bean 实例
- 调用构造器

2. 属性填充(Population)
- 注入依赖
- 设置属性值

3. 初始化(Initialization)
- 调用 Aware 接口方法
- 执行 BeanPostProcessor 前置处理
- 执行初始化方法
- 执行 BeanPostProcessor 后置处理

4. 使用(Usage)
- Bean 处于就绪状态

5. 销毁(Destruction)
- 执行销毁方法

实例化阶段

Spring 通过构造器或工厂方法创建 Bean 实例:

@Service
public class UserService {

public UserService() {
System.out.println("1. 实例化:调用构造器");
}
}

属性填充阶段

Spring 注入依赖和属性值:

@Service
public class UserService {

@Autowired
private UserDao userDao;

@Value("${app.name}")
private String appName;
}

Aware 接口

Spring 提供了一系列 Aware 接口,让 Bean 获取容器的相关信息:

@Service
public class AwareBean implements
BeanNameAware,
BeanFactoryAware,
ApplicationContextAware {

@Override
public void setBeanName(String name) {
System.out.println("2. BeanNameAware: " + name);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("3. BeanFactoryAware");
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("4. ApplicationContextAware");
}
}

常用的 Aware 接口:

接口获取的信息
BeanNameAwareBean 的名称
BeanFactoryAwareBeanFactory 引用
ApplicationContextAwareApplicationContext 引用
EnvironmentAwareEnvironment 对象
ResourceLoaderAwareResourceLoader 对象
MessageSourceAwareMessageSource 对象
ApplicationEventPublisherAware事件发布器

初始化方法

有三种方式定义初始化方法:

1. @PostConstruct 注解

@Service
public class UserService {

@PostConstruct
public void init() {
System.out.println("5. @PostConstruct 初始化");
}
}

2. InitializingBean 接口

@Service
public class UserService implements InitializingBean {

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("6. InitializingBean.afterPropertiesSet()");
}
}

3. @Bean 的 initMethod 属性

@Configuration
public class AppConfig {

@Bean(initMethod = "init")
public UserService userService() {
return new UserService();
}
}

public class UserService {
public void init() {
System.out.println("7. 自定义 init 方法");
}
}

执行顺序:@PostConstructInitializingBean → 自定义 init 方法

BeanPostProcessor

BeanPostProcessor 是 Spring 提供的扩展点,可以在 Bean 初始化前后进行自定义处理:

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor 前置处理: " + beanName);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor 后置处理: " + beanName);
return bean;
}
}

BeanPostProcessor 的典型应用:

创建代理对象:Spring AOP 使用 BeanPostProcessor 为 Bean 创建代理。

属性校验:检查 Bean 的属性是否符合要求。

自定义注解处理:扫描并处理自定义注解。

销毁方法

有三种方式定义销毁方法:

1. @PreDestroy 注解

@Service
public class UserService {

@PreDestroy
public void destroy() {
System.out.println("销毁: @PreDestroy");
}
}

2. DisposableBean 接口

@Service
public class UserService implements DisposableBean {

@Override
public void destroy() throws Exception {
System.out.println("销毁: DisposableBean");
}
}

3. @Bean 的 destroyMethod 属性

@Configuration
public class AppConfig {

@Bean(destroyMethod = "cleanup")
public UserService userService() {
return new UserService();
}
}

public class UserService {
public void cleanup() {
System.out.println("销毁: 自定义 destroy 方法");
}
}

完整生命周期示例

@Service
public class LifecycleBean implements
BeanNameAware,
InitializingBean,
DisposableBean {

public LifecycleBean() {
System.out.println("1. 构造器");
}

@Override
public void setBeanName(String name) {
System.out.println("2. BeanNameAware: " + name);
}

@PostConstruct
public void postConstruct() {
System.out.println("3. @PostConstruct");
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("4. InitializingBean.afterPropertiesSet()");
}

public void customInit() {
System.out.println("5. 自定义初始化方法");
}

@PreDestroy
public void preDestroy() {
System.out.println("6. @PreDestroy");
}

@Override
public void destroy() throws Exception {
System.out.println("7. DisposableBean.destroy()");
}

public void customDestroy() {
System.out.println("8. 自定义销毁方法");
}
}

懒加载

默认情况下,单例 Bean 在容器启动时创建。使用 @Lazy 可以延迟到首次使用时创建:

@Service
@Lazy
public class LazyService {

public LazyService() {
System.out.println("LazyService 创建");
}
}

也可以在注入点使用:

@Service
public class UserService {

@Autowired
@Lazy
private LazyService lazyService;
}

条件化 Bean

使用 @Conditional 注解可以根据条件决定是否创建 Bean:

@Configuration
public class DataSourceConfig {

@Bean
@Conditional(OnProductionCondition.class)
public DataSource productionDataSource() {
return new ProductionDataSource();
}

@Bean
@Conditional(OnDevelopmentCondition.class)
public DataSource developmentDataSource() {
return new DevelopmentDataSource();
}
}

public class OnProductionCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return "prod".equals(context.getEnvironment().getProperty("spring.profiles.active"));
}
}

Spring Boot 提供了更方便的条件注解:

@Configuration
public class MyConfig {

@Bean
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public FeatureService featureService() {
return new FeatureService();
}

@Bean
@ConditionalOnClass(DataSource.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}

@Bean
@ConditionalOnMissingBean
public DataSource defaultDataSource() {
return new HikariDataSource();
}
}

Profile

Profile 是 Spring 提供的环境隔离机制,可以根据不同环境激活不同的 Bean:

@Configuration
public class DataSourceConfig {

@Bean
@Profile("dev")
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}

@Bean
@Profile("prod")
public DataSource prodDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://prod-db:3306/app");
return dataSource;
}
}

激活 Profile:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(AppConfig.class);
context.refresh();

在 application.properties 中:

spring.profiles.active=dev

小结

本章详细介绍了 Spring Bean 的管理:

  1. Bean 定义:使用注解、@Bean 方法、XML 定义 Bean
  2. Bean 作用域:singleton、prototype、request、session、application 等
  3. Bean 生命周期:实例化、属性填充、初始化、销毁四个阶段
  4. 生命周期回调:Aware 接口、@PostConstruct、InitializingBean、@PreDestroy、DisposableBean
  5. BeanPostProcessor:初始化前后的扩展点
  6. 懒加载:延迟 Bean 创建
  7. 条件化 Bean:@Conditional 及 Spring Boot 的条件注解
  8. Profile:环境隔离机制

下一章我们将学习 Spring 的另一核心特性:AOP 面向切面编程。