【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();
   }
}

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 {

   }
}

总结

  • 按照SpringBoot启动原理和SpringBean的生命周期为思路
  • @Component + @ComponentScan
  • @Bean + @Configuration
  • @Import
  • BeanDefinitionRegistryPostProcessor接口实现postProcessBeanDefinitionRegistry后置函数
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值