|
16 | 16 | */ |
17 | 17 | package org.apache.dubbo.config.spring.beans.factory.annotation; |
18 | 18 |
|
19 | | -import org.apache.dubbo.config.annotation.Reference; |
20 | | -import org.apache.dubbo.config.spring.ReferenceBean; |
21 | 19 | import org.apache.commons.logging.Log; |
22 | 20 | import org.apache.commons.logging.LogFactory; |
| 21 | +import org.apache.dubbo.common.Constants; |
| 22 | +import org.apache.dubbo.common.utils.StringUtils; |
| 23 | +import org.apache.dubbo.config.annotation.Reference; |
| 24 | +import org.apache.dubbo.config.spring.ReferenceBean; |
23 | 25 | import org.springframework.beans.BeanUtils; |
24 | 26 | import org.springframework.beans.BeansException; |
25 | 27 | import org.springframework.beans.PropertyValues; |
|
35 | 37 | import org.springframework.core.PriorityOrdered; |
36 | 38 | import org.springframework.core.env.Environment; |
37 | 39 | import org.springframework.util.ClassUtils; |
| 40 | +import org.springframework.util.ConcurrentReferenceHashMap; |
| 41 | +import org.springframework.util.ObjectUtils; |
38 | 42 | import org.springframework.util.ReflectionUtils; |
39 | | -import org.springframework.util.StringUtils; |
40 | 43 |
|
41 | 44 | import java.beans.PropertyDescriptor; |
| 45 | +import java.lang.annotation.Annotation; |
42 | 46 | import java.lang.reflect.Field; |
43 | 47 | import java.lang.reflect.Method; |
44 | 48 | import java.lang.reflect.Modifier; |
45 | 49 | import java.util.ArrayList; |
46 | 50 | import java.util.Collection; |
| 51 | +import java.util.Iterator; |
47 | 52 | import java.util.LinkedHashMap; |
48 | 53 | import java.util.LinkedList; |
49 | 54 | import java.util.List; |
@@ -83,6 +88,9 @@ public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBean |
83 | 88 | private final ConcurrentMap<String, ReferenceBean<?>> referenceBeansCache = |
84 | 89 | new ConcurrentHashMap<String, ReferenceBean<?>>(); |
85 | 90 |
|
| 91 | + private static final Map<Class<? extends Annotation>, List<Method>> annotationMethodsCache = |
| 92 | + new ConcurrentReferenceHashMap<Class<? extends Annotation>, List<Method>>(256); |
| 93 | + |
86 | 94 | @Override |
87 | 95 | public PropertyValues postProcessPropertyValues( |
88 | 96 | PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { |
@@ -193,7 +201,7 @@ private ReferenceInjectionMetadata buildReferenceMetadata(final Class<?> beanCla |
193 | 201 |
|
194 | 202 | private InjectionMetadata findReferenceMetadata(String beanName, Class<?> clazz, PropertyValues pvs) { |
195 | 203 | // Fall back to class name as cache key, for backwards compatibility with custom callers. |
196 | | - String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); |
| 204 | + String cacheKey = (StringUtils.isNotEmpty(beanName) ? beanName : clazz.getName()); |
197 | 205 | // Quick check on the concurrent map first, with minimal locking. |
198 | 206 | ReferenceInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); |
199 | 207 | if (InjectionMetadata.needsRefresh(metadata, clazz)) { |
@@ -402,11 +410,7 @@ private ReferenceBean<?> buildReferenceBean(Reference reference, Class<?> refere |
402 | 410 | */ |
403 | 411 | private String generateReferenceBeanCacheKey(Reference reference, Class<?> beanClass) { |
404 | 412 |
|
405 | | - String interfaceName = resolveInterfaceName(reference, beanClass); |
406 | | - |
407 | | - String key = reference.url() + "/" + interfaceName + |
408 | | - "/" + reference.version() + |
409 | | - "/" + reference.group(); |
| 413 | + String key = resolveReferenceKey(annotationValues(reference)); |
410 | 414 |
|
411 | 415 | Environment environment = applicationContext.getEnvironment(); |
412 | 416 |
|
@@ -501,5 +505,90 @@ private <T> T getFieldValue(Object object, String fieldName, Class<T> fieldType) |
501 | 505 |
|
502 | 506 | } |
503 | 507 |
|
| 508 | + /** |
| 509 | + * Generate a key based on the annotation. |
| 510 | + * |
| 511 | + * @param annotations annotatoin value |
| 512 | + * @return unique key, never null will be returned. |
| 513 | + * @since 2.7.0 |
| 514 | + */ |
| 515 | + private String resolveReferenceKey(Map<String, Object> annotations) { |
| 516 | + Iterator<Map.Entry<String, Object>> annotationVisitor = annotations.entrySet().iterator(); |
| 517 | + StringBuilder builder = new StringBuilder(); |
| 518 | + while (annotationVisitor.hasNext()) { |
| 519 | + Map.Entry<String, Object> attribute = annotationVisitor.next(); |
| 520 | + String attributeValue = null; |
| 521 | + if (attribute.getValue() instanceof String[]) { |
| 522 | + attributeValue = toPlainString((String[]) attribute.getValue()); |
| 523 | + } else { |
| 524 | + attributeValue = attribute.getValue() == null ? "" : attribute.getValue().toString(); |
| 525 | + } |
| 526 | + |
| 527 | + if (StringUtils.isNotEmpty(attributeValue)) { |
| 528 | + if (builder.length() > 0) { |
| 529 | + builder.append(Constants.PATH_SEPARATOR); |
| 530 | + } |
| 531 | + builder.append(attributeValue); |
| 532 | + } |
| 533 | + } |
| 534 | + return builder.toString(); |
| 535 | + } |
| 536 | + |
| 537 | + private Map<String, Object> annotationValues(Annotation annotation) { |
| 538 | + Map<String, Object> annotations = new LinkedHashMap<>(); |
504 | 539 |
|
| 540 | + for (Method method : getAnnotationMethods(annotation.annotationType())) { |
| 541 | + try { |
| 542 | + Object attributeValue = method.invoke(annotation); |
| 543 | + Object defaultValue = method.getDefaultValue(); |
| 544 | + if (nullSafeEquals(attributeValue, defaultValue)) { |
| 545 | + continue; |
| 546 | + } |
| 547 | + annotations.put(method.getName(), attributeValue); |
| 548 | + } catch (Throwable e) { |
| 549 | + throw new IllegalStateException("Failed to obtain annotation attribute value for " + method, e); |
| 550 | + } |
| 551 | + } |
| 552 | + return annotations; |
| 553 | + } |
| 554 | + |
| 555 | + private static List<Method> getAnnotationMethods(Class<? extends Annotation> annotationType) { |
| 556 | + List<Method> methods = annotationMethodsCache.get(annotationType); |
| 557 | + if (methods != null) { |
| 558 | + return methods; |
| 559 | + } |
| 560 | + |
| 561 | + methods = new ArrayList<Method>(); |
| 562 | + for (Method method : annotationType.getDeclaredMethods()) { |
| 563 | + if (isAnnotationMethod(method)) { |
| 564 | + ReflectionUtils.makeAccessible(method); |
| 565 | + methods.add(method); |
| 566 | + } |
| 567 | + } |
| 568 | + |
| 569 | + annotationMethodsCache.put(annotationType, methods); |
| 570 | + return methods; |
| 571 | + } |
| 572 | + |
| 573 | + private static boolean isAnnotationMethod(Method method) { |
| 574 | + return (method != null |
| 575 | + && method.getParameterTypes().length == 0 |
| 576 | + && method.getReturnType() != void.class); |
| 577 | + } |
| 578 | + |
| 579 | + private static boolean nullSafeEquals(Object first, Object another) { |
| 580 | + return ObjectUtils.nullSafeEquals(first, another); |
| 581 | + } |
| 582 | + |
| 583 | + private String toPlainString(String[] array) { |
| 584 | + if (array == null || array.length == 0) return ""; |
| 585 | + StringBuilder buffer = new StringBuilder(); |
| 586 | + for (int i = 0; i < array.length; i++) { |
| 587 | + if (i > 0) { |
| 588 | + buffer.append(Constants.COMMA_SEPARATOR); |
| 589 | + } |
| 590 | + buffer.append(array[i]); |
| 591 | + } |
| 592 | + return buffer.toString(); |
| 593 | + } |
505 | 594 | } |
0 commit comments