2024-12-18  阅读(80)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1062993388

回答

在 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 {}


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文