我是靠谱客的博主 如意画笔,最近开发中收集的这篇文章主要介绍夯实Spring系列|第十章:IoC 依赖来源夯实Spring系列|第十章:IoC 依赖来源,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 夯实Spring系列|第十章:IoC 依赖来源
    • 本章说明
    • 1.项目环境
    • 2.依赖查找的来源
      • 2.1 Spring 内建 BeanDefinition 注册过程
      • 2.2 单例对象注册
    • 3.依赖注入的来源
      • 3.1 非 Spring 容器管理对象(ResolvableDependency)
      • 3.2 依赖来源示例
    • 4.Spring 容器管理和游离对象
    • 5.Spring BeanDefinition 作为依赖来源
    • 6.单例对象作为依赖来源
      • 6.1 注册单例对象
      • 6.2 单例对象依赖查找
    • 7.非 Spring 容器管理对象作为依赖来源
      • 7.1 registerResolvableDependency 示例
    • 8.外部化配置作为依赖来源
      • 8.1 示例
    • 9.面试题
      • 9.1 注入和查找的依赖来源是否相同?
      • 9.2 单例对象能在 IOC 容器启动后注册吗?
      • 9.3 Spring 依赖注入有哪些来源?
    • 10.参考

夯实Spring系列|第十章:IoC 依赖来源

本章说明

本系列之前 7 ~ 9 章的主要讲解 Spring IoC 依赖查找和依赖注入相关特性和使用方法,本章主要讨论 依赖查找依赖注入 的依赖来源,大概分为 7 个议题,之前章节中的一些遗留的问题也会在本章中进行说明。

本章源码分析相对之前章节较多,如果看过之前的章节,会比较容易理解

1.项目环境

  • jdk 1.8
  • spring 5.2.2.RELEASE
  • github 地址:https://github.com/huajiexiewenfeng/thinking-in-spring
    • 本章模块:dependency-source

2.依赖查找的来源

  • 一般来源
来源配置元数据
Spring BeanDefinition<bean id=“user” class="…" …>
-@Bean public User user(){…}
-BeanDefinitionBuilder
单例对象API 实现
  • Spring 内建 BeanDefinition

注解驱动 Spring 应用上下文内建可查找的依赖(部分)

Bean 名称Bean 实例使用场景
org.springframework.context.annotation. internalConfigurationAnnotationProcessorConfigurationClassPostProcessor 对象处理Spring配置类
org.springframework.context.annotation. internalAutowiredAnnotationProcessorAutowiredAnnotationBeanPostProcessor对象处理 @Autowired 以及 @Value 注解
org.springframework.context.annotation. internalCommonAnnotationProcessorCommonAnnotationBeanPostProcessor对象(条件激活) 处理 JSR - 250 注解,比如 @PostConstruct
org.springframework.context.event. internalEventListenerProcessorEventListenerMethodProcessor对象处理标准 @EventListener 的 Spring 事件监听方法
org.springframework.context.event. internalEventListenerFactoryDefaultEventlistenerFactory 对象@EvenListener 事件监听方法适配为 ApplicationListener
org.springframework.context.annotation. internalPersistenceAnnotationProcessorPersistenceAnnotationBeanPostProcessor 对象(条件激活)处理 JPA 注解场景
  • Spring 内建单例对象
Bean 名称Bean 实例使用场景
environmentEnvironment 对象外部化配置以及 Profiles
systemPropertiesjava.util.Properties 对象Java 系统属性
systemEnvironmentjava.util.Map 对象操作系统环境变量
messageSourceMessageSource 对象国际化文案
lifecycleProcessorLifecycleProcessor 对象Lifecycle Bean 处理器
applicationEventMulticasterApplicationEventMulticaster 对象Spring 事件广播

2.1 Spring 内建 BeanDefinition 注册过程

相关源码位置:AnnotationConfigUtils#registerAnnotationConfigProcessors()

部分源码:

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
        ...
 
		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
        ...
		}

这个方法会显示的去注册一些内建的 Bean 依赖,这个方法在很多地方被调用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-coJpeSLI-1587778381692)(C:UsersAdministratorAppDataRoamingTyporatypora-user-imagesimage-20200424085913314.png)]
比如我们在上下文 xml 配置文件中加入下面的配置,就会触发 registerAnnotationConfigProcessors()方法的调用

    <context:component-scan base-package="com..."/>
    <context:annotation-config/>

当我们激活注解驱动的时候,这些 Bean 就会通过内建的方式放到我们的应用上下文中。

2.2 单例对象注册

相关源码位置:AbstractApplicationContext#prepareBeanFactory()

注册一些内建的 Bean,如果引入更多的模块,比如 AOP、事务,也会有相应通过 registerSingleton 注册 Bean。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		...
		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

3.依赖注入的来源

依赖注入 的来源比 依赖查找 多了 非 Spring 容器管理对象 这一块

来源配置元数据
Spring BeanDefinition<bean id=“user” class="…" …>
-@Bean public User user(){…}
-BeanDefinitionBuilder
单例对象API 实现
非 Spring 容器管理对象

3.1 非 Spring 容器管理对象(ResolvableDependency)

  • 对象不存在 spring 容器中(即通过 getBean 的方法无法查找),但是可以依赖注入

源码位置:AbstractApplicationContext#prepareBeanFactory

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        ...
		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
        // 使用自动绑定的方式找到
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        ...

registerResolvableDependency() 这个方法的实现在 DefaultListableBeanFactory 中

	@Override
	public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
		Assert.notNull(dependencyType, "Dependency type must not be null");
		if (autowiredValue != null) {
			if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
				throw new IllegalArgumentException("Value [" + autowiredValue +
						"] does not implement specified dependency type [" + dependencyType.getName() + "]");
			}
			this.resolvableDependencies.put(dependencyType, autowiredValue);
		}
	}

通过 this.resolvableDependencies.put(dependencyType, autowiredValue);

可以看到将这个 4 个对象放到 resolvableDependencies 这个 ConcurrentHashMap 中。

在启动Spring容器的时候,可以将断点打在 DefaultListableBeanFactory#findAutowireCandidates 这个方法里面,看到 resolvableDependencies 集合的元素,就是前面注册的 4 个对象,而且因为后面三个对象注册的都是 this,也就是当前的应用上下文 applicationContext,所以是同一个对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QFCtjQju-1587778381695)(C:UsersAdministratorAppDataRoamingTyporatypora-user-imagesimage-20200424215602102.png)]

3.2 依赖来源示例

我们将这 4 个对象分别注入到类的属性中,看看他们到底是什么

/**
 * 依赖来源示例
 */
public class DependencySourceDemo {

    /**
     * 注入在 postProcessProperties 方法执行,早于 setter 注入 ,也早于 @PostConstruct
     */
    @Autowired
    private BeanFactory beanFactory;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @PostConstruct
    public void init() {
        System.out.println("beanFactory == applicationContext:" + (beanFactory == applicationContext));
        System.out.println("beanFactory == applicationContext.getBeanFactory:" + (beanFactory == applicationContext.getAutowireCapableBeanFactory()));
        System.out.println("resourceLoader == applicationContext:" + (resourceLoader == applicationContext));
        System.out.println("applicationEventPublisher == applicationContext:" + (applicationEventPublisher == applicationContext));
    }

    @PostConstruct
    public void initLookup() {
        getBean(BeanFactory.class);
        getBean(ResourceLoader.class);
        getBean(ApplicationContext.class);
        getBean(ApplicationEventPublisher.class);
    }

    private <T> T getBean(Class<T> beanType) {
        try {
            return beanFactory.getBean(beanType);
        } catch (NoSuchBeanDefinitionException e) {
            System.out.println("当前类型:" + beanType + " 无法在 BeanFactory 中查找!");
        }
        return null;
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(DependencySourceDemo.class);

        applicationContext.refresh();

        DependencySourceDemo demo = applicationContext.getBean(DependencySourceDemo.class);
        System.out.println(demo.beanFactory);
        System.out.println(demo.resourceLoader);
        System.out.println(demo.applicationContext);
        System.out.println(demo.applicationEventPublisher);
        applicationContext.close();
    }

}

执行结果

beanFactory == applicationContext:false
beanFactory == applicationContext.getBeanFactory:true
resourceLoader == applicationContext:true
applicationEventPublisher == applicationContext:true
当前类型:interface org.springframework.beans.factory.BeanFactory 无法在 BeanFactory 中查找!
当前类型:interface org.springframework.core.io.ResourceLoader 无法在 BeanFactory 中查找!
当前类型:interface org.springframework.context.ApplicationContext 无法在 BeanFactory 中查找!
当前类型:interface org.springframework.context.ApplicationEventPublisher 无法在 BeanFactory 中查找!
org.springframework.beans.factory.support.DefaultListableBeanFactory@6b419da: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,dependencySourceDemo]; root of factory hierarchy
org.springframework.context.annotation.AnnotationConfigApplicationContext@3796751b, started on Fri Apr 24 11:23:33 CST 2020
org.springframework.context.annotation.AnnotationConfigApplicationContext@3796751b, started on Fri Apr 24 11:23:33 CST 2020
org.springframework.context.annotation.AnnotationConfigApplicationContext@3796751b, started on Fri Apr 24 11:23:33 CST 2020

由源码可知,BeanFactory 注册的对象是 beanFactory(通过 getBeanFactory() 方法获取),而其他三个对象注册的是 this(即当前的应用上下文 ApplicationContext)

  • beanFactory == applicationContext:false 不相等,而且在前面的文章中也分析过

  • 而其他三个对象,都是 this,所以其他这个对象本身其实都是 applicationContext,所以都相等

  • 这 4 个对象都是非 Spring 容器管理对象,通过 registerResolvableDependency 方法注册,所以通过 BeanFactory#getBean() 依赖查找无法获取,抛出 NoSuchBeanDefinitionException 异常。

    • 这个原因也比较好理解,DefaultListableBeanFactory 中分别用两个对象来进行存储
      • beanDefinitionMap 用来存储一般注册 BeanDefinition,比如 xml,注解,API
      • resolvableDependencies 用来存储 非 Spring 容器管理对象(或者叫游离对象)
    	/** Map from dependency type to corresponding autowired value. */
    	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
    
    	/** Map of bean definition objects, keyed by bean name. */
    	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    

可以猜测通过 beanFactory.getBean() 依赖查找是 beanDefinitionMap 集合,并未查找 resolvableDependencies 集合。那么我们来看下源码

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

doGetBean() 这个方法的内容较多,我们只贴出部分相关的代码

  • 第一步 getSingleton(beanName)查找单例对象集合,如果有的话直接返回
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
  • 第二步是层次性的查找,BeanFactory parentBeanFactory = getParentBeanFactory(); 跳过
  • 第三步是合并 BeanDefinition,final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 跳过
  • AbstractBeanFactory 320 行,这里的单例指的是 Bean 的作用域,和前面的单例对象并不是一个概念,BeanDefinition 注册默认是 singleton。然后通过这个 mbd(合并后的 BeanDefinition ) 去 createBean,创建这个 bean。
			 //判断这个合并之后的 beanDefintion 是否是单例的	
             if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
                ...
				}

那么关键点就在 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 这个合并的过程中。多次查找源码可以看到合并的过程会调用 getBeanDefinition 方法如下:

	@Override
	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			if (logger.isTraceEnabled()) {
				logger.trace("No bean named '" + beanName + "' found in " + this);
			}
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}

果然和我们猜想的一样通过 beanDefinitionMap get() 获取 BeanDefinition,而整个 getBean 依赖查找的过程中没有查找过 resolvableDependencies 集合。所以通过依赖查找无法获取 非 Spring 容器管理对象(Resolvable Dependency)

4.Spring 容器管理和游离对象

依赖对象

来源Spring Bean 对象生命周期管理配置元信息使用场景
Spring BeanDefinition依赖查找、依赖注入
单体对象依赖查找、依赖注入
Resolvable Dependency依赖注入

5.Spring BeanDefinition 作为依赖来源

要素

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

DefaultListableBeanFactory#registerBeanDefinition 相关源码大致分为

  • 第一步 ((AbstractBeanDefinition) beanDefinition).validate();//校验 beanDefinition
    • 这个在BeanDefinitionBuilder#getBeanDefinition 方法中也使用
  • 第二步 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    • 通过 beanName 获取 beanDefinition 信息
  • 第三步 如果 beanDefinition 存在的话做一些判断
    • isAllowBeanDefinitionOverriding()//检查是否能被覆盖,默认 true
    • existingDefinition.getRole() < beanDefinition.getRole() 这个不太好理解,主要是基于业务架构方面的
      • (源码中的注释)e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE(需要具体的业务场景)
  • 第四步 最后将 beanDefinition 存放到集合中
    • this.beanDefinitionMap.put(beanName, beanDefinition);
  • 第五步 如果 beanDefinition 不存在
    • this.beanDefinitionMap.put(beanName, beanDefinition);//Map是无序的
    • this.beanDefinitionNames.add(beanName);//保证顺序
      • ArrayList 存放 beanName 来保证 beanDefinition 调用的顺序
    • 移除单例对象

6.单例对象作为依赖来源

要素

  • 来源:外包普通 Java 对象(不一定是 POJO)
  • 注册:SingletonBeanRegistry#registerSingleton

限制

  • 无生命周期管理
  • 无法实现延迟初始化 Bean

6.1 注册单例对象

源码位置:DefaultSingletonBeanRegistry#registerSingleton

就是简单的 put 操作,将对象存放到 singletonObjects 中。

registerSingleton 的第一把锁,主要是这个方法既调用了 get() 方法,又调用了 add() 方法,为了线程安全。

addSingleton 中加锁的原因是 addSingleton() 方法可能被别的地方调用,而且此方法也是一个多元的操作,为了线程安全。

  • this.singletonObjects.put(beanName, singletonObject);
    • 加入 singletonObjects 集合
  • this.singletonFactories.remove(beanName);
    • ObjectFactory 操作的 Bean,用来进行延迟查找,如果这个 Bean 注册成单例对象,和这个是一个互斥的操作,所以需要删除
  • this.earlySingletonObjects.remove(beanName);
    • 这个早期的 SingletonObject 也是一个互斥的操作,所以需要删除
  • this.registeredSingletons.add(beanName);
    • 这个也是为了保存一个顺序
	@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		Assert.notNull(beanName, "Bean name must not be null");
		Assert.notNull(singletonObject, "Singleton object must not be null");
		synchronized (this.singletonObjects) {
			Object oldObject = this.singletonObjects.get(beanName);
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			addSingleton(beanName, singletonObject);
		}
	}

	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, singletonObject);
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

6.2 单例对象依赖查找

依赖查找 还是通过 getBean 方法

源码位置:AbstractBeanFactory#getBean(java.lang.String, java.lang.Object…)

先查询的是 getSingleton() 而不是先查 BeanDefinition,如果找到 bean 直接返回,而 BeanDefinition 的方式会比较复杂,需要将 BeanDefinition 通过 doGetBean() 变成 Bean,并激活整个 Bean 的生命周期。

这个过程我们已经在本文 3.2 依赖来源示例 做了分析

7.非 Spring 容器管理对象作为依赖来源

要素

  • 注册:ConfigurableListableBeanFactory#registerResolvableDependency
    • 只有类型注入一种
    • 只能实现依赖注入

限制

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

7.1 registerResolvableDependency 示例

  • 我们将类型 String.class 和 “xwf” 注册到 ResolvableDependency 中

  • 再通过 @Autowired 方法进行依赖注入

  • 最后通过 @PostConstruct 打印 name 的值

/**
 * ResolvableDependency 作为依赖来源
 */
public class ResolvableDependencySourceDemo {

    @Autowired
    private String name;

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

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //之前的写法
        //applicationContext.register(ResolvableDependencySourceDemo.class);
        applicationContext.refresh();

         //如果采用这种方式,需要将register放到refresh之后 原因和refresh中代码的spring应用上下文启动过程有关
        applicationContext.register(ResolvableDependencySourceDemo.class);
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
        if (beanFactory instanceof ConfigurableListableBeanFactory) {
            ConfigurableListableBeanFactory configurableListableBeanFactory = (ConfigurableListableBeanFactory) beanFactory;
            configurableListableBeanFactory.registerResolvableDependency(String.class,"xwf");

        }
        
applicationContext.getBean(ResolvableDependencySourceDemo.class);

        applicationContext.close();
    }
}

如果像之前例子的写法将 applicationContext.register(ResolvableDependencySourceDemo.class);写在 refresh()之前,会报错 NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available

因为 applicationContext.refresh(); 执行过程中会去触发依赖注入过程,而 @Autowired 标注的属性 name 还没有对象可以注入,所以我们先不注册 ResolvableDependencySourceDemo.class ,将 applicationContext.register(ResolvableDependencySourceDemo.class); 放在 applicationContext.refresh();之后就不会报错了,但是要触发依赖注入的过程,还需要applicationContext.getBean(ResolvableDependencySourceDemo.class);通过依赖查找触发。

那么有没有什么更简单的方法呢?

可以通过添加BeanFactoryPostProcessor,原因在 AbstractApplicationContext#refresh 的源码中,有相关的容器生命周期设计;我们添加的BeanFactory 的后置处理,会在invokeBeanFactoryPostProcessors()这个里面进行处理,而依赖注入过程在这之后的 finishBeanFactoryInitialization()

/**
 * ResolvableDependency 作为依赖来源
 */
public class ResolvableDependencySourceDemo {

    @Autowired
    private String name;

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

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ResolvableDependencySourceDemo.class);
        
        //第二种方式
        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            beanFactory.registerResolvableDependency(String.class,"xwf-post");
        });

        applicationContext.refresh();
        applicationContext.close();
    }
}

执行结果

xwf-post

8.外部化配置作为依赖来源

要素

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

限制

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

8.1 示例

我们先在 resources/META-INF 目录下面新建一个 default.properties 的配置文件

user.id = 1
usr.name = 小仙
user.resource = classpath://META-INF/default.properties

我们分别将三个值注入到 ExternalConfigurationDependencyDemo 的属性中

/**
 * 外部化配置依赖来源
 */
@Configuration
@PropertySource(value = "META-INF/default.properties", encoding = "gbk")
public class ExternalConfigurationDependencyDemo {

    @Value("${user.id:-1}")
    private Long id;

    @Value("${usr.name}")
    private String name;

    @Value("${user.resource:classpath://default.properties}")
    private Resource resource;

    @PostConstruct
    public void init() {
        System.out.println("PostConstruct-> id: " + id);
        System.out.println("PostConstruct-> resource: " + resource);
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(ExternalConfigurationDependencyDemo.class);

        applicationContext.refresh();
        ExternalConfigurationDependencyDemo demo = applicationContext.getBean(ExternalConfigurationDependencyDemo.class);

        System.out.println(demo.id);
        System.out.println(demo.name);
        System.out.println(demo.resource);

        applicationContext.close();
    }
}

执行结果

PostConstruct-> id: 1
PostConstruct-> resource: class path resource [META-INF/default.properties]
1
小仙
class path resource [META-INF/default.properties]

如果汉字打印有乱码,需要注意 default.properties 文件和 idea 的字符集,具体设置 @PropertySource(value = "META-INF/default.properties", encoding = "gbk")

调用源码位置:DefaultListableBeanFactory#doResolveDependency 1225 行
在这里插入图片描述
三个字段,会依次进来三次。

9.面试题

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

不完全一样,依赖查找的来源仅限于 Spring BeanDefinition 以及单例对象,而依赖注入的来源还包括 Resolvable Dependency(非 Spring 容器管理对象或者称游离对象) 以及 @Value 所标注的外部化配置

9.2 单例对象能在 IOC 容器启动后注册吗?

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

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

  • Spring BeanDefinition
  • 单体对象
  • Resolvable Dependency 游离对象 4个
    • BeanFactory
    • ApplicationContext
    • ResourceLoader
    • ApplicationEventPublisher
  • 外部化配置@Value

10.参考

  • 极客时间-小马哥《小马哥讲Spring核心编程思想》

最后

以上就是如意画笔为你收集整理的夯实Spring系列|第十章:IoC 依赖来源夯实Spring系列|第十章:IoC 依赖来源的全部内容,希望文章能够帮你解决夯实Spring系列|第十章:IoC 依赖来源夯实Spring系列|第十章:IoC 依赖来源所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部