spring自动装配原理

这篇具有很好参考价值的文章主要介绍了spring自动装配原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

为了搞明白自动装配原理,需要知道spring容器管理bean的生命周期

Spring Bean 生命周期流程图

spring自动装配原理

bean自身方法的生命周期

分为四步:

//执行此段代码,spring容器的bean执行实例化、属性赋值、初始化
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
//关闭容器,执行销毁
classPathXmlApplicationContext.close();

1、实例化

  • 读取spring配置文件
  • 通过反射进行bean的实例化(eg:通过BeanFactory实例化)

2、属性赋值

  • 解析自动装配(byName、byType、constractor、default)DI的体现
  • 循环依赖

3、初始化

  • 调用XXXAware回调方法
  • 调用初始化生命周期回调(三种)
  • 如果bean实现aop创建动态代理

4、销毁

  • 在spring容器关闭的时候进行调用
  • 调用初始化生命周期回调

对应上述文字,下图展示了bean装载到spring应用上下文种的一个典型的生命周期过程

spring自动装配原理

spring自动装配原理

@Autowired注解的自动装配过程

先说结论:

@Autowired是在Bean属性赋值阶段进行装配,通过Bean的后置处理器进行解析

1、在创建一个spring上下文的时候在构造函数中注册AutowiredAnnotationBeanPostProcessor

2、在Bean的创建过程中进行解析

        1、在实例化后预解析(解析@Autowired标注的属性、方法,比如:把属性的类型、名称、属性所在的类...元数据缓存)

        2、在属性赋值阶段真正的注入(拿到上一步缓存的元数据去ioc容器进行查找,并且返回注入)

                a.首先根据解析的元数据拿到类型去容器种查找

                        *如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

                        *如果查询的结果不止一个,那么@Autowired会根据名称来查找

                        *如果上述查找结果为空,那么就会抛出异常。

大致流程图如下:

spring自动装配原理

 @Autowired字段注入源码分析

/* ......源码注解过多,只贴一部分有用的
 * <h3>Not supported in {@code BeanPostProcessor} or {@code BeanFactoryPostProcessor}</h3>
 * <p>Note that actual injection is performed through a
 * {@link org.springframework.beans.factory.config.BeanPostProcessor
 * BeanPostProcessor} which in turn means that you <em>cannot</em>
 * use {@code @Autowired} to inject references into
 * {@link org.springframework.beans.factory.config.BeanPostProcessor
 * BeanPostProcessor} or
 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor}
 * types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
 * class (which, by default, checks for the presence of this annotation).
 *
 * @author Juergen Hoeller
 * @author Mark Fisher
 * @author Sam Brannen
 * @since 2.5
 * @see AutowiredAnnotationBeanPostProcessor
 * @see Qualifier
 * @see Value
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

1、重点在注释里的一句:

 Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}

2、AutowiredAnnotationBeanPostProcessor是Spring的后置处理器,专门处理@Autowired和@Value注解。查看AutowiredAnnotationBeanPostProcessor类,关注postProcessMergedBeanDefinition()方法、postProcessPropertyValues()方法和构造器;

//Spring在每个Bean实例化的时候,调用populateBean进行属性注入的时候,即调用postProcessPropertyValues方法。
@Deprecated
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
	return postProcessProperties(pvs, bean, beanName);
}


//​Spring容器在每个Bean实例化之后,调用AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法。
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
	metadata.checkConfigMembers(beanDefinition);
}

//AutowiredAnnotationBeanPostProcessor构造器
public AutowiredAnnotationBeanPostProcessor() {
	//后置处理器将处理@Autowire注解
	this.autowiredAnnotationTypes.add(Autowired.class);
	//后置处理器将处理@Value注解
	this.autowiredAnnotationTypes.add(Value.class);
	try {
		//后置处理器将处理javax.inject.Inject JSR-330注解
		this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
				ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
		logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
}

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    //获取指定类中autowire相关注解的元信息
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
        //对Bean的属性进行自动注入
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

3、查看对Bean的属性进行自动注入metadata.inject(bean, beanName, pvs);方法

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
    //要注入的字段集合
	Collection<InjectedElement> elementsToIterate = (checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		for (InjectedElement element : elementsToIterate) {
			element.inject(target, beanName, pvs);
		}
	}
}

4、查看element.inject(target, beanName, pvs);方法

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {
	if (this.isField) {
		Field field = (Field) this.member;
		ReflectionUtils.makeAccessible(field);
		field.set(target, getResourceToInject(target, requestingBeanName));
	}
	else {
		if (checkPropertySkipping(pvs)) {
			return;
		}
		try {
			Method method = (Method) this.member;
			ReflectionUtils.makeAccessible(method);
			method.invoke(target, getResourceToInject(target, requestingBeanName));
		}
		catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}
}

这是element.inject(target, beanName, pvs);的原始方法,它还有两个子类自己实现的方法,如图:

spring自动装配原理

 此案例是字段注入分析,查看AutowiredFieldElement

//AutowiredAnnotationBeanPostProcessor.java

	@Override
	protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		//获取要注入的字段
		Field field = (Field) this.member;
		Object value;
		//如果字段的值有缓存
		if (this.cached) {
			//从缓存中获取字段值value
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		//没有缓存
		else {
			//创建一个字段依赖描述符
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			//获取容器中的类型转换器
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			try {
				//核心!获取注入的值
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			//线程同步,确保容器中数据一致性
			synchronized (this) {
				//如果字段的值没有缓存
				if (!this.cached) {
					//字段值不为null,并且required属性为true
					if (value != null || this.required) {
						this.cachedFieldValue = desc;
						//为指定Bean注册依赖Bean
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							//如果容器中有指定名称的Bean对象
							if (beanFactory.containsBean(autowiredBeanName)) {
								//依赖对象类型和字段类型匹配,默认按类型注入
								if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									//创建一个依赖对象的引用,同时缓存
									this.cachedFieldValue = new ShortcutDependencyDescriptor(
											desc, autowiredBeanName, field.getType());
								}
							}
						}
					}
					//如果获取的依赖关系为null,且获取required属性为false
					else {
						//将字段值的缓存设置为null
						this.cachedFieldValue = null;
					}
					//容器已经对当前字段的值缓存
					this.cached = true;
				}
			}
		}
		//如果字段值不为null
		if (value != null) {
			//显式使用JDK的反射机制,设置自动的访问控制权限为允许访问
			ReflectionUtils.makeAccessible(field);
			//为字段赋值
			field.set(bean, value);
		}
	}

从注解@Value/@Autowired中获取要注入的值,之后利用反射set到字段中。 重点就是怎么从注解中获取要注入的值,我们来看核心代码

value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
//DefaultListableBeanFactory.java

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
	@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
	if (Optional.class == descriptor.getDependencyType()) {
		return createOptionalDependency(descriptor, requestingBeanName);
	}
	else if (ObjectFactory.class == descriptor.getDependencyType() ||
			ObjectProvider.class == descriptor.getDependencyType()) {
		return new DependencyObjectProvider(descriptor, requestingBeanName);
	}
	else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
		return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
	}
	else {
		Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
				descriptor, requestingBeanName);
		if (result == null) {
			//真正获取值的代码
			result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
		}
		return result;
	}
	}

进行跟踪:

//DefaultListableBeanFactory.java

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
	@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
	try {
		Object shortcut = descriptor.resolveShortcut(this);
		if (shortcut != null) {
			return shortcut;
		}

		//获取字段属性的类型
		Class<?> type = descriptor.getDependencyType();

		//拿到@Value里的值
		Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
		if (value != null) {
			if (value instanceof String) {
				String strVal = resolveEmbeddedValue((String) value);
				BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
				value = evaluateBeanDefinitionString(strVal, bd);
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			return (descriptor.getField() != null ?
					converter.convertIfNecessary(value, type, descriptor.getField()) :
					converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
		}

		//如果标识@Autowired注解的属性是集合类型,Array,Collection,Map,
		// 从这个方法获取@Autowired里的值
<1>		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
		if (multipleBeans != null) {
			return multipleBeans;
		}

		//如果标识@Autowired注解的属性是非集合类型,
		// 从这个方法获取@Autowired里的值
<2>		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		//如果没有符合该类型的Bean
		if (matchingBeans.isEmpty()) {
			//是否是必须的
			if (isRequired(descriptor)) {
				//抛出异常
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;

		//如果符合该类型的Bean有多个
		if (matchingBeans.size() > 1) {
			//挑选出最优解
<3>			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
					//抛出异常
					return descriptor.resolveNotUnique(type, matchingBeans);
				}
				else {
					// In case of an optional Collection/Map, silently ignore a non-unique case:
					// possibly it was meant to be an empty collection of multiple regular beans
					// (before 4.3 in particular when we didn't even look for collection beans).
					return null;
				}
			}
			instanceCandidate = matchingBeans.get(autowiredBeanName);
		}
		else {
			// We have exactly one match.
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
			autowiredBeanName = entry.getKey();
			instanceCandidate = entry.getValue();
		}

		if (autowiredBeanNames != null) {
			autowiredBeanNames.add(autowiredBeanName);
		}
		if (instanceCandidate instanceof Class) {
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		Object result = instanceCandidate;
		if (result instanceof NullBean) {
			if (isRequired(descriptor)) {
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			result = null;
		}
		if (!ClassUtils.isAssignableValue(type, result)) {
			throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
		}
		return result;
	}
	finally {
		ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
	}
	}

大致流程就是: 根据字段类型从IOC容器中获取符合的Bean,如果有多个,则挑选出最优的那一个。

<1>处:@Autowired注入集合数组,如Map.List。

<2>处:@Autowired注入非集合数组,即普通的类如Service

<3>处:多个同类型的bean中挑选出最优解

总结:

        在容器启动,为bean属性赋值的时候,spring会用后置处理器AutowiredAnnotationBeanPostProcessor解析@Autowired注解,来创建属性的实例,然后从IOC容器中根据@Primary、@Order、@PriorityOrder或Spring默认规则挑选出最符合的Bean,利用反射注入到字段中完成赋值;文章来源地址https://www.toymoban.com/news/detail-430772.html

到了这里,关于spring自动装配原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot源码解析 - 自动装配原理

    Spring Boot 自动装配是 Spring Boot 框架的一个关键特性,它的目标是让开发者能够快速构建 Spring 应用程序,减少繁琐的配置工作。   @SpringApplication 从启动类 @SpringApplication 注解入手, @SpringBootApplication 是一个组合注解,它是 Spring Boot 框架中常用的一个主要注解之一。它结合了

    2024年01月19日
    浏览(30)
  • Spring Boot中自动装配机制的原理

    1 .自动装配,简单来说就是自动把第三方组件的Bean装载到Spring IOC容器里面 ,不需要开发人员再去写Bean的装配配置, 2.在Spring Boot应用里面,只需要在启动类加上 @SpringBootApplication 注解就可以实现自动装配。 3.@SpringBootApplication是一个复合注解, 真正实现自动装配的注解是@

    2024年02月10日
    浏览(26)
  • 【Spring Boot自动装配原理详解与常见面试题】—— 每天一点小知识

                                                                  💧 S p r i n g B o o t 自动装配原理详解与常见面试题 color{#FF1493}{Spring Boot自动装配原理详解与常见面试题} Sp r in g B oo t 自动装配原理详解与常见面试题 💧           🌷 仰望天空

    2024年02月16日
    浏览(33)
  • spring boot自动装配及自动装配条件判断

    第一步需要在pom.xml文件指定需要导入的坐标 要是没有自动提示需要检查maven有没有 实现代码 执行代码示例

    2024年02月20日
    浏览(26)
  • Spring Boot自动装配

    自动装配是 Spring Boot 最核心的功能之一,第三方可以基于这个特性非常方便的和 Spring 做整合,实现自己的 Starter,做到开箱即用。 Java 早期并不支持注解,所以那会儿 Spring 只能通过 xml 的形式来配置。早期项目里要引入一个功能模块,首先我们要引入 SDK,然后在 xml 里配置

    2024年01月23日
    浏览(32)
  • springboot自动装配大概原理

    自动装配 : pom.xml spring-boot-dependence:核心都依赖在父类工程中! 我们在写入或者引入springboot依赖的时候,不需要指定版,因为有这些仓库的版本 启动器:------spring boot的启动场景 比如spring-boot-starter-web,他就会帮我们导入web环境苏需要的依赖。 springboot会将所有的功能场景

    2023年04月25日
    浏览(24)
  • SpringBoot自动装配原理

            自动装配简单来说就是自动去把第三方的组件bean加载到springIOC容器当中,不需要开发人员再去写bean相关的配置,springboot应用里面只需要把@SpringbootApplication注解加在启动类上边,就可完成自动配置的功能,而@SpringbootApplication是一个复合注解,真正完成自动配置功

    2024年01月22日
    浏览(35)
  • SpringBoot自动装配原理及分析

    在使用SpringBoot的时候,会自动将Bean装配到IOC容器中。例如我们在使用Redis数据库的时候,会引入依赖spring-boot-starter-data-redis。在引入这个依赖后,服务初始化的时候,会将操作Redis需要的组件注入到Ioc容器中进行后续使用。 自动装配的大致过程如下: 获取到组件(spring-boo

    2024年01月21日
    浏览(31)
  • spring中的Bean的自动装配

    自动装配是使用spring满足bean依赖的一种方法 spring会在应用上下文中为某个bean寻找其依赖的bean 在xml中显式配置;(bean标签和property标签) 在java中显式配置;(get,set方法) 隐式的bean发现机制和自动装配。(自动装配) Spring的自动装配需要从两个角度来实现,或者说是两个

    2024年02月15日
    浏览(30)
  • 深入了解Spring Boot自动装配

    Spring Boot的自动装配是一项强大的功能,能够简化应用程序的配置和开发过程。让我们通过一系列详细的例子来深入了解这一特性。 在Spring Boot中,自动装配是指框架根据应用程序的依赖关系,自动配置和装配相应的Bean,而无需手动设置。这使得开发者可以更专注于业务逻辑

    2024年01月23日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包