Spring Bean 注册方式详解
1. 注解方式注册Bean
@Component及其衍生注解
// 通用组件
@Component
public class UserService {
}
// 控制器组件
@Controller
public class UserController {
}
// 业务逻辑组件
@Service
public class OrderService {
}
// 数据访问组件
@Repository
public class ProductDao {
}
@Configuration + @Bean
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
@Bean(name = "orderService") // 自定义Bean名称
@Scope("prototype") // 指定作用域
public OrderService orderService() {
return new OrderService();
}
// 带参数的Bean注册
@Bean
public PaymentService paymentService(UserService userService) {
return new PaymentService(userService);
}
}
@Import注解
// 直接导入类
@Import(UserService.class)
public class AppConfig {
}
// 导入配置类
@Import(OtherConfig.class)
public class AppConfig {
}
// 使用ImportSelector
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.example.Service1", "com.example.Service2"};
}
}
@Import(MyImportSelector.class)
public class AppConfig {
}
2. XML配置方式注册Bean
基本配置
<?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定义 -->
<bean id="userService" class="com.example.UserService"/>
<!-- 指定作用域 -->
<bean id="orderService"
class="com.example.OrderService"
scope="prototype"/>
<!-- 构造器注入 -->
<bean id="customerService" class="com.example.CustomerService">
<constructor-arg ref="userService"/>
</bean>
<!-- setter注入 -->
<bean id="productService" class="com.example.ProductService">
<property name="userService" ref="userService"/>
</bean>
</beans>
复杂配置
<!-- 初始化和销毁方法 -->
<bean id="exampleBean"
class="com.example.ExampleBean"
init-method="init"
destroy-method="cleanup"/>
<!-- 工厂方法创建Bean -->
<bean id="clientService"
class="com.example.ClientService"
factory-method="createInstance"/>
<!-- 懒加载 -->
<bean id="lazyBean"
class="com.example.LazyBean"
lazy-init="true"/>
3. Java API方式注册Bean
使用BeanDefinition
public class BeanDefinitionDemo {
public void registerBean() {
// 创建BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 创建BeanDefinition
BeanDefinition beanDefinition = new RootBeanDefinition(UserService.class);
// 注册BeanDefinition
factory.registerBeanDefinition("userService", beanDefinition);
}
}
使用BeanDefinitionBuilder
public class BeanDefinitionBuilderDemo {
public void registerBean() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 使用Builder创建BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(UserService.class)
.addPropertyReference("dependencyService", "dependencyService")
.setScope(BeanDefinition.SCOPE_SINGLETON)
.setLazyInit(false);
// 注册BeanDefinition
factory.registerBeanDefinition("userService", builder.getBeanDefinition());
}
}
4. FactoryBean方式注册Bean
public class UserServiceFactoryBean implements FactoryBean<UserService> {
@Override
public UserService getObject() throws Exception {
return new UserService();
}
@Override
public Class<?> getObjectType() {
return UserService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
// 配置FactoryBean
@Configuration
public class FactoryBeanConfig {
@Bean
public UserServiceFactoryBean userService() {
return new UserServiceFactoryBean();
}
}
5. 条件化Bean注册
@Conditional注解
// 自定义条件
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux");
}
}
// 使用条件注解
@Configuration
public class ConditionalConfig {
@Bean
@Conditional(LinuxCondition.class)
public UserService linuxUserService() {
return new LinuxUserService();
}
}
常用条件注解
// 类路径下存在指定类时创建Bean
@ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate")
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate() {
return new RedisTemplate();
}
}
// 属性值匹配时创建Bean
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
public class DevConfig {
// ...
}
// Bean不存在时创建Bean
@ConditionalOnMissingBean
public class DefaultConfig {
// ...
}
6. 最佳实践建议
选择合适的注册方式
推荐使用注解方式,更加简洁直观
对于第三方库的Bean,使用@Configuration + @Bean
特殊场景可以考虑FactoryBean或Java API方式
命名规范
Bean的名称应该符合驼峰命名规范
使用有意义的名称,反映Bean的用途
如果同类型Bean有多个,名称要能区分用途
作用域选择
默认使用singleton作用域
对于有状态的Bean考虑使用prototype
Web环境下根据需要选择request/session作用域
依赖注入
优先使用构造器注入
必要时使用setter注入
避免使用字段注入
条件化配置
善用条件注解实现灵活配置
注意条件的判断逻辑要清晰
条件类要单一职责