学静思语
Published on 2025-03-15 / 13 Visits
0
0

Spring Bean 注册方式详解

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. 最佳实践建议

  1. 选择合适的注册方式

  2. 推荐使用注解方式,更加简洁直观

  3. 对于第三方库的Bean,使用@Configuration + @Bean

  4. 特殊场景可以考虑FactoryBean或Java API方式

  5. 命名规范

  6. Bean的名称应该符合驼峰命名规范

  7. 使用有意义的名称,反映Bean的用途

  8. 如果同类型Bean有多个,名称要能区分用途

  9. 作用域选择

  10. 默认使用singleton作用域

  11. 对于有状态的Bean考虑使用prototype

  12. Web环境下根据需要选择request/session作用域

  13. 依赖注入

  14. 优先使用构造器注入

  15. 必要时使用setter注入

  16. 避免使用字段注入

  17. 条件化配置

  18. 善用条件注解实现灵活配置

  19. 注意条件的判断逻辑要清晰

  20. 条件类要单一职责


Comment