关于java:Spring是如何自动注入多类型

35次阅读

共计 9437 个字符,预计需要花费 24 分钟才能阅读完成。

时常有个小问题围绕着我,Spring 是如何给字段字符装盘,为何反对 Collection、List、Map、String 等这么多类型的呢?在 Spring 注入的过程中,有没有什么小技巧值得咱们学习呢?带着这个纳闷,咱们来一探到底。

本文基于 SpringBoot V2.5.6, Spring V5.3.12。不同版本可能会有不同,请留神哈

想要弄懂下面的问题,有一个小小的要求,那就是要弄懂 SpringBean 的生命周期(如和 Get 一个 Bean),当然,咱们也能够带着这个纳闷,一起去代码中寻找。

代码搜寻
1.1 入口剖析
要开始摸索代码,那咱们当然须要寻找一个入口,那咱们从哪开始呢?当然就从启动函数开始啦。启动代码如下:

public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringTestApplication.class, args);
// 从容器中获取一个 bean
context.getBean(“fattyca1Bean”);
}

咱们在执行 SpringApplication.run 后能够失去一个 ApplicationContext,那么咱们就能够 GetBean 了,能够接着往下看 GetBean。

1.2 深刻其中
1.2.1
咱们从 getBean 点进去,进入的是 org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.String),点进去代码如下:

@Override
public Object getBean(String name) throws BeansException {
    // 获取以后的 BeanFactory,而后在 getBean
    return getBeanFactory().getBean(name);
}

这里就是通过获取以后的 BeanFactory,而后在 getBean。这里咱们对 getBeanFactory()有一点点趣味,为什么有趣味呢?那就是咱们想搞明确以后的 BeanFactory 是什么。话不多说,咱们间接点进去。

1.2.2
点进去的时候发现 org.springframework.context.support.AbstractApplicationContext#getBeanFactory()有两个实现类,别离是:

org.springframework.context.support.AbstractRefreshableApplicationContext
org.springframework.context.support.GenericApplicationContext
咱们进入类中查看是如何实现 BeanFactory 的、

org.springframework.context.support.AbstractRefreshableApplicationContext
查看代码,有一个办法。如下:

protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

org.springframework.context.support.GenericApplicationContext
查看代码,构造函数:

public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}

咱们能够看到一个独特特点,最初实现的 BeanFactory 都是是 org.springframework.beans.factory.support.DefaultListableBeanFactory,好了,到当初咱们晓得了,getBean 最初都是通过 org.springframework.beans.factory.support.DefaultListableBeanFactory 来实现的。

不过呢,又一个疑难来了。纳尼?ApplicationContext 的 GetBean 居然是通过组合 org.springframework.beans.factory.support.DefaultListableBeanFactory 来实现的,那 ApplicationContext 和 org.springframework.beans.factory.support.DefaultListableBeanFactory 有啥关系呢?又有啥区别呢?这个问题留在这,哈哈。

1.2.3
按着 Spring 的老规矩,xxx()是办法,doXxx()是真正实现的办法。咱们一路点进去,从 getBean -> doGetBean -> createBean -> doCreateBean();

在 doCreateBean 有如下代码:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){

    ... 略
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
  // 填充 Bean
        populateBean(beanName, mbd, instanceWrapper);
    }
    ... 略

}

有一个 populateBean 办法,相熟 spring 生命周期的同学晓得,这里是在 Bean 初始化实现后,对 Bean 属性值就行填充的中央,当然,咱们从办法正文也能够看进去哈。java 培训

Populate the bean instance in the given BeanWrapper with the property values from the bean definition.

1.2.4
进去到 populateBean 办法外部。代码如下:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

  ... 略
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    ... 略

}

如咱们所愿,在这里咱们看到了两个全副大写的 AUTOWIRE_BY_NAME&AUTOWIRE_BY_TYPE,这两个不就是主动注入的类型吗?看来是要到关键点了。那就点进去看看呗

1.2.5
1.2.5.1 autowireByName
// Fill in any missing property values with references to other beans in this factory if autowire is set to “byName”.
protected void autowireByName(

        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取属性的名称
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
  // 是否是 bean
        if (containsBean(propertyName)) {Object bean = getBean(propertyName);
    // 将 propertyName 和 Bean 对应起来
            pvs.add(propertyName, bean);
    // 将属性和 Bean 关联起来
            registerDependentBean(propertyName, beanName);
        }
    }

}

在办法中咱们看到了是名称注入是通过 geatBean 获取关联 bean 来注入的。点进去办法发现,是个套娃。getBean 代码如下:

@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

这兜兜转转不又回到原点了吗?那咱们就去另外一个办法看起来咯

1.2.5.2 autowireByType
进入放大,代码如下:

protected void autowireByType(

        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    ... 略
    Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
    // 反射属性形容
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // Don't try autowiring by type for type Object: never makes sense,
            // even if it technically is a unsatisfied, non-simple property.
            if (Object.class != pd.getPropertyType()) {
      // 获取属性的 setter 办法
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // Do not allow eager init for type matching in case of a prioritized post-processor.
      // 是否饥饿?判断是否懒加载
                boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
      // 属性形容
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
      // 解析依赖(要害)
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
        // 关联属性和对应 Bean
                    registerDependentBean(autowiredBeanName, beanName);
                }
                autowiredBeanNames.clear();}
        }
    ... 略
    }
}

这里的代码就比拟清晰了,Spring 做了好几步操作,别离是:

1.2.5.1.1 反射获取属性
咱们通过名称也能够看进去获取了 PropertyDescriptor,这个类次要是获取属性的 Get 和 Setter 办法(writeMethod 和 readMethod),而后通过办法参数构建了一个 DependencyDescriptor,记录一些参数信息,具体的能够看一下看。

1.2.5.1.2 解析依赖(要害)
咱们进到具体的办法外面。代码如下:

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 是不是 Optional 类
    if (Optional.class == descriptor.getDependencyType()) {return createOptionalDependency(descriptor, requestingBeanName);
    }
// 是不是 ObjectFacotry,ObjectProvider
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    else if (javaxInjectProviderClass == descriptor.getDependencyType()) {return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    else {Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);
        if (result == null) {
    // 真正的解析
            result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
        }
        return result;
    }

}

在这个办法里判断了好几种类型。Optional、ObjectFactory、ObjectProvider、Java.Inject.Provider、一般类等。不同的类有不同的解决形式。当然,依照老规矩,咱们还是进入到 doResolveDependency 是真正具体的解析操作,咱们进去瞧一瞧。

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,

        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    try {
        ... 略

        Class<?> type = descriptor.getDependencyType();
  // 主动注入的解析器获取值,默认实现,返回值为 null
        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());
            try {
      // 将类型转换对应的类型的值
                return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
            }
            catch (UnsupportedOperationException ex) {
                // A custom TypeConverter which does not support TypeDescriptor resolution...
                return (descriptor.getField() != null ?
                        converter.convertIfNecessary(value, type, descriptor.getField()) :
                        converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
            }
        }
        // 多依赖 Bean
        Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
        if (multipleBeans != null) {return multipleBeans;}
        ... 略

}

看代码,首先是通过 getAutowireCandidateResolver().getSuggestedValue(descriptor); 获取了一波值,然而跟进一下代码,getAutowireCandidateResolver()的默认实现是:org.springframework.beans.factory.support.SimpleAutowireCandidateResolver,其 getSuggestedValue 的返回值为 null。

public Object getSuggestedValue(DependencyDescriptor descriptor) {
return null;
}

,接着咱们往下看,到了 resolveMultipleBeans,这个一看名字可能就是解析有多个 Bean 的办法,有点那味了,多个 Bean 解析就有可能使咱们要找的,咱们接着看。

private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,

        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {Class<?> type = descriptor.getDependencyType();

    if (descriptor instanceof StreamDependencyDescriptor) {... 略}
    else if (type.isArray()) {... 略}
    else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {... 略}
    else if (Map.class == type) {... 略}
    else {return null;}
}

一点进来,好家伙,这代码,if…else if …else,在看看这判断,不就是咱们心心念念的 Collection、Map…类型注入的吗?那咱们找一个具体的办法看看呗,比如说 Map。代码如下:

else if (Map.class == type) {

      // 获取泛型类型
        ResolvableType mapType = descriptor.getResolvableType().asMap();
        Class<?> keyType = mapType.resolveGeneric(0);
      // 判断 key 的类型是不是 String
        if (String.class != keyType) {return null;}
        Class<?> valueType = mapType.resolveGeneric(1);
        if (valueType == null) {return null;}
      // 找到符合条件的 Bean,并返回 Map<BeanName,Bean> 类型
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
                new MultiElementDescriptor(descriptor));
        if (matchingBeans.isEmpty()) {return null;}
        if (autowiredBeanNames != null) {autowiredBeanNames.addAll(matchingBeans.keySet());
        }
      // 返回后果
        return matchingBeans;

}

通过反射获取须要注入类型的泛型(ResolvableType 是 Spring 中提供反射的,正文上有应用阐明,能够自行看一下)。而后判断 key 的类型。这里有一个小问题,如果 KeyType 不是 String 类型的,将会间接返回 Null。这个是咱们应用注册 Bean 的时候须要的留神点。

而后是判断 valueType,接着应用 findAutowireCandidates 办法找到 Class 的所有 Bean 类型,并且间接封装成了 Map 类型的构造,而后间接返回了。

至此咱们晓得了,在咱们主动拆卸 Spring 帮咱们做了太多的事件了,设计的 Spring 的初始化,在注入时主动帮忙组装成 Map、List、Array 等,Spring 还是仔细啊。

正文完
 0