В предыдущей статье было записано срабатывание внедрения зависимостей и создание bean-компонентов, в этой статье в будущем будет записан процесс внедрения свойств bean-компонентов. Внедрение свойства Bean происходит вBeanDefinitionValueResolver
В этом классеBeanDefinitionValueResolver
Этот класс является вспомогательным классом для реализации фабрики компонентов, в обязанности которого входит анализ значений, содержащихся в объекте определения компонента, в фактические значения, которые применяются к целевому экземпляру компонента.
BeanDefinitionValueResolver
в классеresolveValueIfNecessary()
Метод содержит обработку всех типов впрыска. Поэтому данная статья в основном посвящена этому методу.
метод resolveValueIfNecessary
resolveValueIfNecessary()
: Учитывая PropertyValue, вернуть значение, которое разрешает ссылки на другие bean-компоненты в фабрике. значение может быть:
- RuntimeBeanReference: при разборе зависимого компонента анализатор создаст объект RuntimeBeanReference на основе имени зависимого компонента и поместит этот объект в MutablePropertyValues BeanDefinition.
- ManagedList: используется для хранения элементов списка, которыми он управляет, он может содержать ссылки на bean-компоненты времени выполнения (которые будут преобразованы в bean-объекты).
- ManagedSet: используется для хранения заданного значения, которым он управляет, он может содержать ссылки на bean-компоненты во время выполнения (будет преобразован в bean-объекты)
- ManagedMap : используется для хранения значений карты, которыми он управляет, он может содержать ссылки на bean-компоненты во время выполнения (будет разрешен для bean-объектов)
1. Заявление о методе
argName : имя определенного для него параметра
value : объект значения для анализа
public Object resolveValueIfNecessary(Object argName, Object value)
2. RuntimeBeanReference
когда в beanfactory как другойссылка на бин, как объект значения свойства, который будет разрешен во время выполнения. RuntimeBeanReference — это объект данных, созданный при разборе BeanDefinition.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
3. RuntimeBeanNameReference
когда в beanfactory как другойссылка на имя компонента, как объект значения свойства, который будет разрешен во время выполнения.
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
//异常:Invalid bean name '" + refName + "' in bean reference for " + argName
}
return refName;
}
4. Держатель определения компонента
Resolve BeanDefinitionHolder: содержит BeanDefinition с именем и псевдонимом. BeanDefinitionHolder использует имя или псевдоним для сохранения BeanDefinition.
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
5. Определение компонента
Разбор чистого BeanDefinition
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
6. Управляемый массив
Содержит ссылки на bean-компоненты времени выполнения (будут разрешены как bean-объекты)
else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
ManagedArray array = (ManagedArray) value;
Class<?> elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
try {
elementType = ClassUtils.forName(elementTypeName,
this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
}
catch (Throwable ex) {
// Improve the message by showing the context.
//异常:Error resolving array type for " + argName
}
}
else {
elementType = Object.class;
}
}
return resolveManagedArray(argName, (List<?>) value, elementType);
}
7. Управляемый список, управляемый набор, управляемая карта
Содержит ссылки на bean-компоненты времени выполнения (будут разрешены как bean-объекты)
//对ManagedList进行解析
else if (value instanceof ManagedList) {
return resolveManagedList(argName, (List<?>) value);
}
//对ManagedSet进行解析
else if (value instanceof ManagedSet) {
return resolveManagedSet(argName, (Set<?>) value);
}
//对ManagedMap进行解析
else if (value instanceof ManagedMap) {
return resolveManagedMap(argName, (Map<?, ?>) value);
}
8. Управляемые свойства
ManagedProperties представляет экземпляр свойства, управляемого пружиной, который поддерживает слияние определений родительских и дочерних элементов.
//对ManagedProperties进行解析
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
Object propKey = propEntry.getKey();
Object propValue = propEntry.getValue();
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
copy.put(propKey, propValue);
}
return copy;
}
9. Типизированное строковое значение
TypedStringValue содержит значение свойства типа.
//对TypedStringValue进行解析
else if (value instanceof TypedStringValue) {
// Convert value to target type here.
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
else {
return valueObject;
}
}
catch (Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(
//异常:Error converting typed String value for " + argName
}
}
9. Вычислить как выражение
Оценивает заданное значение как выражение.
else {
return evaluate(value);
}
После завершения вышеуказанного синтаксического анализа мы готовы к внедрению зависимостей. Здесь реальный объект Bean задается свойствами другого Bean, от которого он зависит Как видите, обрабатываемые свойства также различаются. Внедрение определенных свойств выполняется в методе setPropertyValue класса реализации BeanWrapperImpl упомянутого ранее интерфейса BeanWrapper.
метод setPropertyValue
1. Объявление метода
Этот метод является закрытым и является фактическим методом обработки BeanWrapperImpl.Он также предоставляет другие перегруженные методы setPropertyValue для предоставления услуг.
private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException
PropertyTokenHolder — это внутренний класс BeanWrapperImpl:
private static class PropertyTokenHolder {
public String canonicalName;
public String actualName;
public String[] keys;
}
В методе setPropertyValue есть две разные ветви в зависимости от того, имеет ли переменная tokens значение null. Когда маркеры равны нулю, имя атрибута будет рекурсивно вызываться и анализироваться, и будет возвращен проанализированный объект BeanWrapImpl nestedBw. Если nestedBw==this, будет установлено значение атрибута resolveTokens объекта pv, и, наконец, будет вызван метод установки значения атрибута объекта nestedBw для установки атрибута. Давайте взглянем:
Когда токены равны нулю, вводится домен класса коллекции.
// 设置tokens的索引和keys
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
getterTokens.canonicalName = tokens.canonicalName;
getterTokens.actualName = tokens.actualName;
getterTokens.keys = new String[tokens.keys.length - 1];
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
Object propValue;
//getPropertyValue用来获取Bean中对对象注入的引用;
try {
propValue = getPropertyValue(getterTokens);
}
catch (NotReadablePropertyException ex) {
//异常:Cannot access indexed value in property referenced " +
"in indexed property path '" + propertyName
}
1. значение свойства равно нулю
if (propValue == null) {
// 空值映射的情况
if (this.autoGrowNestedPaths) {
// TODO: cleanup, this is pretty hacky
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
propValue = setDefaultValue(getterTokens);
}
else {
//异常:Cannot access indexed value in property referenced " +
"in indexed property path '" + propertyName + "': returned null"
}
}
2. Внедрить массив
if (propValue.getClass().isArray()) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(key);
Object oldValue = null;
try {
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
//异常:Invalid array index in property path '" + propertyName
}
}
2. Введите список
else if (propValue instanceof List) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
pd.getReadMethod(), tokens.keys.length);
List list = (List) propValue;
int index = Integer.parseInt(key);
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
int size = list.size();
if (index >= size && index < this.autoGrowCollectionLimit) {
for (int i = size; i < index; i++) {
try {
list.add(null);
}
catch (NullPointerException ex) {
//异常:InvalidPropertyException
}
}
list.add(convertedValue);
}
else {
try {
list.set(index, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
//异常:Invalid list index in property path '" + propertyName + "'"
}
}
}
2. Внедрить карту
else if (propValue instanceof Map) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
pd.getReadMethod(), tokens.keys.length);
Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
pd.getReadMethod(), tokens.keys.length);
Map map = (Map) propValue;
//重要提示:不要在这里传递完整的属性名称
TypeDescriptor typeDescriptor = (mapKeyType != null ?
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
Object oldValue = null;
if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey);
}
// 在这里传递完整的属性名称和旧值,因为希望对map值有完整的转换能力。
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
mapValueType, TypeDescriptor.nested(property(pd), tokens.keys.length));
map.put(convertedMapKey, convertedMapValue);
}
Среди них, когда токены не нулевые, то есть вводится домен класса неколлекции
Это основное место, получить метод set внедренного свойства и внедрить в него объект через механизм отражения.
final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() :
pd.getWriteMethod());
Суммировать
Благодаря приведенному выше анализу мы, вероятно, знакомы с процессом создания bean-компонента и внедрения зависимостей объекта, В этом процессе Spring необходимо рекурсивно завершить внедрение зависимостей в соответствии с информацией в Beandefinition. И эти рекурсивные записи являются методом getBean.
Рекурсия — это рекурсивный вызов для поиска требуемого компонента в системе контекста и создания компонента;
Другой рекурсией является рекурсивный вызов метода контейнера getBean во время внедрения зависимостей для получения зависимого компонента текущего компонента, а также инициирование создания и внедрения зависимого компонента.
Процесс синтаксического анализа при внедрении зависимостей в свойства компонента также является рекурсивным процессом. Таким образом, создание и внедрение bean-компонентов можно выполнять слой за слоем в соответствии с зависимостями, пока создание текущего bean-компонента не будет окончательно завершено.
Ссылаться на
-
"Инсайдер весенних технологий"
-
https://www.cnblogs.com/davidwang456/p/4213652.html