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 接口:
| 接口 | 获取的信息 |
|---|---|
| BeanNameAware | Bean 的名称 |
| BeanFactoryAware | BeanFactory 引用 |
| ApplicationContextAware | ApplicationContext 引用 |
| EnvironmentAware | Environment 对象 |
| ResourceLoaderAware | ResourceLoader 对象 |
| MessageSourceAware | MessageSource 对象 |
| 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 方法");
}
}
执行顺序:@PostConstruct → InitializingBean → 自定义 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 的管理:
- Bean 定义:使用注解、@Bean 方法、XML 定义 Bean
- Bean 作用域:singleton、prototype、request、session、application 等
- Bean 生命周期:实例化、属性填充、初始化、销毁四个阶段
- 生命周期回调:Aware 接口、@PostConstruct、InitializingBean、@PreDestroy、DisposableBean
- BeanPostProcessor:初始化前后的扩展点
- 懒加载:延迟 Bean 创建
- 条件化 Bean:@Conditional 及 Spring Boot 的条件注解
- Profile:环境隔离机制
下一章我们将学习 Spring 的另一核心特性:AOP 面向切面编程。