咱们常常注入的形式都是相似这样子的

@Servicepublic class HelloService {    @Autowired    private BeanFactory beanFactory;    @Autowired    public HelloService(ApplicationContext applicationContext) {    }    @Autowired    public void setEnvironment(Environment environment) {       }}

不论是构造函数注入还是属性注入、咱们都能够称为显式注入。

咱们再来看看一个咱们罕用的注解 @Bean

public @interface Bean {   @AliasFor("name")   String[] value() default {};   @AliasFor("value")   String[] name() default {};   @Deprecated   Autowire autowire() default Autowire.NO;   boolean autowireCandidate() default true;   String initMethod() default "";   String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;}

咱们关注的属性 autowire 尽管标注曾经被废除了、然而不障碍咱们理解一下它。

  • NO 默认值、代表不会主动注入
  • BY_NAME 、通过 beanName 进行主动注入
  • BY_TYPE、通过参数的类型进行主动注入

Autowire.NO

@Configurationpublic class Config {    @Bean(autowire = Autowire.NO)    public HelloService helloService() {        return new HelloService();    }}public class HelloService {    public void setEnvironment(Environment environment) {        System.out.println("invoke " + environment);    }}

咱们应用默认的配置、不对 HelloService 进行主动注入、毫无疑问、setEnvironment 是不会被 Spring 框架调起的。

Autowire.BY_NAME

咱们将下面的代码改为

@Bean(autowire = Autowire.BY_NAME)

会发现 setEnvironment 被调起、并且参数 environment 就是 Spring 中的 StandardServletEnvironment

这一步如果对 Spring 获取 bean 流程有印象的、Spring 获取单例流程(三) 能够得悉其在 AbstractAutowireCapableBeanFactory#populateBean 中被调用

if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);   // 将主动注入的值放入到 newPvs 中   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;}..........if (pvs != null) {            applyPropertyValues(beanName, mbd, bw, pvs);}

对应的代码也是十分的简略的

protected void autowireByName(      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {      // 依据 setter 办法获取须要次要的 beanName、解释 setter 办法   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);   for (String propertyName : propertyNames) {     // 如果不在 BeanFactory 中、间接疏忽、不会报错      if (containsBean(propertyName)) {         Object bean = getBean(propertyName);        // 退出到 pvs 中         pvs.add(propertyName, bean);         registerDependentBean(propertyName, beanName);                }      else {        // 如果不存在该 bean、不报错、间接疏忽      }   }}

能够看到 BY_NAME 的形式、是通过解释 setter 办法名来获取须要注入的 beanName。如果 beanName 不存在 BeanFactory 中、间接疏忽、相似于 @Autowired(required=false) 。不是强制性注入

然而你的办法名称必须是 setXxx 结尾、合乎肯定的命名规定、跟 BeanInfo 的规定相似(Java 内省)、然而比它宽松、这里不限定返回值肯定要是 void

Autowire.BY_TYPE

autowireByType

protected void autowireByType(      String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {       .......   Set<String> autowiredBeanNames = new LinkedHashSet<>(4);   String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);  // 遍历 setter 办法解释获取其属性名   for (String propertyName : propertyNames) {      try {         PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);                  if (Object.class != pd.getPropertyType()) {            MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);            boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);           // AutowireByTypeDependencyDescriptor 这个类很要害、它返回的 getDependencyName 始终为 null            DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);            Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);            if (autowiredArgument != null) {               pvs.add(propertyName, autowiredArgument);            }            for (String autowiredBeanName : autowiredBeanNames) {               registerDependentBean(autowiredBeanName, beanName);            }            autowiredBeanNames.clear();         }      }      catch (BeansException ex) {         throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);      }   }}

跟 BY_NAME 很类似的、那如果我主动注入的对象不存在 BeanFactory 中、是不是也不会抛异样呢?答案是的、这里次要是因为应用了这个类 AutowireByTypeDependencyDescriptor

private static class AutowireByTypeDependencyDescriptor extends DependencyDescriptor {   public AutowireByTypeDependencyDescriptor(MethodParameter methodParameter, boolean eager) {      super(methodParameter, false, eager);   }   @Override   public String getDependencyName() {      return null;   }}// 父类public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {        super(methodParameter);      .......        this.required = required;        .......    }

第一个关键点就是 requied 为 false、当所依赖的 bean 不存在 BeanFactory 的时候、false 则不会抛异样。

第二个关键点则是、如果存在两个雷同的 bean 、如果这两个 bean 都没有申明 Primary 或者 PriorityOrderd 的话、那么它还是会抛出异样的、而不会依据 beanName 去匹配筛选出适合的 bean、因为 getDependencyName 始终返回 null

这种状况跟 @Autowired 的形式不太一样、因为 BY_TYPE 的形式是不依赖 beanName的

@Nullableprotected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {   Class<?> requiredType = descriptor.getDependencyType();   String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);   if (primaryCandidate != null) {      return primaryCandidate;   }   String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);   if (priorityCandidate != null) {      return priorityCandidate;   }   // Fallback   for (Map.Entry<String, Object> entry : candidates.entrySet()) {      String candidateName = entry.getKey();      Object beanInstance = entry.getValue();     // resolvableDependencies       if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||          // BY_TYPE matchesBeanName 返回 false            matchesBeanName(candidateName, descriptor.getDependencyName())) {         return candidateName;      }   }   return null;}

resolvableDependencies 中寄存 key-value 的状况

总结

主动注入绝对显式注入、在理论场景中的确用得比拟少、然而理解其过程还是会让你播种到一些相干的常识和流程

给本人和所有看到这篇文章的同学加油~!!

微信公众号:CoderLi