Spring源码分析(九)依赖注入源码解析2:AutowireCapableBeanFactory#resolveDependency 从工厂解析依赖项

入口分析

先回顾一下上节@Autowired注解注入,寻找注入点的方法:
在这里插入图片描述
AutowiredFieldElement:字段对应的注入点
AutowiredMethodElement:方法对应的注入点
并且是针对@Autowired、@Value、@Inject注解标记的字段或方法:
在这里插入图片描述

注入点注入入口:
org.springframework.beans.factory.annotation.InjectionMetadata#inject

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);
        }
    }
}

根据字段、方法有不同的实现,依次看一下

字段注入:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    //优先从缓存取,先不看
    if (this.cached) {...}
    else {
        //根据field从BeanFactory中查到的匹配的Bean对象
        value = resolveFieldValue(field, bean, beanName);
    }
    if (value != null) {
        //反射给field赋值
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
}

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue

private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
    //构造依赖描述符对象
    //	DependencyDescriptor:描述符用于即将被注入的特定依赖项。包装构造函数参数、方法参数或字段,允许统一访问它们的元数据。
    //	this.required:@Autowired的required属性
    DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
    desc.setContainingClass(bean.getClass());
    
    //autowiredBeanNames(在后续执行过程中会)记录当前Bean需要注入的Bean的BeanName
    Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
    Assert.state(beanFactory != null, "No BeanFactory available");
    //类型转换器
    TypeConverter typeConverter = beanFactory.getTypeConverter();
    Object value;
    try {
        //核心方法,从工厂中解析依赖项要注入的值
        //针对这个工厂中定义的bean解析指定的依赖项
        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    }
    catch (BeansException ex) {...}
    //后面是将结果缓存,先不看
    synchronized (this) {...}
    return value;
}

核心方法是AutowireCapableBeanFactory#resolveDependency

方法注入:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    //如果pvs中已经有当前注入点的值了,则跳过注入
    if (checkPropertySkipping(pvs)) {
        return;
    }
    Method method = (Method) this.member;
    Object[] arguments;
    //有缓存先从缓存取,暂时不看
    if (this.cached) {...}
    else {
        //当前是方法入注,这里会解析方法入参
        arguments = resolveMethodArguments(method, bean, beanName);
    }
    if (arguments != null) {
        try {
            //反射调用方法
            ReflectionUtils.makeAccessible(method);
            method.invoke(bean, arguments);
        }
        catch (InvocationTargetException ex) {...}
    }
}

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#resolveMethodArguments

    private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
        //方法有可能有多个参数,所以这里都是数组
        int argumentCount = method.getParameterCount();
        Object[] arguments = new Object[argumentCount];
        DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
        
        //autowiredBeanNames记录了当前Bean需要注入的Bean的BeanName
        Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
        Assert.state(beanFactory != null, "No BeanFactory available");
        //类型转换器
        TypeConverter typeConverter = beanFactory.getTypeConverter();

        //遍历每个方法参数,找到匹配的bean对象
        for (int i = 0; i < arguments.length; i++) {
            //i是索引,代表方法上的第几个参数
            MethodParameter methodParam = new MethodParameter(method, i);
            //构造依赖描述符(对于方法入注,多个参数情况就会对应多个依赖描述符)
            DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
            currDesc.setContainingClass(bean.getClass());
            descriptors[i] = currDesc;
            try {
                //看到也是调用了beanFactory.resolveDependency
                //核心方法,从工厂中解析依赖项要注入的值
                //针对这个工厂中定义的bean解析指定的依赖项
                Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
                if (arg == null && !this.required) {
                    arguments = null;
                    break;
                }
                //每个参数对应的要传入的值
                arguments[i] = arg;
            }
            catch (BeansException ex) {
                throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
            }
        }
        //缓存逻辑,和字段注入差不多,暂时不看
        synchronized (this) {...}
        return arguments;
    }
}

可以看到,无论是字段注入,还是方法注入,解析依赖项要注入的值都调用了org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set<java.lang.String>, org.springframework.beans.TypeConverter)

从工厂解析依赖项

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
	//descriptor可能是字段,也可能是普通方法、构造方法中的一个参数

    //1.初始化参数名字发现器,用来获取方法入参名字的
    //	如果是字段注入,拿字段的类型和字段的名字比较简单
    //  但是方法注入,拿方法参数的类型简单,但是拿方法参数的名字就比较复杂
    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

    //接下来会判断 字段/方法参数 的类型,走不同的逻辑:

    // 2. 处理Optional类型的依赖注入
    if (Optional.class == descriptor.getDependencyType()) {
        //为指定的依赖项创建可选包装器。
        return createOptionalDependency(descriptor, requestingBeanName);
    }
    // 3. 处理ObjectFactory和ObjectProvider类型的依赖注入
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {
        //可序列化的ObjectFactory/ObjectProvider用于延迟解析依赖项。
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    // 处理JSR330 相关的依赖注入
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    else {
    	//4. 查找具体的依赖注入对象(最常见)

        //4.1 判断是否是懒注入
        //	在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选bean
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                descriptor, requestingBeanName);
        if (result == null) {
            //4.2 真正开始解析依赖项,核心是doResolveDependency
            //	descriptor表示某个字段属性、或某个方法上的某个入参
            //	requestingBeanName表示当前正在进行依赖注入的Bean
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }
}

1. 初始化参数名字发现器

在jdk1.7中,拿方法入参类型有直接的api,但是获取参数名字没有直接提供api:
在这里插入图片描述
而1.8提供了getParameters方法可以获取Parameter,但是getName名字并不是我们期望的:
在这里插入图片描述
还需要配置一个编译时期的参数:
在这里插入图片描述
刷新一下maven,并重新编译以后再次执行:
在这里插入图片描述

上面可以看出,java反射层面其实并没有什么比较方便的api可以拿到方法入参到名字,那Spring是如何拿到的呢?默认支持两种方式,一个是上面说的反射,另一个是利用了一些字节码层面的技术,直接分析字节码内容是可以拿到的。

看Spring源码:
org.springframework.beans.factory.config.DependencyDescriptor#initParameterNameDiscovery

//这个方法比较简单,就是set赋值
public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) {
    if (this.methodParameter != null) {
        this.methodParameter.initParameterNameDiscovery(parameterNameDiscoverer);
    }
}

//org.springframework.core.MethodParameter#initParameterNameDiscovery
public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) {
    this.parameterNameDiscoverer = parameterNameDiscoverer;
}

获取参数名字发现器:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getParameterNameDiscoverer

protected ParameterNameDiscoverer getParameterNameDiscoverer() {
    return this.parameterNameDiscoverer;
}

有默认实现提供:
在这里插入图片描述

public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {

	public DefaultParameterNameDiscoverer() {
		// TODO Remove this conditional inclusion when upgrading to Kotlin 1.5, see https://youtrack.jetbrains.com/issue/KT-44594
		if (KotlinDetector.isKotlinReflectPresent() && !NativeDetector.inNativeImage()) {
			addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
		}
        //看到有两个具体的实现,会依次调用Discoverer来获取某个方法的参数名
        //StandardReflectionParameterNameDiscoverer:它使用JDK 8的反射功能来内省参数名(基于“-parameters”编译器标志)。
		addDiscoverer(new StandardReflectionParameterNameDiscoverer());
        //LocalVariableTableParameterNameDiscoverer:使用ObjectWeb的ASM库来分析类文件。
        //解析字节码文件,使用方法属性中的LocalVariableTable信息来发现参数名称。
		addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
	}

}

优先利用反射去拿,如果运行环境是jdk1.7或者jdk1.8没有设置编译参数,有可能拿不到,再利用字节码中的本地变量表去拿。
小仙女讲JVM(4)—类文件结构

2. 处理Optional类型的依赖注入

org.springframework.beans.factory.support.DefaultListableBeanFactory#createOptionalDependency

private Optional<?> createOptionalDependency(
        DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {

    DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
        @Override
        public boolean isRequired() {
            return false;
        }
        @Override
        public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
            return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :
                    super.resolveCandidate(beanName, requiredType, beanFactory));
        }
    };
    //4.2 核心是doResolveDependency,真正开始解析依赖项
    Object result = doResolveDependency(descriptorToUse, beanName, null, null);
    //最终返回结果如果不是Optional,会用Optional再包装一下
    return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
}

3. 处理ObjectFactory和ObjectProvider类型的依赖注入

org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider#getObject()

public Object getObject() throws BeansException {
    if (this.optional) {
        //2. 处理Option类型的依赖注入
        return createOptionalDependency(this.descriptor, this.beanName);
    }
    else {
        //4.2 核心还是doResolveDependency,真正开始解析依赖项
        Object result = doResolveDependency(this.descriptor, this.beanName, null, null);
        if (result == null) {
            throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
        }
        return result;
    }
}

延迟依赖查找功能,只有当使用者调用ObjectProvider#getObject()方法时,才会通过依赖查找的方式获取对应的Bean

Bean的延迟依赖查找功能,ObjectFactory 和 ObjectProvider

4. 查找具体的依赖注入对象

4.1 判断是否是懒注入

@Lazy注解可以加在类上、字段上,也可以加在方法入参上
在这里插入图片描述

//4.1 判断是否是懒注入
//	在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
        descriptor, requestingBeanName);
if (result == null) {
    //4.2 真正开始解析依赖项,核心是doResolveDependency
    //	descriptor表示某个字段属性、或某个方法上的某个入参
    //	requestingBeanName表示当前正在进行依赖注入的Bean
    result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;

getAutowireCandidateResolver默认返回的是ContextAnnotationAutowireCandidateResolver
org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary

//判断是不是懒注入(@Autowired + @Lazy),如果是,则会在注入时先生成一个代理对象注入给属性
//所以懒注入并不代表属性为null
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
    //不是懒注入,则返回null,否则创建一个代理对象
    return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}

判断是否是懒注入

判断是否有@Lazy注解,且value是true:
org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#isLazy

protected boolean isLazy(DependencyDescriptor descriptor) {
    //1.参数级别获取注解
    //获取与被包装的字段或方法/构造函数参数关联的注解
    for (Annotation ann : descriptor.getAnnotations()) {
        Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
        if (lazy != null && lazy.value()) {
            return true;
        }
    }
	//2.方法级别获取注解
	//判断方法/构造函数上的注解
    MethodParameter methodParam = descriptor.getMethodParameter();
    if (methodParam != null) {
        Method method = methodParam.getMethod();
        if (method == null || void.class == method.getReturnType()) {
            //该方法公开在方法/构造函数本身上声明的注解(即在方法/构造函数级别,而不是在参数级别)。
            Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
            if (lazy != null && lazy.value()) {
                return true;
            }
        }
    }
    return false;
}

注意虽然MethodParameter代表的是方法上的某一个参数,但是methodParam.getAnnotatedElement()返回的是方法上的注解,非参数级别的。

创建懒注入的代理对象

动态代理,不是本节重点,以后讲SpringAOP的时候会细说。
只要知道这里会生成一个代理对象即可,当真正执行方法的时候才会去解析依赖项。

org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy

protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
    BeanFactory beanFactory = getBeanFactory();
    Assert.state(beanFactory instanceof DefaultListableBeanFactory,
            "BeanFactory needs to be a DefaultListableBeanFactory");
    final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;

    TargetSource ts = new TargetSource() {
        //被代理对象类型
        @Override
        public Class<?> getTargetClass() {
            return descriptor.getDependencyType();
        }
        //是否是静态的:true,则每次调用getTarget()返回的都是相同的对象
        @Override
        public boolean isStatic() {
            return false;
        }
        //获取被代理对象
        @Override
        public Object getTarget() {
            Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
            //4.2 核心还是doResolveDependency,真正开始解析依赖项
            Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
            if (target == null) {...}
            if (autowiredBeanNames != null) {...}
            return target;
        }
        @Override
        public void releaseTarget(Object target) {...}
    };

    ProxyFactory pf = new ProxyFactory();
    pf.setTargetSource(ts);
    Class<?> dependencyType = descriptor.getDependencyType();
    if (dependencyType.isInterface()) {
        pf.addInterface(dependencyType);
    }
    //生成一个代理对象
    return pf.getProxy(dlbf.getBeanClassLoader());
}

在这里插入图片描述

一开始只会赋值一个代理对象,当真正使用这个对象执行其方法的时候,作为一个代理对象,最终肯定会去拿到被代理对象,执行被代理对象对应的方法,所以就会调用org.springframework.aop.TargetSource#getTarget这个方法拿到被代理对象,而在这个方法中才会真正解析依赖项:
在这里插入图片描述

4.2 真正开始解析依赖项(最核心方法)

篇幅过长,下一节讲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

犬豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值