目录
前言
spring使用@Autowired和@Value实现了属性的注入,本文重点分析两种注入方式的源码,然后说明@Lazy注解在属性注入时的作用,将上篇文章中的遗留问题解答。
一、整体流程
对@Value和@Autowired注解的处理主要是在AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法,首先是查找@Value和@Autowired注解相关的属性,然后给相关的属性赋值,如果属性中引用的外部bean没有创建,还要进行bean的创建,这也是循环依赖产生的地方。
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
//自动注入属性包含@Value@Autowired注解,this.autowiredAnnotationTypes.add(Autowired.class);
// this.autowiredAnnotationTypes.add(Value.class);
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//完成属性注入
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;
}
二、findAutowiringMetadata
这个方法主要用于查找对象中标注了@Value或者@Autowired注解的属性和方法,本文主要针对属性进行分析,关于方法的处理不会涉及。使用了spring自行封装的ReflectionUtils工具类,遍历对象的所有属性,找出具有相关注解的属性。
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
//含有@Value和@Autowired注解的属性
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
return metadata;
}
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>();
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
//遍历所有属性判断是否含有@Value或者@Autowired注解
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));
}
}
});
return new InjectionMetadata(clazz, elements);
}
三、inject
1.整体流程
在找到需要注入的属性后,会在环境中查找对应的值,通过反射给创建的对象属性进行赋值。
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//处理依赖的bean对象 @Value@autowried,返回对应的值
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
}
if (value != null) {
//反射调用设置属性的值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
如果属性上有@Lazy注解,则直接生成相应的代理对象,将代理对象赋值给相应属性。没有会在环境中进行查找。
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName,
//判断属性上是否有@Lazy注解,有注解生成代理对象,调用时通过DynamicAdvisedInterceptor拦截器解析
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
//在此处解析@value和@Autowaired注解,,,,,,
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
在环境中查找分为@Value和@Autowired两种处理方式,@Value用于注入字面量,@Autowired用于注入依赖的对象属性,下面分别进行分析。
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Class<?> type = descriptor.getDependencyType();
//获取注解中的value值,${name} QualifierAnnotationAutowireCandidateResolver
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
//可用于解析 @Value("${name}")类似属性注入
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value); //从propertysource中读取注入的真正属性值,,
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()));
}
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//获取自动注入的候选 @Autowaird
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
return (instanceCandidate instanceof Class ?
descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
2.@Value注解解析过程
在@Value解析过程中,@Value("${name:xiaoming}")为例,首先以注解中的全部字符 作为key(name:xiaoming)进行查找,结果为null时,查看key中是否存在冒号,有则将key以冒号分割,以冒号前的字符(name)作为key进行查找,结果如果还是null,就以冒号后的字符(xiaoming)作为默认值返回。
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
StringBuilder result = new StringBuilder(value);
int startIndex = value.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
//@Value设置默认值逻辑 @Value("${name:xiaoming}"),以“:”分割进行查找,结果null值以默认值返回
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
}
return result.toString();
}
查找的过程就是在预先加载的propertySource中根据key进行查找,propertySources中存储着容器中的所有属性,包括系统属性,属性文件以及apollo中的属性等。
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
//在所有的propertySources中进行寻找,找到之后退出
for (PropertySource<?> propertySource : this.propertySources) {
if (logger.isTraceEnabled()) {
logger.trace("Searching for key '" + key + "' in PropertySource '" +
propertySource.getName() + "'");
}
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
return null;
}
3.@Autowired注解解析过程
对@Autowired注解属性的查找就是在容器中根据类型查找对应的bean,查找到多个会根据其他属性进行排序,此处不做过多介绍。
protected Map<String, Object> findAutowireCandidates(
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
}
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
//根据类型获取
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
四、@Lazy注解的作用
前面介绍了两种属性的获取过程,在有@Lazy注解的情况下,不会直接注入相关属性,会构建代理对象注入。
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}
构建的代理对象重写了TargetSource的getTarget方法,在调用代理对象的方法时,会调用到getTarget方法,获取真正的属性值,此时才会进行属性的加载。@Lazy注解延迟了属性的加载时间,在调用方法时才会加载,在面对循环依赖和初始化顺序导致的问题时,这个注解有奇效。上篇文章中提到,在有异步任务存在的情况下,循环依赖会有问题,这时我们把相关注入属性加上@Lazy注解,在容器初始化完成后调用相关方法,能够保证对象中的属性都是代理完成后的,从而异步任务能够生效。。
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final 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();
}
@Override
public boolean isStatic() {
return false;
}
@Override
public Object getTarget() {
Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<String>(1) : null);
//获取自动注入的对象,这波操作实现了延迟加载,在调用代理对象方法的时候才会加载,在解决循环依赖和bean加载顺序导致的问题时有奇效
Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
return target;
}
@Override
public void releaseTarget(Object target) {
}
};
总结
本文主要讲解了spring中属性注入的相关源码,主要时@Value,@Autowired和@Lazy注解的相关作用,针对上篇文章中遗留的循环依赖和异步任务的额相关问题进行了补充分析,如有不当之处,欢迎大家一起讨论。