• 【SpringBoot】浅谈向容器注入Bean有几种方式。


    前言

    SpringBoot的核心之一是通过IOC容器管理各个bean对象,前几天看到一个大厂面试题问向Spring容器中注入bean有哪几种方式,今天整理了下跟大家分析一波。

    这个题看似简单,实则暗藏玄机,可能大部分掘友能回答出一部分,要回答全面在众多面试者中脱颖而出似乎不是那么简单。

    首先面试官问出这个问题,思路应该要立刻转到SpringBoot的启动流程来,按SpringBoot是怎么扫描出要注入的类入手。

    启动流程模糊的掘友可以回顾下之前的文章:SpringBoot启动流程

    @Component + @ComponentScan

    SpringBoot启动类的@SpringBootApplication注解中就标注了 @ComponentScan注解,这个注解默认扫描当前包及其子包下的标注有@Component@Controller@Service@Repository等的类加载到容器中。

    这一条应该都能答出来,属于基础八股了。

    @Import注解

    了解过SpringBoot源码的掘友应该对这个注解不陌生,SpringBoot之所以拥有自动装配能力,全依仗于启动类@SpringBootApplication注解中的另一个核心注解 @EnableAutoConfiguration

    点进去这个注解会发现 @Import(AutoConfigurationImportSelector.class),也就是通过将AutoConfigurationImportSelector类加载到容器中。

    并通过此类的getAutoConfigurationEntry()方法,查找并筛选出位于META-INF/spring.factories文件中的所有需要注入的自动配置类并加载。

    这个注解也可以直接注入class,SpringBoot默认是注入ImportSelector接口,重写selectImports规则实现,本质上都是将外部类加载到当前classpath中并注入成bean。

    @Configuration + @Bean

    这个组合相信大家都有用过,比如想利用ioc容器管理一个map容器,只需要在配置类上标注上@Configuration声明配置类,在某个方法上标注@Bean并返回一个new HashMap即可。

    @Configuration
    public class TestConfig {
    
       @Bean
       public Map TestAutoMap() {
           return new HashMap();
       }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    BeanDefinitionRegistryPostProcessor

    万变不离其宗,掌握SpringBoot启动流程和SpringBean的生命周期,很多问题就能连点成线的串起来。

    我们知道SpringBean的生命周期中有很多前后置方法,整体上可以概括为普通类对象转化为beanDefinition再转化为spring中的bean这么三个阶段。

    而Spring会在启动的AbstratApplicationContxt类中的refresh方法中执行 invokeBeanFactoryPostProcessors,这个方法中会回调所有实现 BeanDefinitionRegistryPostProcessor接口的钩子方法。

    可以简单理解成beanDefinition加载完毕之后,会对beanDefinition进行后置处理。所以理论上实现BeanDefinitionRegistryPostProcessor接口就可以手动将bean注入到容器中。

    public class TestBeanProcessor {
    
       public static void main(String[] args) {
          AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
          UptownBeanProcessor beanDefinitionRegistryPostProcessor = new UptownBeanProcessor();
          applicationContext.addBeanFactoryPostProcessor(beanDefinitionRegistryPostProcessor);
          applicationContext.refresh();
          Object bean = applicationContext.getBean("test_map");
          System.out.println(bean);
       }
    }
    
    
    class UptownBeanProcessor implements BeanDefinitionRegistryPostProcessor {
    
       @Override
       public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
          AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(HashMap.class).getBeanDefinition();
          registry.registerBeanDefinition("test_map", beanDefinition);
       }
    
       @Override
       public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    总结

    • 按照SpringBoot启动原理和SpringBean的生命周期为思路
    • @Component + @ComponentScan
    • @Bean + @Configuration
    • @Import
    • BeanDefinitionRegistryPostProcessor接口实现postProcessBeanDefinitionRegistry后置函数
  • 相关阅读:
    Spring:核心容器(6)
    Win11 25188.1000补丁包介绍及下载地址
    高教社杯数模竞赛特辑论文篇-2018年A题:高温作业专用服装设计(附获奖论文及MATLBA代码)(续)
    CentOS 7 不显示ip
    【sdx62】WCN685X将bdwlan.bin和bdwlan.txt相互转化操作方法
    QT调用onnx 模型Demo(代码和讲解)
    【无标题】超时超时超时超时超时
    2.2 发布与订阅python
    java计算机毕业设计交通事故档案管理系统源码+数据库+系统+lw文档+mybatis+运行部署
    Vue (十四) --------- vue-router (路由)
  • 原文地址:https://blog.csdn.net/m0_37817220/article/details/128207760