7. IOC 依赖来源 Dependency Sources
7.1 依赖查找的来源
依赖查找 Dependency Lookup 的来源:
-
外部:
- BeanDefinition
<bean id='"user" class="org....User" >- @Bean,@Component
- BeanDefinitionBuilder 创建 BeanDefinition,并进行注册
- 单例对象
- api 手动注册外部单例对象,SingletonBeanRegistry#registerSingleton
- BeanDefinition
-
内部:
- Spring 内建 BeanDefinition
- Spring 内建单例对象
7.2 依赖注入的来源
依赖注入的来源在依赖查找的基础上面,增加了两个新的来源:
- 非 Spring 容器管理的对象 ResolvableDependency,也称为 游离对象,这些对象并没有注册到容器。
- 外部配置,使用 @Value 引入
ResolvableDependency 非 Spring 容器管理的对象有 4 个:
- BeanFactory
- ResourceLoader
- ApplicationEventPublisher
- ApplicationContext
为什么依赖查找的来源没有 ResolvableDependency ?
其实很容易想明白,依赖查找就是通过 BeanFactory 查找 bean,即已经得到 BeanFactory 和 ApplicationContext 了,自然就不需要去查找这几个对象了
- 注册 4 个非Spring容器管理的对象到容器ResolvableDependency,保存在上下文的 resolvableDependencies 属性中
Spring 框架在应用上下文启动时refresh()会调用下面这个方法,注册 4 个非Spring容器管理的对象到容器,源码如下:
AbstractApplicationContext.java
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 注册非容器管理对象ResolvableDependency, this是当前应用上下文
// 可以看到后3个其实是同一个对象this
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
}
DefaultListableBeanFactory.java
// 注册ResolvableDependency, 将其保存到resolvableDependencies中
public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
Assert.notNull(dependencyType, "Dependency type must not be null");
if (autowiredValue != null) {
this.resolvableDependencies.put(dependencyType, autowiredValue);
}
}
- 在6.14 章节,依赖处理时会根据目标 bean 的类型进行层次性查找,那如果目标 bean 是非 Spring 容器管理的对象即 ResolvableDependency 呢?下面这个例子就使用 @Autowired 依赖注入了 4 个 ResolvableDependency 对象
public class ResolvableDependencySourceDemo {
@Autowired
private BeanFactory beanFactory;
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Autowired
private ApplicationContext applicationContext;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(DependencySourceDemo.class);
applicationContext.refresh();
}
}
- 源码分析,在依赖处理过程中,会去容器中查找符合条件的目标 bean,上述例子中依赖的都是非 Spring 容器管理的对象,即
BeanFactoryUtils.beanNamesForTypeIncludingAncestors()从容器中找不到这些类型的 bean,因此还会去this.resolvableDependencies中根据类型进行查找(无法根据名称查找)
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 根据bean类型进行层次性查找候选bean,
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 遍历4个非 Spring 容器管理的对象 ResolvableDependency
// 如果目标bean类型是ResolvableDependency 4个对象的类型, 则将该对象返回
// ResolvableDependency包含BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
// 若目标bean类型是autowiringType
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
// 将对象类名作为key,对象作为value加入到result并返回
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 判断循环依赖? 跳过
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
}
return result;
}
- 查看是否注入成功。
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(DependencySourceDemo.class);
applicationContext.refresh();
DependencySourceDemo bean = applicationContext.getBean(DependencySourceDemo.class);
System.out.println(bean.beanFactory);
System.out.println(bean.resourceLoader);
System.out.println(bean.applicationEventPublisher);
System.out.println(bean.applicationContext);
System.out.print("注入的applicationContext与当前应用上下文是同一个对象: ");
System.out.println(bean.applicationContext == applicationContext);
System.out.print("注入的BeanFactory与当前应用上下文中的BeanFactory是同一个对象: ");
System.out.println((bean.beanFactory == applicationContext.getBeanFactory()));}
// 检验容器中是否有 BeanFactory 类型的bean, 肯定没有,
// 虽然可以进行依赖注入, 但是BeanFactory不是由 Spring 容器管理的
try {
applicationContext.getBean(BeanFactory.class);
} catch (NoSuchBeanDefinitionException e) {
System.out.println("容器中没有 BeanFactory 类型的 bean");
}
}
输出结果:
- 可以看到注入的 BeanFactory 是 DefaultListableBeanFactory 类型,且与当前应用上下文的 BeanFactory 是同一个对象,
- 注入的 ApplicationContext 也与当前上下文 ApplicationContext 是同一个对象
- 注入的 resourceLoader,applicationEventPublisher,applicationContext 都是同一个对象,即当前应用上下文
- ResolvableDependency 对象可以用来依赖注入,但不能进行依赖查找
org.springframework.beans.factory.support.DefaultListableBeanFactory@3745e5c6: 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@7c75222b, started on Tue Apr 27 23:06:01 CST 2021
org.springframework.context.annotation.AnnotationConfigApplicationContext@7c75222b, started on Tue Apr 27 23:06:01 CST 2021
org.springframework.context.annotation.AnnotationConfigApplicationContext@7c75222b, started on Tue Apr 27 23:06:01 CST 2021
注入的applicationContext与当前应用上下文是同一个对象: true
注入的BeanFactory与当前应用上下文中的BeanFactory是同一个对象: true
容器中没有 BeanFactory 类型的 bean
7.3 Spring 容器管理和游离对象
7.4 BeanDefinition 作为依赖来源
通过 7.1 章节我们知道,依赖来源包括 BeanDefinition,包括 xml 配置,@Bean 注解配置,BeanDefinitionBuilder 手动创建的 BeanDefinition。
BeanDefinition 作为依赖来源,有以下几个特点:
- 元数据:BeanDefinition 由 xml 配置,@Bean 注解配置,BeanDefinitionBuilder 手动创建
- 注册到容器:BeanDefinitionRegistry#registerBeanDefinition
- 类型:延迟和非延迟
- 顺序:Bean 初始化时按照声明顺序进行
- 存储:DefaultListableBeanFactory.beanDefinitionMap 属性,是 ConcurrentHashMap 类型
1. 外部 BeanDefinition
通过 xml,@Bean 注解,BeanDefinitionBuilder 手动注册 bean 的方式,见 4.4 章节
- 注册 BeanDefinition 到容器源码分析,无论是 Spring 内建 BeanDefinition,还是 xml 配置,@Bean 注解配置的 bean,都要调用下面的方法注册 BeanDefinition 到容器。DefaultListableBeanFactory 是 BeanDefinitionRegistry 接口的实现类,实现了注册 BeanDefinition 功能
DefaultListableBeanFactory.java,
// 保存BeanDefinition
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 保存bean名称, 有序
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 实现了BeanDefinitionRegistry接口registerBeanDefinition方法
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 校验bean
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 查找bean名称是否已被占用
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// bean名称已被占用, 会使用当前bean进行覆盖
// Springboot2.1中修改为抛出异常BeanDefinitionOverrideException
} else {
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
// 将BeanDefinition注册到容器,即保存到beanDefinitionMap
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
// 添加bean的名称
updatedDefinitions.add(beanName);
// beanDefinitionNames是ArrayList,保证bean初始化的顺序与声明顺序相同
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
} else {
// 将BeanDefinition注册到容器,即保存到beanDefinitionMap
this.beanDefinitionMap.put(beanName, beanDefinition);
// 将bean名称保存到beanDefinitionNames
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
// 补充: debug各种配置bean的方式, 看看注册beandefinition时是不是都一样, 已经debug了, 都是调用该方法
2. Spring 内建 BeanDefinition
通过 7.1 章节我们知道 Spring 有多个内建 BeanDefinition 会注册到容器。
- 源码分析,注册 Spring 内建 BeanDefinition 到上下文。在注解驱动, Annotation 类型上下文等情况下都会调用该方法加载 Spring 内建 bean
AnnotationConfigUtils.java
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// .....
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
// 注册internalConfigurationAnnotationProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// 设置bean的class
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
// 注册bean到上下文registry, bean名称为CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME
// registerPostProcessor 源码见下一个方法
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册internalAutowiredAnnotationProcessor
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));
}
// 注册internalCommonAnnotationProcessor
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册internalPersistenceAnnotationProcessor
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 注册internalEventListenerProcessor
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
// 注册internalEventListenerFactory
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
// 注册beanDefinition到registry
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 见上个代码块
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
- // 补充: 依赖注入Spring内建BeanDefinition
7.5 单例对象作为依赖来源
- 来源:外部普通 java 对象,不一定是 pojo
- 注册:SingletonBeanRegistry#RegisterSingleton
- 无生命周期管理
- 无法实现延迟初始化,因为在外部已经初始化,然后才注册到容器的
- 存储:DefaultSingletonBeanRegistry.singletonObjects 属性,ConcurrentHashMap类型
- 处理依赖:DefaultSingletonBeanRegistry#getSingleton
1. 外部单例对象
- 参考 4.4.4 章节 外部对象注册到容器,下面的例子是手动创建一个 user 对象,将user 对象注册到容器,显而易见,容器无法对 user 进行延迟初始化,也无法进行生命周期管理
public static void main(String[] args) {
// 1. 创建应用上下文
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 2. 创建一个外部 user 对象
User user = new User();
// 3. 注册外部对象到容器
SingletonBeanRegistry beanFactory = applicationContext.getBeanFactory();
beanFactory.registerSingleton("mercy", user);
// 4. 启动应用上下文
applicationContext.refresh();
// 5. 依赖查找, 会优先从容器的 singletonObjects 属性中查找 bean
User mercy = applicationContext.getBean("mercy", User.class);
// 6. 判断容器中的 bean 是否是那个外部对象
System.out.println("mercy == user: " + (mercy == user));
// 7. 关闭应用上下文
applicationContext.close();
}
输出结果:
User{id=null, name='null'}
mercy == user: true
- 注册外部单例对象到容器源码分析,外部 java 对象注册到容器,是保存到容器的 singletonObjects 属性中,是一个ConcurrentHashMap 集合
DefaultSingletonBeanRegistry.java
// 保存外部对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 保存外部对象bean名称顺序
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
// DefaultListableBeanFactory继承了DefaultSingletonBeanRegistry
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);
// 容器中已经存在同名bean, 抛出异常
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
// 将外部java对象保存到ConcurrentHashMap集合singletonObjects
addSingleton(beanName, singletonObject);
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
// singleton和factoryBean互斥
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
// 保存外部对象到LinkedHashSet集合中, 可以保证顺序
this.registeredSingletons.add(beanName);
}
}
- 依赖查找单例 bean 源码分析,在以来查找 getBean() 时会优先从容器的 singletonObjects 属性中查找 bean,查找不到才去 BeanDefinitionMap 中查找。依赖注入底层也是通过依赖查找获取 bean 的,也要执行下面这块代码,调用时机是处理依赖查找候选bean
findAutowireCandidates()
DefaultSingletonBeanRegistry.java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 查找外部单例对象user
Object singletonObject = this.singletonObjects.get(beanName);
// 跳过
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// ...
}
return singletonObject;
}
// 补充: 这里的单例是什么意思?经测试,两个 user 对象都可以注册到容器,只要 bean 名称不同即可
这个 singleton 和 spring 的 scope 里面的单例是一回事
2. Spring 内部单例对象
- 通过 7.1 章节我们知道 Spring 内建单例对象有 environment,systemProperties 等,下面的例子我们依赖注入Spring 内建单例对象,也可以通过依赖查找 Spring 内建单例对象
public class SingletonDependencySourceDemo {
@Autowired
private Environment environment;
// 注入spring内建单例对象,
// 将字段名称作为 bean 名称去容器 singletonObjects 属性中查找
@Autowired
private Map systemProperties;
@Autowired
private Map systemEnvironment;
@Autowired
private MessageSource messageSource;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(SingletonDependencySourceDemo.class);
applicationContext.refresh();
SingletonDependencySourceDemo demo = applicationContext.getBean(SingletonDependencySourceDemo.class);
System.out.println(demo.environment);
System.out.println(demo.systemProperties.get("java.runtime.name"));
System.out.println(demo.systemEnvironment.get("JAVA_HOME"));
System.out.println(demo.messageSource);
// 依赖查找
Environment environment = applicationContext.getBean(Environment.class);
System.out.println(environment==demo.environment);
}
}
输出结果
StandardEnvironment {activeProfiles=[], defaultProfiles=[default],...}
Java(TM) SE Runtime Environment
C:\local\Java\jdk1.8.0_201
Empty MessageSource
true
- Spring 框架在应用上下文启动时
refresh()会调用下面这几个方法,注册 6 个内建单例 bean,源码如下:
AbstractApplicationContext.java
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// ....
// 注册内建environment bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// 注册内建systemProperties bean
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
// 注册内建systemEnvironment bean
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
// 注册内建bean messageSource
protected void initMessageSource() {}
// 注册内建bean applicationEventMulticaster
protected void initApplicationEventMulticaster() {}
// 注册内建bean lifecycleProcessor
protected void initLifecycleProcessor() {}
- 具体注册到容器的代码与上一小节 7.7.1 SingletonBeanRegistry#RegisterSingleton 相同,依赖注入或依赖查找 Spring 内建单例 bean 的源码与上一小节 7.7.1 DefaultSingletonBeanRegistry#getSingleton 相同
7.6 游离对象作为依赖来源
- 注册:ConfigurableListableBeanFactory#registerResolvableDependency
- 无生命周期管理
- 无法实现延迟初始化 bean
- 可以依赖注入,无法通过依赖查找
- 处理依赖:DefaultListableBeanFactory#doResolveDependency -> findAutowireCandidates
1. 外部游离对象
- 手动注册游离对象到容器,ConfigurableListableBeanFactory#registerResolvableDependency
public class ResolvableDependencySourceDemo {
@Autowired
private String value;
@PostConstruct
public void init() {
System.out.println("依赖注入成功, value: " + value);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ResolvableDependencySourceDemo.class);
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// 手动注册游离对象
beanFactory.registerResolvableDependency(String.class, "hello world");
// 启动上下文
applicationContext.refresh();
try {
applicationContext.getBean(String.class);
} catch (NoSuchBeanDefinitionException e) {
System.out.println("容器中没有找到 String 类型的 bean, 说明 ResolvableDependency 对象无法进行依赖查找");
}
}
}
输出结果:
依赖注入成功, value: hello world
容器中没有找到 String 类型的 bean, 说明 ResolvableDependency 对象无法进行依赖查找
- 源码分析,DefaultListableBeanFactory 实现了 ConfigurableListableBeanFactory 接口的 registerResolvableDependency 方法,负责将游离对象注册到容器中,保存到容器的
resolvableDependencies属性中,与 Spring 内建游离对象一样
DefaultListableBeanFactory.java
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
public void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue) {
Assert.notNull(dependencyType, "Dependency type must not be null");
if (autowiredValue != null) {
// 判断游离对象autowiredValue是不是指定的类型dependencyType
// 判断游离对象是不是ObjectFactory类型
if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
throw new IllegalArgumentException("Value [" + autowiredValue +
"] does not implement specified dependency type [" + dependencyType.getName() + "]");
}
// 将游离对象保存到resolvableDependencies集合中
this.resolvableDependencies.put(dependencyType, autowiredValue);
}
}
- 游离对象如何进行依赖注入,以及 Spring 框架默认注册的游离对象和注册时机,见7.2章节
7.7 外部配置作为依赖来源
- 使用 @Value 将外部配置作为依赖来源
- 处理外部化配置的依赖:DefaultListableBeanFactory#doResolveDependency
- 非常规的 Spring 对象依赖来源
- 无生命周期管理
- 无法实现延迟初始化
- 无法通过依赖查找
- 首先创建一个 default.properties 文件,作为外部化配置
user.id = 22
user.name=巴蒂斯特
hero.name=巴蒂斯特
user.resource = aaa
- 使用 @Value 注解依赖注入外部化配置,使用 @PropertySource 指定配置文件
@Configuration // 这个是必须的
@PropertySource("default.properties")
public class ExternalConfigurationDependencySourceDemo {
// 设置默认值为-1
@Value("${user.id:-1}")
private Long id;
// 这里会注入优先级更高的系统属性,即当前操作系统用户的名称
@Value("${user.name}")
private String name;
@Value("${hero.name}")
private String heroName;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ExternalConfigurationDependencySourceDemo.class);
// 启动上下文
applicationContext.refresh();
ExternalConfigurationDependencySourceDemo bean = applicationContext.getBean(ExternalConfigurationDependencySourceDemo.class);
System.out.println("user.id: " + bean.id);
System.out.println("user.name: " + bean.name);
System.out.println("hero.name: " + bean.heroName);
}
}
输出结果
user.id: 22
user.name: mao # 这里会注入优先级更高的系统属性, 即当前操作系统用户名称
hero.name: 巴蒂斯特
- 源码分析,处理依赖的逻辑依然在 DefaultListableBeanFactory#doResolveDependency 中,与处理 BeanDefinition 和 游离对象作为依赖来源的方法是同一个,与 @Autowired 的处理类相同都是 AutowireAnnotationBeanPostProcessor
DefaultListableBeanFactory.java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 获取要注入的bean类型
Class<?> type = descriptor.getDependencyType();
// 6.14 章节跳过了这部分, 因为这里是处理 @Value注解的
// 查找@Value 的信息, 这里是${user.id}
// 见下方代码块
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 解析配置文件中的user.id, 返回"22"
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// 将"22"转为Long类型的22L
// 将value转为type类型, 若类型不匹配抛出TypeMismatchException
// 详细见类型转换章节
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 处理集合类型的依赖
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 处理单个类型的依赖
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
//....
}
public Object getSuggestedValue(DependencyDescriptor descriptor) {
// 查找@Value注解的值, 这里是${user.id}
Object value = findValue(descriptor.getAnnotations());
// 跳过,
if (value == null) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
value = findValue(methodParam.getMethodAnnotations());
}
}
return value;
}
7.8 面试题
-
依赖注入和依赖查找的来源有哪些,是否相同?
答:依赖查找的来源有 2 处:
-
BeanDefinition,外部包括 xml 配置,@Bean 配置,@BeanDefinitionBuilder 手动注册,Spring 内建的 BeanDefinition
-
单例对象,Spring 内建的单例对象,外部手动注册的单例对象
依赖注入的来源相比依赖查找多了 2 处:
- ResolveDependency 游离对象,包括 Spring 内建的和外部手动注册的
- 外部配置使用 @Value 依赖注入
-
-
单例对象能在 IoC 容器启动后注册吗?
答:可以,单例对象的注册与 BeanDefinition 不同,BeanDefinition 会被 ConfigurableListableBeanFactory#freezeConfiguration 方法影响,从而冻结注册,单例对象则没有这个限制。
-
Spring 依赖注入的来源有哪些?
答:1. Spring BeanDefinition,外部 xml 配置,@Bean,BeanDefinition 手动注册,Spring 内建的BeanDefinition。
2. 单例对象,外部手动注册的,Spring 内建的单例对象,如 Environment 3. 游离对象 Resolvable Dependency,如 BeanFactory 4. @Value 外部配置