Spring中创建Bean有几种方式?

 作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题


代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等


联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。码炫课堂的个人空间-码炫码哥个人主页-面试,源码等

回答

在 Spring 中,有多种方式创建 Bean:

  • 通过 XML 配置文件创建 Bean

这是一种比较传统的方式,通过 <bean> 标签在 XML 配置文件中定义 Bean 的 id 和 class 属性。

  • 通过注解方式创建 Bean

利用注解 @Component@Service@Repository 或 @Controller 等注解来标记类,Spring 会自动扫描并将其注册为 Bean。

  • 通过 Config 配置类创建 Bean

基于 Java 的配置方式,结合 @Configuration 和 @Bean 注解,定义方法来返回实例,这些方法的返回值会被 Spring 容器管理为 Bean。

  • 通过工厂方法创建 Bean

实现 FactoryBean 接口,我们可以自定义更加复杂创建 Bean 的逻辑。

  • 使用 @Import 方式

使用 @Import 可以将外部类直接注册为 Bean。

  • @Import + ImportSelector 方式

ImportSelector 是一个接口,它支持动态选择要注册的类。使用它有两点好处:

1、把某个功能的相关类放到一起,方面管理和维护

2、重写 selectImports() 时,我们可以根据条件判断某些类是否需要被实例化,或者某个条件实例化这些 Bean,其他的条件实例化那些 Bean 等,我们能够非常灵活的定制化 Bean 的实例化。

  • @Import + ImportBeanDefinitionRegistrar 方式

这种方式我们需要实现 ImportBeanDefinitionRegistrar 接口,并重写 registerBeanDefinitions(),然后定义我们需要注册的 Bean 的定义信息,然后调用 registry.registerBeanDefinition()注册即可。这种方式比使用 ImportSelector 更加灵活,除了可以注册 Bean 外,还可以自定义 Bean 的名称、作用域等很多参数。

  • 使用 BeanDefinitionRegistryPostProcessor 方式
  • 使用 BeanFactoryPostProcessor 方式

后面两种方式是基于 Spring 得扩展,使用场景比较少。

详解

通过 XML 配置文件创建 Bean

这是一种非常传统的方式,是 Spring 早期支持的方式,现在基本上被放弃了。

<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.skjava.UserService"/>
</beans>

Spring 在启动时会解析 XML 文件,将 <bean> 标签中定义的类加载并实例化,然后注册到 Spring 容器中。

通过注解方式创建 Bean

可以使用 @Component、@Service、@Repository 或 @Controller 等注解来标记类,Spring 会自动扫描并将其注册为 Bean。目前这是最主流的方式。

@Component
public class UserService {
    // business logic
}

通过 Config 配置类创建 Bean

使用基于 Java 的配置方式,结合 @Configuration 和 @Bean 注解,定义方法来返回实例,这些方法的返回值会被 Spring 容器管理为 Bean。

@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService();
    }
}

通过工厂方法创建 Bean

FactoryBean 是一个特殊的 Bean,它允许我们自定义 Bean 的创建,主要有三个方法:

  • getObject():自定义Bean如何创建
  • getObjectType():要注册的Bean的类型
  • isSingleton():是否单例
public class CustomFactoryBean implements FactoryBean<UserService> {
    @Override
    public UserService getObject() {
        return new UserService();
    }
    
    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }
}


@Bean
public FactoryBean<UserService> userFactoryBean() {
    return new CustomFactoryBean();
}


Spring 检测到 FactoryBean 时,会调用其 getObject() 方法获取实际 Bean。它提供了更细粒度的创建控制,适合复杂对象的构建。

使用 @Import 方式

使用 @Import 可以将外部类直接注册为 Bean。

@Import(UserService.class)
@Configuration
public class AppConfig {}

@Import 会将指定得类注册为 Spring 容器中得 Bean。其内部使用 ImportBeanDefinitionRegistrar 将类转换为 BeanDefinition。

@Import + ImportSelector 方式

ImportSelector 是一个接口,它支持动态选择要注册的类。使用它有两点好处:

  • 把某个功能的相关类放到一起,方面管理和维护
  • 重写 selectImports() 时,我们可以根据条件判断某些类是否需要被实例化,或者某个条件实例化这些 Bean,其他的条件实例化那些 Bean 等,我们能够非常灵活的定制化 Bean 的实例化。
public class SkServiceImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"com.skjava.UserService","com.skjava.OrderService","com.skjava.ProductService"};
    }
}

然后使用 @Import

@Import(SkServiceImportSelector.class)
@Configuration
public class AppConfig {}

@Import + ImportBeanDefinitionRegistrar 方式

这种方式我们需要实现 ImportBeanDefinitionRegistrar 接口,并重写 registerBeanDefinitions(),然后定义我们需要注册的 Bean 的定义信息,然后调用 registry.registerBeanDefinition()注册即可。这种方式比使用 ImportSelector 更加灵活,除了可以注册 Bean 外,还可以自定义 Bean 的名称、作用域等很多参数。

public class SkServiceRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition userServiceBeanDefinition = new RootBeanDefinition(UserService.class)
        userServiceBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        
        registry.registerBeanDefinition("userService", userServiceBeanDefinition );
    }
}

然后使用 @Import

@Import(SkServiceRegistrar.class)
@Configuration
public class AppConfig {}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值