概述
文章目录
- 夯实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. internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor 对象 | 处理Spring配置类 |
org.springframework.context.annotation. internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor对象 | 处理 @Autowired 以及 @Value 注解 |
org.springframework.context.annotation. internalCommonAnnotationProcessor | CommonAnnotationBeanPostProcessor对象 | (条件激活) 处理 JSR - 250 注解,比如 @PostConstruct |
org.springframework.context.event. internalEventListenerProcessor | EventListenerMethodProcessor对象 | 处理标准 @EventListener 的 Spring 事件监听方法 |
org.springframework.context.event. internalEventListenerFactory | DefaultEventlistenerFactory 对象 | @EvenListener 事件监听方法适配为 ApplicationListener |
org.springframework.context.annotation. internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 对象 | (条件激活)处理 JPA 注解场景 |
- Spring 内建单例对象
Bean 名称 | Bean 实例 | 使用场景 |
---|---|---|
environment | Environment 对象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties 对象 | Java 系统属性 |
systemEnvironment | java.util.Map 对象 | 操作系统环境变量 |
messageSource | MessageSource 对象 | 国际化文案 |
lifecycleProcessor | LifecycleProcessor 对象 | Lifecycle Bean 处理器 |
applicationEventMulticaster | ApplicationEventMulticaster 对象 | 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 依赖,这个方法在很多地方被调用
比如我们在上下文 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
,所以是同一个对象。
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);
- 这个原因也比较好理解,DefaultListableBeanFactory 中分别用两个对象来进行存储
可以猜测通过 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 依赖来源所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复