【Spring编程思想】五、Spring IoC 依赖来源

Spring IoC 依赖来源

本章节参考模块:dependency-source

一、依赖查找的来源

  • 查找来源

    来源配置源数据
    Spring BeanDefinition
    @Bean public User user(){}
    BeanDefinitionBuilder
    单例来源Api实现
  • Spring 内建BeanDefinition

    Bean名称Bean实例使用场景
    org.springframework.context.annotation.internalConfigurationAnnotationProcessorConfigurationClassPostProcessor对象处理Spring配置类
    org.springframework.context.annotation.internalAutowiredAnnotationProcessorAutowiredAnnotationBeanPostProcessor对象处理@Autowired以及@Value注解
    org.springframework.context.annotation.internalCommonAnnotationProcessorCommonAnnotationBeanPostProcessor对象(条件激活)处理JSR-250注解,如@PostCustruct注解
    org.springframework.context.event.internalEventListenerProcessorEventListenerMethodProcessor对象处理标注@EventListener的Spring事件监听方法
  • Bean内建单例对象

Bean名称Bean实例使用场景
environmentEnvironment对象外部化配置以及Profiles
systemPropertiesjava.util.Properties对象Java 系统属性
systemEnvironmentjava.util.Map对象操作系纺环境变量
messageSourceMessageSource对象国际化文案
LifecycleProcessorLifecycleProcessor对象Lifecycle Bean处理器
ApplicationEnventMutlicasterApplicationEnventMutlicaster对象Spring事件广播器

主要由org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 加载

二、 依赖注入的来源

  • 注入来源
来源配置源数据
Spring BeanDefinition
@Bean public User user(){}
BeanDefinitionBuilder
单例来源Api实现
非Spring管理对象

org.springframework.context.support.AbstractApplicationContext#refresh#prepareBeanFactory

applicationContext上下文启动时,默认注入了4种Bean(两个对象:beanFactory以及this)

三、 Spring容器管理和游离对象

  • 依赖对象
来源Spring Bean对象生命周期对象配置元信息使用场景
Spring BeanDefintion依赖查找、依赖注入
单体对象依赖查找、依赖注入
ResolvableDependency依赖注入

四、 Spring BeanDefinition作为来源对象

  • 要素
    • 元数据:BeanDefinition
    • 注册:BeanDefinitionRegistry#registerBeanDefintion
    • 类型:延迟和非延迟
    • 顺序:Bean生命周期顺序按照注册顺序

阅读源码:org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

BeanDefinitionRegistry 为了确保注册顺序,冗余一个字段beanDefintionNames帮忙我们在未来的初始化过程中按照顺序加载

五、单例对象作为依赖来源

  • 要素

    • 来源:外部普通Java对象(不一定是POJO)
    • 注册:SingletonBeanRegistry#registerBeginDefinition
    • 限制
      • 无生命周期
      • 无法实现延迟初始化Bean

    之前代码中演示:com.forjson.spring.bean.definition.SingletonBeanRegisterDemo 注册外部类

    AbstractBeanFactory#getBean时,会优先从SingletonBeanRegistry中查找,若查找到Bean,则直接返回

    getBean源码:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

    // Eagerly check singleton cache for manually registered singletons.
    		Object sharedInstance = getSingleton(beanName);
    		if (sharedInstance != null && args == null) {
    			if (logger.isTraceEnabled()) {
    				if (isSingletonCurrentlyInCreation(beanName)) {
    					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
    							"' that is not fully initialized yet - a consequence of a circular reference");
    				}
    				else {
    					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
    				}
    			}
    			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    

六、非Spring容器管理对象作为来源对象

  • 要素

    • 注册:ConfigurableListableBeanFactory#registerResolvableDependency
    • 限制
      • 无生命周期管理
      • 无法实现延迟初始化Bean
      • 无法通过依赖查找

    代码演示: com.forjson.spring.dependency.source.ResolvableDependencySourceDemo

		@Autowired
    private String value;

    @PostConstruct
    public void init() {
        System.out.println(value);
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //1.注册当前类为 配置类(Configuration Class)
        applicationContext.register(ResolvableDependencySourceDemo.class);
        /**
         * A 解决方案: 添加BeanFactoryPostProcessor
         * 原因:AbstractApplicationContext#refresh() 应用上下文启动时,会先执行BeanFactoryPostProcessor,再执行init()方法
         * 故,在init调用之前,执行我们需要做的操作即可。
         */
        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.registerResolvableDependency(String.class, "Hello,World!");
        });


        //2. 启动应用上下文
        applicationContext.refresh();
        /**
         * Question:
         * 下面两行代码会抛异常:org.springframework.beans.factory.NoSuchBeanDefinitionException
         * 原因是因为Spring生命周期初始化执行完成,才会执行该代码。
         * 在@PostConstruct 执行初始化方法时,需要获取到该注入类型,但此时该类型还没有注入,所以会抛异常.
         * 解决方案:在init之前,将该String类型,注册.见A代码处
         */
//        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
//        beanFactory.registerResolvableDependency(String.class, "Hello,World!");
        //3.关闭应用上下文
        applicationContext.close();
    }

七、外部化配置作为依赖来源

  • 要素

    • 类型:非常规Spring 对象依赖来源
  • 限制

    • 无生命周期管理
    • 无法实现延迟初始化Bean
    • 无法通过依赖查找

参考代码: ExternalConfigurationDependencySourceDemo

八、面试题精选

  • 注入和查找的依赖来源是否相同?

    • 否。依赖查找的来源仅限于BeanDefinition以及单例对象,而依赖注入的来源还包括Resolvable Dependency以及@Value所标注的外部化配置
  • 单例对象能在IoC容器启动后注册吗?

    • 可以的。单例对象的注册与BeanDefinition注册不同,BeanDefinition会被ConfigurableListableBeanFactory#freezeConfiguration()方法影响,从而冻结注册,单例对象则没有这个限制。

    ConfigurableListableBeanFactory#freezeConfiguration() 方法会影响DefaultListableBeanFactory#getBeanDefinitionNames

  • Spring依赖注入来源有哪些?

    • Spring BeanDefinition
    • 单例对象
    • Resolvable Dependency
    • @Value
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值