Spring自动装配实现原理

Spring自动装配实现原理

Java中使用注解的情况主要在SpringMVC(SpringBoot等),注解实际上相当于一种标记语言,它允许你在运动时动态地对拥有标签的成员进行操作。

注意:spring框架默认不支持自动装配,要想使用自动装配需要更改spring配置文件中标签的autowire属性

自动配置有六个值可以选,分别代表不同含义:


byName

从spring环境中获取环境对象时,目标对象中的属性会根据名称在整个Spring环境中查找标签的id属性值。如果有相同的,那么获取这个对象,实现关联。

整个Spring环境:表示所有的Spring配置文件中查找,那么id不能有重复的

byType

从Spring环境中获取目标对象时,目标对象的属性会根据类型在spring环境中查找标签的class属性值。如果有相同的,获取这个对象,实现关联


缺点:如果存在多个相同类型的bean对象,会出错;如果属性为单一类型的数据,那么查找到多个关联对象会发生错误;如果属性为数组或者集合(泛型)类型,那么查找到多个关联对象不会发生异常。


constructor -> 使用构造方法完成对象注入,其实也是根据构造参数类型进行对象查找,相当于使用byType的方式

autodetect -> 自动选择:如果对象没有无参数的构造方法,那么自动选择constructor的自动装配方法进行构造注入。如果对象含有无参数的构造方法,那么自动选择byType的自动装配方式进行setter注入


no -> 不支持自动装配

default -> 表示默认采用上一级标签的自动装配的取值。如果存在多个配置文件的话,那么每一个配置文件的自动装配方式都是独立的


SpringBoot声明周期流程图

bean自身方法的声明周期

分为四步:

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

    • 读取Spring配置文件

    • 通过反射进行bean的实例化(通过BeanFactory实例化)

  2. 属性赋值

    • 解析自动装配(byName、byType、constructor、default)DI的体现

    • 循环依赖

  3. 初始化

    • 调用XXXAware回调方法

    • 调用初始化声明周期回调(三种)

    • 如果bean实现aop创建动态代理

  4. 销毁

    • 在Spring容器关闭时进行调用

    • 调用初始化生命周期回调

下图展示了bean装载到spring应用上下文的一个典型的声明周期过程

image-20231017162656249

image-20231017162733246

@Autowired注解的自动装配过程

结论:

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

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

  2. 在Bean的创建的过程中进行创建

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

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

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

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

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

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

大致流程图为下:

image-20231017164421380

@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}
  1. AutowiredAnnotationBeanPostProcessor是Spring的后置处理器,专门处理@Autowired和@Value注解。查看AutowiredAnnotationBeanPostProcessor类,关注postProcessorMergedBeanDefiniton()方法、postProcessorPropertyValues()方法和构造器

    //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;
    }
    1. 查看对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);
            }
        }
    }
    1. 查看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);的原始方法,它还有两个子类自己实现的方法,如图:

image-20231017190036871

此案例是字段注入分析,查看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,利用反射注入到字段中完成赋值;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值