你不知道的Spring的依赖的查找和注入的来源

1.写在前面

前面的博客我们已经介绍完了spring的依赖的查找和注入的方式,这篇博客我们主要介绍下spring的依赖的查找和注入的来源。

2.依赖查找的来源

查找来源

在这里插入图片描述

Spring 內建 BeanDefintion

在这里插入图片描述

Spring 內建单例对象

在这里插入图片描述

上面的各种依赖都是在spring的生命周期的过程中,初始化的,这儿不做过多的赘述,后面的博客我们在详细的介绍。

3.依赖注入的来源

注入来源

在这里插入图片描述

具体的代码如下:

package org.learn.spring.dependency.source;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.ResourceLoader;

import javax.annotation.PostConstruct;

// 依赖来源示例
// BeanFactory.class ResourceLoader.class ApplicationEventPublisher.class ApplicationContext.class 不能用于我们的getBean
public class DependencySourceDemo {

    // 注入在 postProcessProperties 方法执行,早于 setter注入 也早于生命周期回调函数@PostConstruct
    @Autowired
    private BeanFactory beanFactory;

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private ApplicationContext applicationContext;

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

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

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

    public static void main(String[] args) {
        // 创建BeanFactory的容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册Configuration Class 配置类 -> Spring Bean
        applicationContext.register(DependencySourceDemo.class);

        // 启动应用上下文
        applicationContext.refresh();

        // 依赖查找 DependencySourceDemo Bean
        DependencySourceDemo demo = applicationContext.getBean(DependencySourceDemo.class);


        // 显示的关闭spring应用上下文
        applicationContext.close();
    }
}

运行的结果如下:

在这里插入图片描述

这儿的对象我们称之为spring的非托管对象,那么是怎么注册的。具体的如下:

在这里插入图片描述

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

依赖对象

在这里插入图片描述

5.Spring BeanDefinition 作为依赖来源

要素

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

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

要素

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

限制

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

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

要素

  • 注册: ConfigurableListableBeanFactory#registerResolvableDependency

限制

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

具体的代码如下:

package org.learn.spring.dependency.source;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.annotation.PostConstruct;

// ResolvableDependency 作为依赖来源
// 这儿的依赖的注入只能是类型的依赖的注入
public class ResolvableDependencySourceDemo {

    @Autowired
    private String value;

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

    public static void main(String[] args) {
        // 创建BeanFactory的容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册Configuration Class 配置类 -> Spring Bean
        applicationContext.register(ResolvableDependencySourceDemo.class);

        applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
            // 注册 Resolvable Dependency
            beanFactory.registerResolvableDependency(String.class, "Hello,World");
        });

        // 启动应用上下文
        applicationContext.refresh();
        

        // 显示的关闭spring应用上下文
        applicationContext.close();
    }
}

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

要素

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

限制

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

具体的代码如下

user.id=1
usr.name=甘雨
user.resource=classpath:/META-INF/default.properties
package org.learn.spring.dependency.source;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;

import javax.swing.text.StyleConstants;

// 外部化配置作为依赖的来源
@PropertySource(value = "classpath:/META-INF/default.properties",encoding = "UTF-8")
@Configuration
public class ExternalConfigurationDependencySourceDemo {

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

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

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

    public static void main(String[] args) {
        // 创建BeanFactory的容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册Configuration Class 配置类 -> Spring Bean
        applicationContext.register(ExternalConfigurationDependencySourceDemo.class);

        // 启动应用上下文
        applicationContext.refresh();

        // 依赖查找 ExternalConfigurationDependencySourceDemo Bean
        ExternalConfigurationDependencySourceDemo demo = applicationContext.getBean(ExternalConfigurationDependencySourceDemo.class);

        System.out.println("demo.id = " + demo.id);
        System.out.println("demo.name = " + demo.name);
        System.out.println("demo.resource = " + demo.resource);

        // 显示的关闭spring应用上下文
        applicationContext.close();
    }
}

9.再来简单的看一下相应的源码

注册BeanDefinition,具体的代码如下:

	@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");

    // 我们这儿所有的BeanDefinition的类型都是AbstractBeanDefinition AbstractBeanDefinition是所有的BeanDefinition的超类
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
        // 这儿会校验BeanDefinition,这儿我不会做过多的赘述,后面有专门的博客来做介绍
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

    // 先查找对应的BeanDefinition是否存在
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
      // 如果存在的话,看看这个BeanDefinition是否可以被覆盖,如果可以被覆盖,就重新存入Map中去,springFramework默认是true,是可以被覆盖,在springboot这个值被被改成了false,这儿就会抛出异常。
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
      // 判断当前的BeanDefinition是否在创建中
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
          // 将对应的key为BeanName value的值为BeanDefinition存放到beanDefinitionMap 中去
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
          // 将对应的BeanName的Map进行更新
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
        // 如果没有创建就将key为BeanName value的值为BeanDefinition存放到beanDefinitionMap 中去
				this.beanDefinitionMap.put(beanName, beanDefinition);
        // 将对应的BeanName存到beanDefinitionNames的List中去
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

从上面的的代码我们可以知道BeanDefinition是存在beanDefinitionMap的Map中去,key 是beanName,valueBeanDefinition。同时将beanName存到beanDefinitionNames的List中去。

注册单例对象,具体的代码如下:

	@Override
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    // 走来调用的是父类的方法
		super.registerSingleton(beanName, singletonObject);
		updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
		clearByTypeCache();
	}

可以看到我们走来调用的是父类的方法org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerSingleton

具体的代码如下:

	@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) {
      // 将这个单例的对象存到对应Map中去,key为beanName value为singletonObject
			this.singletonObjects.put(beanName, singletonObject);
      // 从singletonFactories中移出beanName
			this.singletonFactories.remove(beanName);
      // 从earlySingletonObjects中移出beanName
			this.earlySingletonObjects.remove(beanName);
      // 从registeredSingletons中添加beanName
			this.registeredSingletons.add(beanName);
		}
	}

从上面的代码我们可以知道单例的对象是添加singletonObjectsMap中keybeanNamevalue是这个单例的对象。同时beanName也会存到registeredSingletons中去。

ResolvableDependency最后是不受spring管理的对象,注册的过程如下:

	@Override
	public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
		Assert.notNull(dependencyType, "Dependency type must not be null");
		if (autowiredValue != null) {
      // 是ObjectFactory 直接抛出异常
			if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
				throw new IllegalArgumentException("Value [" + autowiredValue +
						"] does not implement specified dependency type [" + dependencyType.getName() + "]");
			}
      // 将对应的对象存到resolvableDependencies Map中去 key为dependencyType value为autowiredValue
			this.resolvableDependencies.put(dependencyType, autowiredValue);
		}
	}

上面的代码就是将这个对象存到resolvableDependencies存到Map中去,key为dependencyType value为autowiredValue。上面的就是所有的依赖的注入的来源。而依赖的查找只会BeanDefinition的和singletonObjects这两个,这部分源码后面在介绍。

10.面试题

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

否, 依赖查找的来源仅限于 Spring BeanDefinition 以及单例对象, 而依赖注入的来源还包括 Resolvable Dependency 以及@Value 所标注的外部化配置

10.2 单例对象能在 IoC 容器启动后注册吗?

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

10.3 Spring 依赖注入的来源有哪些?

  • Spring BeanDefinition
  • 单例对象
  • Resolvable Dependency
  • @Value 外部化配置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值