GVKun编程网logo

【04】spring源码解析之Autowired属性注入(spring属性注入原理)

9

这篇文章主要围绕【04】spring源码解析之Autowired属性注入和spring属性注入原理展开,旨在为您提供一份详细的参考资料。我们将全面介绍【04】spring源码解析之Autowired属

这篇文章主要围绕【04】spring源码解析之Autowired属性注入spring属性注入原理展开,旨在为您提供一份详细的参考资料。我们将全面介绍【04】spring源码解析之Autowired属性注入的优缺点,解答spring属性注入原理的相关问题,同时也会为您带来Autowired属性为null-Spring Boot配置、Autowired的注入过程源码解析、Spring @Autowired 注入为 null、Spring boot 下 @Autowired 注入为 NULL 的问题的实用方法。

本文目录一览:

【04】spring源码解析之Autowired属性注入(spring属性注入原理)

【04】spring源码解析之Autowired属性注入(spring属性注入原理)

    在文章【03】spring源码解析之配置文件context:component-scan 解析流程中分析了spring是如何解析配置文件的,spring根据配置文件中配置的bean扫描路径(或者是xml文件中配置的bean)找到这些需要被spring管理的bean,找到这些bean以后,并没有组织这些bean之间的关系,只是返回了BeanDefinitions,也就是描述这些Bean性质的BeanDefinition列表,对于一个Bean作为另外一个Bean的属性是如何注入的则在其他的流程中进行组装。下图的时序图粗略的描述了一下整个注入的过程



从上图可以看出,Bean组装的入口是AbstractApplicationContext 的registerBeanPostProcessors方法,这个方法接受一个ConfigurableListableBeanFactory作为参数,对于ConfigurableListableBeanFactory类的层级关系如下类图:


从关系图中可以看出,ConfigurableListableBeanFactory继承ListableBeanFactory,ListableBeanFactory持有BeanDefinition对象,也就是说ConfigurableListableBeanFactory在解析的时候持有了BeanDefinitions这些对象。

 

从图时序图1中可以看出,Bean的创建关键代码是AbstractAutowireCapableBeanFactory的doCreateBean方法,而进行属性注入的是populateBean方法,这个方法声明如下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args);


它接收三个参数,第一个参数是bean的名称,第二个是对这个类的描述对象,第三个参数是创建这个bean时候的构造函数所需要的参数。返回值是一个创建完成的对象。


而创建对象的过程主要是分为两个步骤

1、创建对象

2、注入属性

创建对象是由createBeanInstance方法完成的,注入属性是populateBean方法完成的

一、对象创建

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 确保这个类是存在的,并且通过mbd反向查找到类
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   //校验类是否为空,是否public的,是否可访问的,如果不满足以上条件,则抛出异常
   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn''t public, and non-public access not allowed: " + beanClass.getName());
   }

   .....

   //实例化Bean,对具有没有参数的构造函数进行实例化,registerCustomEditors
    //调用过程为instantiateBean->registerCustomEditors->BeanUtils.instantiateClass(editorClass);  

   return instantiateBean(beanName, mbd);
}

//把instanceWrapper 对象转化为真正实例化后的对象
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);



二、属性注入

1、查找Bean中的注解

入口为applyMergedBeanDefinitionPostProcessors,真正的查找方法为AutowiredAnnotationBeanProcessor中的findAutowiredMetadata方法,然后调用bulidResourceMetadate方法,解析class文件中的注解文件,

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
		Class<?> targetClass = clazz;

		do {
			final LinkedList<InjectionMetadata.InjectedElement> currElements =
					new LinkedList<InjectionMetadata.InjectedElement>();
			
			//通过反射的方法,找到class的所有属性,然后回调FieldCallback方法,在这个方法中过滤被Autowired注解所修饰
			的属性,并且校验属性是不是static的,如果是的话,则记录warin级别的日志,Autowired不支持修饰static变量
			然后把符合条件的属性集合放入到currElements集合中以待后续处理
			ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
				@Override
				public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
					AnnotationAttributes ann = findAutowiredAnnotation(field);
					if (ann != null) {
						if (Modifier.isStatic(field.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static fields: " + field);
							}
							return;
						}
						boolean required = determineRequiredStatus(ann);
						currElements.add(new AutowiredFieldElement(field, required));
					}
				}
			});


			//和doWithLocalFields采取相同的方式,处理相关方法
			ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
				@Override
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
					Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
					if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
						return;
					}
					AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
					if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
						if (Modifier.isStatic(method.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static methods: " + method);
							}
							return;
						}
						if (method.getParameterTypes().length == 0) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation should be used on methods with parameters: " + method);
							}
						}
						boolean required = determineRequiredStatus(ann);
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new AutowiredMethodElement(method, required, pd));
					}
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return new InjectionMetadata(clazz, elements);
	}



2、属性注解检验

static修饰的属性,不允许使用Autowired注解



3、属性注入

数据准备完成以后,通过调用populateBean方法,真正的对需要注入的属性进行注入

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
		PropertyValues pvs = mbd.getPropertyValues();

		if (bw == null) {
			if (!pvs.isEmpty()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}

		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}

//mbd.getResolvedAutowireMode() 根据自动注入策略,获取注入策略的值,默认值是0
RootBeanDefinition.AUTOWIRE_BY_NAME的值是1
RootBeanDefinition.AUTOWIRE_BY_TYPE的值是2

		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

			// Add property values based on autowire by name if applicable.
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}

			// Add property values based on autowire by type if applicable.
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}

			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

		if (hasInstAwareBpps || needsDepCheck) {
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}

		applyPropertyValues(beanName, mbd, bw, pvs);
	}
实例化属性,注入的代码
	
	DefaultListableBeanFactory.java
	
	public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
			Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

		Class<?> type = descriptor.getDependencyType();
		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()));
		}

		if (type.isArray()) {
			Class<?> componentType = type.getComponentType();
			DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
			targetDesc.increaseNestingLevel();
			
			
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, targetDesc);
			//注入其依赖的属性,实例化属性,这样就能达到一个循环,把所有的依赖从最里层逐步剥离出来进行实例化,然后注入
			
			if (matchingBeans.isEmpty()) {
				if (descriptor.isRequired()) {
					raiseNoSuchBeanDefinitionException(componentType, "array of " + componentType.getName(), descriptor);
				}
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof Object[]) {
				Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
			Class<?> elementType = descriptor.getCollectionType();
			if (elementType == null) {
				if (descriptor.isRequired()) {
					throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
				}
				return null;
			}
			DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
			targetDesc.increaseNestingLevel();
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType, targetDesc);
			if (matchingBeans.isEmpty()) {
				if (descriptor.isRequired()) {
					raiseNoSuchBeanDefinitionException(elementType, "collection of " + elementType.getName(), descriptor);
				}
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (getDependencyComparator() != null && result instanceof List) {
				Collections.sort((List<?>) result, adaptDependencyComparator(matchingBeans));
			}
			return result;
		}
		else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
			Class<?> keyType = descriptor.getMapKeyType();
			if (String.class != keyType) {
				if (descriptor.isRequired()) {
					throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
							"] must be [java.lang.String]");
				}
				return null;
			}
			Class<?> valueType = descriptor.getMapValueType();
			if (valueType == null) {
				if (descriptor.isRequired()) {
					throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
				}
				return null;
			}
			DependencyDescriptor targetDesc = new DependencyDescriptor(descriptor);
			targetDesc.increaseNestingLevel();
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, targetDesc);
			if (matchingBeans.isEmpty()) {
				if (descriptor.isRequired()) {
					raiseNoSuchBeanDefinitionException(valueType, "map with value type " + valueType.getName(), descriptor);
				}
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			return matchingBeans;
		}
		else {
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				if (descriptor.isRequired()) {
					raiseNoSuchBeanDefinitionException(type, "", descriptor);
					
					//如果没有找到属性所要注入的实例,则会抛出我们非常常见的一个异常 ^_^
				//expected at least 1 bean which qualifies as autowire candidate for this dependency.  Dependency annotations:xxxx
				}
				return null;
			}
			if (matchingBeans.size() > 1) {
				String primaryBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (primaryBeanName == null) {
					throw new NoUniqueBeanDefinitionException(type, matchingBeans.keySet());
					//针对一个属性,找到了多个实例,抛出实例重复异常
					//expected at least 1 bean which qualifies as autowire candidate for this dependency.
				}
				if (autowiredBeanNames != null) {
					autowiredBeanNames.add(primaryBeanName);
				}
				return matchingBeans.get(primaryBeanName);
			}
			//确保有且只能找到一个
			// We have exactly one match.
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(entry.getKey());
			}
			return entry.getValue();
		}
	}


最让人兴奋的地方来了,对象属性值注入的最根本的代码


AutowiredAnnotationBeanPostProcessor的内部类AutowiredFieldElement中的inject方法

 @Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
                ...........
		...............
		if (value != null) {
					ReflectionUtils.makeAccessible(field);
					field.set(bean, value);
					//对属性注入值的最根本的代码
					//注入属性^_^ ^_^ ^_^^_^^_^^_^^_^^_^^_^ 
					//我得意的笑啊,终于找到这家伙了
					
				}
			}
			catch (Throwable ex) {
				throw new BeanCreationException("Could not autowire field: " + field, ex);
			}
		}
	}






Autowired属性为null-Spring Boot配置

Autowired属性为null-Spring Boot配置

我在自动装配的属性中陷入空值。我希望可以得到一些帮助。

我们正在使用项目Spring-boot版本0.5.0.M6。

带有bean的四个配置文件在一个软件包中,并按“区域”排序:

  1. 数据源配置
  2. 全局方法安全性配置(因为我们使用Spring-ACL)
  3. MVC配置
  4. Spring Security配置

引导所有内容的主要方法在以下文件中:

@EnableAspectJAutoProxy@EnableSpringConfigured@EnableAutoConfiguration(exclude = {    DataSourceTransactionManagerAutoConfiguration.class,    HibernateJpaAutoConfiguration.class,    JpaRepositoriesAutoConfiguration.class,    SecurityAutoConfiguration.class,    ThymeleafAutoConfiguration.class,    ErrorMvcAutoConfiguration.class,    MessageSourceAutoConfiguration.class,    WebSocketAutoConfiguration.class})@Configuration@ComponentScanpublic class IntegrationsImcApplication {    public static void main(String[] args) throws Exception {        ApplicationContext ctx = SpringApplication.run(                IntegrationsImcApplication.c lass, args);    }}

包含数据源配置bean的第一个文件如下(我省略了一些方法主体部分以使其更具可读性):

@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)@Configurationpublic class RootDataSourceConfig         extends TomcatDataSourceConfiguration         implements TransactionManagementConfigurer {    @Override    public DataSource dataSource() {        return jpaDataSource();    }    public PlatformTransactionManager annotationDrivenTransactionManager() {        return jpaTransactionManager();    }    @Bean    public HibernateExceptionTranslator hibernateExceptionTranslator() {        return new HibernateExceptionTranslator();    }    @Bean(name="jpaDataSource")    public DataSource jpaDataSource() {......}    @Bean(name = {"transactionManager","txMgr"})    public JpaTransactionManager jpaTransactionManager() {......}    @Bean(name = "entityManagerFactory")    public EntityManagerFactory jpaEmf() {......}}

这是下一个配置文件,该文件取决于上方的数据源。它有大约20个与ACL配置相关的bean,但是在使用数据源的firsts bean上失败了:

@EnableGlobalMethodSecurity(prePostEnabled = true)@Configurationpublic class RootGlobalMethodSecurityConfig         extends GlobalMethodSecurityConfiguration         implements Ordered {    @Autowired    public DataSource dataSource;    @Override    public int getOrder() {        return IntegrationsImcApplication.ROOT_METHOD_SECURITY_CO NFIG_ORDER;    }    @Bean    public MutableAclService aclService()             throws CacheException, IOException {        MutableJdbcAclService aclService = new MutableJdbcAclService(                dataSource, aclLookupStrategy(), aclCache());        aclService.setClassIdentityQuery("SELECT @@IDENTITY");        aclService.setSidIdentityQuery("SELECT @@IDENTITY");        return aclService;    }    ...................................}

基本上,调用aclService()会引发错误,因为它dataSource为null。我们已经尝试通过实现Ordered接口来订购配置文件。我们也尝试使用,@AutoConfigureAfter(RootDataSourceConfig.class)但这也无济于事。除了尝试做之外@AutowiredDataSource我们还尝试注入RootDataSourceConfig类本身,但是它仍然为null。我们尝试在这些bean上使用@DependsOn@Ordered,但再次没有成功。似乎没有任何东西可以注入此配置。

启动时的控制台输出将按我们想要的顺序列出bean,其中数据源是第一个。我们为此受到了很大的阻碍。

我们在这里所做的任何奇怪或独特的事情都不起作用吗?如果这是设计的,那么我们如何才能不同地注入数据​​源?

回购:github

答案1

小编典典

依赖于a的bean的较早初始化DataSource绝对是问题所在。根本原因与Spring
Boot或自动配置无关,而是通过一个由包裹您的业务bean的方面来应用简单的老式鸡和蛋方法安全性BeanPostProcessor。一个bean只能发表一些初始化处理
非常
早。在这种情况下,进行DataSource注入还为时过早(实际上,实例化@Configuration需要的类DataSource为时过早,无法正确包装在@Configuration加工机械中,因此无法自动接线)。我的建议(只会使您与缺少相同之处AuthenticationManager)是将声明GlobalMethodSecurityConfiguration为嵌套类,而不是将其声明为嵌套类。DataSource
在以下位置需要:

@EnableGlobalMethodSecurity(prePostEnabled = true)@Configurationprotected static class ActualMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {    @Autowired    @Qualifier("aclDaoAuthenticationProvider")    private AuthenticationProvider aclDaoAuthenticationProvider;    @Autowired    @Qualifier("aclAnonymousAuthenticationProvider")    private AnonymousAuthenticationProvider aclAnonymousAuthenticationProvider;    @Autowired    @Qualifier("aclExpressionHandler")    private MethodSecurityExpressionHandler aclExpressionHandler;    @Override    protected void configure(AuthenticationManagerBuilder auth)            throws Exception {        auth.authenticationProvider(aclDaoAuthenticationProvider);        auth.authenticationProvider(aclAnonymousAuthenticationProvider);    }    @Override    public MethodSecurityExpressionHandler createExpressionHandler() {        return aclExpressionHandler;    }

}

也就是说RootMethodSecurityConfiguration,将其粘贴到并@EnableGlobalMethodSecurity从该类中删除注释。

Autowired的注入过程源码解析

Autowired的注入过程源码解析

一、案例场景

在使用 @Autowired 时,你或多或少都会遇过类似的错误:

required a single bean, but 2 were found

为了重现这个错误,我们可以先写一个案例来模拟下。

@RestController
@Slf4j
@Validated
public class StudentController {
    @Autowired
    DataService dataService;
    @RequestMapping(path = "students/{id}", method = RequestMethod.DELETE)
    public void deleteStudent(@PathVariable("id") @Range(min = 1,max = 100) int id) {
        dataService.deleteStudent(id);
    }
}

其中 DataService 是一个接口,其实现依托于 Oracle,代码示意如下:

public interface DataService {
    void deleteStudent(int id);
} 
@Repository
@Slf4j
public class OracleDataService implements DataService {
    @Override
    public void deleteStudent(int id) {
        log.info("delete student info maintained by oracle");
    }
}

截止目前,运行并测试程序是毫无问题的。直到某天,我们接到节约成本的需求,希望把一些部分非核心的业务从 Oracle 迁移到社区版 Cassandra,所以我们自然会先添加上一个新的 DataService 实现,代码如下:

@Repository
@Slf4j
public class CassandraDataService implements DataService{
    @Override
    public void deleteStudent(int id) {
        log.info("delete student info maintained by cassandra");
    }
}

此时,程序就已经无法启动了,报错如下:

image-20220719210803377

二、案例解析

首先,我们先来了解下 @Autowired 发生的位置和核心过程。当一个 Bean 被构建时,核心包括两个基本步骤:

  • 执行 AbstractAutowireCapableBeanFactory#createBeanInstance 方法:通过构造器反射构造出这个 Bean,在此案例中相当于构建出 StudentController 的实例;
  • 执行 AbstractAutowireCapableBeanFactory#populateBean 方法:填充(即设置)这个 Bean,在本案例中,相当于设置 StudentController 实例中被 @Autowired 标记的 dataService 属性成员。

在步骤 2 中,“填充”过程的关键就是执行各种 BeanPostProcessor 处理器,关键代码如下:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  //省略非关键代码
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
      //省略非关键代码
    }
  }
}

在上述代码执行过程中,因为 StudentController 含有标记为 Autowired 的成员属性 dataService,所以会使用到AutowiredAnnotationBeanPostProcessor(BeanPostProcessor 中的一种)来完成“装配”过程:找出合适的 DataService 的 bean 并设置给StudentController#dataService。如果深究这个装配过程,又可以细分为两个步骤:

  • 寻找出所有需要依赖注入的字段和方法,参考 AutowiredAnnotationBeanPostProcessor#postProcessProperties 中的代码行:
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
  • 根据依赖信息寻找出依赖并完成注入,以字段注入为例,参考 AutowiredFieldElement#inject 方法:
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    //省略非关键代码
    DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
    //寻找“依赖”,desc为"dataService"的DependencyDescriptor
    value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    //省略非关键代码
    if (value != null) {
        ReflectionUtils.makeAccessible(field);
        //装配“依赖”
        field.set(bean, value);
    }
}

当我们根据 DataService 这个类型来找出依赖时,我们会找出 2 个依赖,分别为 CassandraDataService 和 OracleDataService。在这样的情况下,如果同时满足以下两个条件则会抛出本案例的错误:

  • 调用 determineAutowireCandidate 方法来选出优先级最高的依赖,但是发现并没有优先级可依据。具体选择过程可参考DefaultListableBeanFactory#determineAutowireCandidate。

优先级的决策是先根据 @Primary 来决策,其次是 @Priority 决策,最后是根据 Bean 名字的严格匹配来决策。如果这些帮助决策优先级的注解都没有被使用,名字也不精确匹配,则返回 null,告知无法决策出哪种最合适。

  • @Autowired 要求是必须注入的(即 required 保持默认值为 true),或者注解的属性类型并不是可以接受多个 Bean 的类型,例如数组、Map、集合。这点可以参考 DefaultListableBeanFactory#indicatesMultipleBeans 的实现。

三、问题修正

第一,我们可以通过使用标记 @Primary 的方式来让被标记的候选者有更高优先级,从而避免报错。

@Repository
@Primary
@Slf4j
public class OracleDataService implements DataService{
  //省略非关键代码
}

但是这种方式并不一定符合业务需求。

第二,我们可以使用下面的方式去修改:

@Autowired
DataService oracleDataService;

将属性名和 Bean 名字精确匹配,这样就可以让注入选择不犯难:需要 Oracle 时指定属性名为 oracleDataService,需要 Cassandra 时则指定属性名为 cassandraDataService。

第三,还可以采用 @Qualifier 来显式指定引用的是那种服务,例如采用下面的方式:

@Autowired
@Qualifier("cassandraDataService")
DataService dataService;

这种方式之所以能解决问题,在于它能让寻找出的 Bean 只有一个(即精确匹配),所以压根不会出现后面的决策过程,可以参考 DefaultListableBeanFactory#doResolveDependency。

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
		Set&lt;String&gt; autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
    //...
    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    //...
}

以上就是Autowired的注入过程源码解析的详细内容,更多关于Autowired注入过程的资料请关注其它相关文章!

您可能感兴趣的文章:
  • 解析Idea为什么不推荐使用@Autowired进行Field注入
  • new出来的对象中无法使用@autowired进行对象bean注入问题
  • @Autowired 自动注入接口失败的原因及解决
  • 解决@Autowired注入空指针问题(利用Bean的生命周期)
  • springboot 静态方法中使用@Autowired注入方式
  • 聊聊@Autowired注解注入,写接口名字还是实现类的名字

Spring @Autowired 注入为 null

Spring @Autowired 注入为 null

Spring @Autowired 自动注入时,如果该对象为静态对象注入的bean就为null,解决办法如下

Spring boot 下 @Autowired 注入为 NULL 的问题

Spring boot 下 @Autowired 注入为 NULL 的问题

问题描述:在 springboot 项目中集成 quartz 时,需要使用到一个 import org.springframework.scheduling.quartz.SchedulerFactoryBean 这个类,并需要自动注入,在测试代码时,发现无法注入到普通.class 文件中,后台报错提示:空指针异常。通过断电调试,发现时 SchedulerFactoryBean 这个类为 NULL。

问题解决方案:

1. 根据 springboot 框架的注入方式检查,@Autowired 注解正确,因为引用的框架本身的类,不需要在 SchedulerFactoryBean 类文件上加上 @Component,所以本身没错。

2. 采用另外的方式进行解决:

 @Autowired
 private SchedulerFactoryBean schedulerFactoryBean;
    
 private static QuartzManager quartzManager;
    
 /**
  * 通过@PostConstruct实现初始化bean之前进行的操作
  * @desc 初始化操作,得到QuartzManager实例
  * @Date 2019年1月7日
  */
 @PostConstruct 
 public void init() {  
      quartzManager = this;  
      quartzManager.schedulerFactoryBean = this.schedulerFactoryBean;        
}

其中 QuartzManager 类就是该类本身,通过 “quartzManager = this;  ” 可以看出来。以后使用 “schedulerFactoryBean” 就直接用 “quartzManager.schedulerFactoryBean” 来代替。

 

这个解决方案的原理还不甚理解,但是可以获取到对象。尝试过将该种写法放在 abstract class 类文件中,结果是无效的,不能解决,所以这种写法我初步认为只能解决普通类的注入问题,缘由还待深究。

关于【04】spring源码解析之Autowired属性注入spring属性注入原理的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Autowired属性为null-Spring Boot配置、Autowired的注入过程源码解析、Spring @Autowired 注入为 null、Spring boot 下 @Autowired 注入为 NULL 的问题的相关知识,请在本站寻找。

本文标签: