Spring依赖注入来源
上一章中,我们在第三步的代码分析中可看到,在进行注入的依赖查找的时候,查找来源会从如下几个方式去查找:
- • 1、先看注入是否是外部化配置,如果是,则注入(@Value的方式)
- • 2、遍历看注入的对象是否是
resolvableDependencies
中包含的对象,如果是则返回(非Spring容器管理的对象) - • 3、从Spring容器中的对象中查找返回或者是Spring单例对象中查找返回
接下来我们从源码的角度来看一下注入来源的存储结构。
Spring容器中的对象
Spring容器中的对象,大多数说的就是我们使用
BeanDefinition
构建的对象,这种方式包括了xml、@Bean以及直接使用API构建的方式,当然也包括了一些如AutowiredAnnotationBeanPostProcessor
在内的内建对象。
首先BeanDefinition在Spring容器中主要存储在DefaultListableBeanFactory
对象中,我们来看看他的主要结构:
// 存储BeanDefinition信息,key为bean的名称列表
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 存储BeanDefinition的名称列表,按照注入顺序排序
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
而BeanDefinition信息是在方法DefaultListableBeanFactory#registerBeanDefinition
中注册到上面的集合中的:
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// 数据校验,这里只对AbstractBeanDefinition进行校验是因为BeanDefinitionBuilder创建的BeanDefinition信息在getBeanDefinition时候进行过校验
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 校验是否注册过
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// 注册过的话校验是否可以覆盖注册过的beanDefinition信息
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
// ....
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// 是否正在创建的过程中
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
// 设置beanDefinition信息
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
Spring单例对象
Spring单例对象可以看成是一种特殊的容器对象,他是我们创建好了对象注册到容器中的,所以容器中不会存储他对应的
BeanDefinition
信息,Spring也不会管理他对应的生命周期。
单例对象案例:
public class SingletonBeanRegistryDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(SingletonBeanRegistryDemo.class);
annotationConfigApplicationContext.refresh();
CommonInjectionEntity commonInjectionEntity = new CommonInjectionEntity(1L, "Singleton Bean Registry Test!");
// 获得单例注册器
SingletonBeanRegistry beanFactory = annotationConfigApplicationContext.getBeanFactory();
// 注册单例
beanFactory.registerSingleton("commonInjectionEntity", commonInjectionEntity);
System.out.println(Objects.equals(commonInjectionEntity, annotationConfigApplicationContext.getBean("commonInjectionEntity")));
annotationConfigApplicationContext.close();
}
}
从示例我们也可以看出,单例是我们创建好了的对象再注入到容器中。
单例对象的处理主要存在DefaultSingletonBeanRegistry
对象中:
// 存储Bean得单例对象,key为对象名称
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 有序的存储Bean单例对象的名称
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
而单例对象的注册主要是在DefaultSingletonBeanRegistry#registerSingleton()
方法中:
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
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);
}
}
非Spring容器管理的对象
什么是非Spring容器管理的对象,换句话来说,也就是我们在使用
BeanFactory#getBean()
的时候获取不到的对象就是非Spring容器管理的对象。
首先我们来看一下非容器化管理的对象的存储结构,他其实就是DefaultListableBeanFactory
对象中的字段resolvableDependencies
:
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
他的设置主要是在DefaultListableBeanFactory#registerResolvableDependency()
方法中:
@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);
}
}
从设置上来看他非常简单,就只是一个简单的存储,在Spring中AbstractApplicationContext#refresh()
方法的第三步prepareBeanFactory()
中,对非Spring容器管理的对象进行了模式添加:
image-20230325213635546
至此我们也可以借助这四个对象来进行测试:
public class ResolvableDependenciesSourceDemo {
@Resource
private BeanFactory beanFactory;
@Resource
private ResourceLoader resourceLoader;
@Resource
private ApplicationEventPublisher applicationEventPublisher;
@Resource
private ApplicationContext applicationContext;
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(ResolvableDependenciesSourceDemo.class);
annotationConfigApplicationContext.refresh();
// 自动注入校验 注入成功
checkAutowiredInfo(annotationConfigApplicationContext);
// 依赖查找校验 全报错
checkLookUp(annotationConfigApplicationContext);
annotationConfigApplicationContext.close();
}
private static void checkAutowiredInfo(BeanFactory beanFactory) {
ResolvableDependenciesSourceDemo bean = beanFactory.getBean(ResolvableDependenciesSourceDemo.class);
System.out.println("beanFactory == resourceLoader" + (bean.beanFactory == bean.resourceLoader));
System.out.println("resourceLoader == applicationEventPublisher" + (bean.resourceLoader == bean.applicationEventPublisher));
System.out.println("beanFactory == applicationEventPublisher" + (bean.beanFactory == bean.applicationEventPublisher));
System.out.println("beanFactory == applicationContext" + (bean.beanFactory == bean.applicationContext));
}
private static void checkLookUp(BeanFactory beanFactory) {
checkLookUp(beanFactory, BeanFactory.class);
checkLookUp(beanFactory, ResourceLoader.class);
checkLookUp(beanFactory, ApplicationEventPublisher.class);
checkLookUp(beanFactory, ApplicationContext.class);
}
private static void checkLookUp(BeanFactory beanFactory, Class<?> clazz) {
try {
beanFactory.getBean(clazz);
} catch (BeansException e) {
System.out.println("Spring上下文不存在对象:" + clazz.getName());
}
}
}
注意:如下面例子一样注册到resolvableDependencies
中后,不同的注入方式可能会导致的结果不同。
演示:
从下面配置可以看出当使用@Resource
中按照名称注入的时候输出的对象与其他形式不同。
public class ResolvableDependenciesSourceDemo {
@Autowired
private CommonInjectionEntity autowiredCommonInjectionEntity;
@Autowired
@Qualifier(value = "commonInjectionEntity")
private CommonInjectionEntity aualifierAutowiredCommonInjectionEntity;
@Resource
private CommonInjectionEntity resolrceCommonInjectionEntity;
@Resource
private CommonInjectionEntity commonInjectionEntity;
@Autowired
private Map<String, CommonInjectionEntity> autowiredCommonInjectionEntityMap;
@Resource
private Map<String, CommonInjectionEntity> resourceCommonInjectionEntityMap;
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(ResolvableDependenciesSourceDemo.class);
annotationConfigApplicationContext.getBeanFactory().registerResolvableDependency(CommonInjectionEntity.class, new CommonInjectionEntity(1L,"ResolvableDependency中的对象"));
annotationConfigApplicationContext.refresh();
ResolvableDependenciesSourceDemo bean = annotationConfigApplicationContext.getBean(ResolvableDependenciesSourceDemo.class);
// Autowired按照类型注入:CommonInjectionEntity{id=1, desc='ResolvableDependency中的对象'}
System.out.println(bean.autowiredCommonInjectionEntity);
// Autowired按照名称注入:CommonInjectionEntity{id=1, desc='ResolvableDependency中的对象'}
System.out.println(bean.aualifierAutowiredCommonInjectionEntity);
// Resource按照类型注入:CommonInjectionEntity{id=1, desc='ResolvableDependency中的对象'}
System.out.println(bean.resolrceCommonInjectionEntity);
// Resource按照名称注入:CommonInjectionEntity{id=2, desc='Spring IOC 容器中的对象'}
System.out.println(bean.commonInjectionEntity);
// Autowired注入Map:{cn.phshi.domain.CommonInjectionEntity@27a8c74e=CommonInjectionEntity{id=1, desc='ResolvableDependency中的对象'}}
System.out.println(bean.autowiredCommonInjectionEntityMap);
// Resource注入Map:{cn.phshi.domain.CommonInjectionEntity@27a8c74e=CommonInjectionEntity{id=1, desc='ResolvableDependency中的对象'}}
System.out.println(bean.resourceCommonInjectionEntityMap);
annotationConfigApplicationContext.close();
}
@Bean
public CommonInjectionEntity commonInjectionEntity() {
return new CommonInjectionEntity(2L,"Spring IOC 容器中的对象");
}
}
我们会发现当使用@Resource
名称注入的时候输出的结果会与其他注入的输出结果不同。虽然我们平时开发几乎用不到这种情况,但是我们还是要认识这种坑。为什么会产生这种情况呢?
我们知道@Resource
会优先名称注入,名称注入找不到再通过类型注入,产生上面的原因就是因为这个。@Resource
具体注入的代码存在于CommonAnnotationBeanPostProcessor#autowireResource()
中,我们来看看区别这块的代码:
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
// 名称校验 通过factory.containsBean判断IOC容器中是否存在对象 注意加了!
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
// 通过类型查找,其实具体非容器管理对象查找逻辑在内部
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
// 就是在IOC容器中取对象
else {
// 其实就是执行 getBean()
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
// ....
return resource;
}
外部化配置
外部化配置使用简单,这里就不做示例
标签:依赖,beanFactory,对象,Spring,beanName,bean,new,注入 From: https://blog.51cto.com/u_16115561/6524012