Bean的配置与管理
Bean的定义
三种配置方式
Spring 7支持三种Bean配置方式:XML、注解、Java配置。
XML配置(传统方式)
xml
<!-- beans.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.example.service.UserService">
<property name="userRepository" ref="userRepository"/>
</bean>
<bean id="userRepository" class="com.example.repository.UserRepositoryImpl"/>
</beans>注解配置
java
@Repository
public class UserRepositoryImpl implements UserRepository {
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}Java配置(推荐)
java
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
@Bean
public UserService userService() {
return new UserService(userRepository());
}
}Bean的作用域
五种作用域
| 作用域 | 说明 | 使用场景 |
|---|---|---|
| singleton | 单例(默认) | 无状态Bean |
| prototype | 多例 | 有状态Bean |
| request | 请求级别 | Web应用 |
| session | 会话级别 | Web应用 |
| application | 应用级别 | Web应用 |
singleton(单例)
java
@Service
@Scope("singleton") // 默认值,可省略
public class UserService {
// 整个应用只有一个实例
}prototype(多例)
java
@Service
@Scope("prototype")
public class ShoppingCart {
// 每次获取都创建新实例
}Web作用域
java
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestInfo {
// 每个HTTP请求一个实例
}
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserPreferences {
// 每个HTTP会话一个实例
}Bean的生命周期
生命周期阶段
实例化 → 属性赋值 → 初始化 → 使用 → 销毁生命周期回调
java
@Service
public class UserService implements InitializingBean, DisposableBean {
private UserRepository userRepository;
// 属性注入
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
System.out.println("2. 属性注入");
}
// 初始化方法1:@PostConstruct
@PostConstruct
public void init() {
System.out.println("3. @PostConstruct初始化");
}
// 初始化方法2:InitializingBean接口
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("4. afterPropertiesSet初始化");
}
// 初始化方法3:@Bean的initMethod
// @Bean(initMethod = "customInit")
public void customInit() {
System.out.println("5. 自定义初始化方法");
}
// 销毁方法1:@PreDestroy
@PreDestroy
public void destroy() {
System.out.println("销毁:@PreDestroy");
}
// 销毁方法2:DisposableBean接口
@Override
public void destroy() throws Exception {
System.out.println("销毁:DisposableBean");
}
// 销毁方法3:@Bean的destroyMethod
// @Bean(destroyMethod = "customDestroy")
public void customDestroy() {
System.out.println("销毁:自定义销毁方法");
}
}执行顺序
1. 构造方法
2. 属性注入
3. @PostConstruct
4. InitializingBean.afterPropertiesSet()
5. @Bean(initMethod)
↓
使用Bean
↓
6. @PreDestroy
7. DisposableBean.destroy()
8. @Bean(destroyMethod)条件化Bean
@Conditional
java
@Configuration
public class AppConfig {
@Bean
@Conditional(LinuxCondition.class)
public UserService linuxUserService() {
return new LinuxUserService();
}
@Bean
@Conditional(WindowsCondition.class)
public UserService windowsUserService() {
return new WindowsUserService();
}
}常用条件注解
java
@Configuration
public class AppConfig {
// 属性条件
@Bean
@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")
public CacheService cacheService() {
return new RedisCacheService();
}
// 类存在条件
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public RedisClient redisClient() {
return new JedisClient();
}
// Bean存在条件
@Bean
@ConditionalOnBean(DataSource.class)
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate();
}
// Bean不存在条件
@Bean
@ConditionalOnMissingBean
public UserService defaultUserService() {
return new DefaultUserService();
}
// 表达式条件
@Bean
@ConditionalOnExpression("${app.feature.enabled} and ${app.feature.premium}")
public PremiumService premiumService() {
return new PremiumService();
}
}Profile环境切换
定义Profile Bean
java
@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://localhost:3306/mydb");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
}激活Profile
yaml
# application.yml
spring:
profiles:
active: devbash
# 命令行
java -jar app.jar --spring.profiles.active=prod
# 环境变量
export SPRING_PROFILES_ACTIVE=prod
# 代码方式
SpringApplication.run(App.class, "--spring.profiles.active=dev");Profile注解
java
@Configuration
@Profile("dev")
public class DevConfig {
// 仅在dev环境生效
}
@Configuration
@Profile("!prod")
public class NonProdConfig {
// 非prod环境生效
}Bean的延迟加载
@Lazy
java
@Configuration
public class AppConfig {
@Bean
@Lazy
public UserService userService() {
System.out.println("创建UserService");
return new UserService();
}
}
@Service
@Lazy
public class LazyService {
// 首次使用时才创建
}Bean的继承
Java配置继承
java
public class BaseService {
protected String name;
public void setName(String name) {
this.name = name;
}
}
@Configuration
public class AppConfig {
@Bean
public BaseService baseService() {
BaseService service = new BaseService();
service.setName("Base");
return service;
}
@Bean
public UserService userService() {
UserService service = new UserService();
service.setName("User"); // 覆盖父类属性
return service;
}
}Bean的方法注入
@Lookup
java
@Service
public class UserService {
// 每次调用都返回新的prototype Bean
@Lookup
protected ShoppingCart getShoppingCart() {
return null; // Spring会覆盖此方法
}
public void process() {
ShoppingCart cart = getShoppingCart();
// 使用cart
}
}
@Component
@Scope("prototype")
public class ShoppingCart {
}下一步
继续学习 AOP面向切面编程,了解Spring的切面编程能力。