diff --git a/spring-context/src/main/java/org/springframework/context/annotation/BeanAnnotationHelper.java b/spring-context/src/main/java/org/springframework/context/annotation/BeanAnnotationHelper.java index cb7dabd3a6..45a68b828e 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/BeanAnnotationHelper.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/BeanAnnotationHelper.java @@ -17,8 +17,11 @@ package org.springframework.context.annotation; import java.lang.reflect.Method; +import java.util.Map; import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.util.ConcurrentReferenceHashMap; /** * Utilities for processing {@link Bean}-annotated methods. @@ -27,10 +30,11 @@ import org.springframework.core.annotation.AnnotatedElementUtils; * @author Juergen Hoeller * @since 3.1 */ -final class BeanAnnotationHelper { +abstract class BeanAnnotationHelper { - private BeanAnnotationHelper() { - } + private static final Map beanNameCache = new ConcurrentReferenceHashMap<>(); + + private static final Map scopedProxyCache = new ConcurrentReferenceHashMap<>(); public static boolean isBeanAnnotated(Method method) { @@ -38,16 +42,33 @@ final class BeanAnnotationHelper { } public static String determineBeanNameFor(Method beanMethod) { - // By default, the bean name is the name of the @Bean-annotated method - String beanName = beanMethod.getName(); - - // Check to see if the user has explicitly set a custom bean name... - Bean bean = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Bean.class); - if (bean != null && bean.name().length > 0) { - beanName = bean.name()[0]; + String beanName = beanNameCache.get(beanMethod); + if (beanName == null) { + // By default, the bean name is the name of the @Bean-annotated method + beanName = beanMethod.getName(); + // Check to see if the user has explicitly set a custom bean name... + AnnotationAttributes bean = + AnnotatedElementUtils.findMergedAnnotationAttributes(beanMethod, Bean.class, false, false); + if (bean != null) { + String[] names = bean.getStringArray("name"); + if (names.length > 0) { + beanName = names[0]; + } + } + beanNameCache.put(beanMethod, beanName); } - return beanName; } + public static boolean isScopedProxy(Method beanMethod) { + Boolean scopedProxy = scopedProxyCache.get(beanMethod); + if (scopedProxy == null) { + AnnotationAttributes scope = + AnnotatedElementUtils.findMergedAnnotationAttributes(beanMethod, Scope.class, false, false); + scopedProxy = (scope != null && scope.getEnum("proxyMode") != ScopedProxyMode.NO); + scopedProxyCache.put(beanMethod, scopedProxy); + } + return scopedProxy; + } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java index d2f29a1885..517cf92b23 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java @@ -47,7 +47,6 @@ import org.springframework.cglib.proxy.MethodProxy; import org.springframework.cglib.proxy.NoOp; import org.springframework.cglib.transform.ClassEmitterTransformer; import org.springframework.cglib.transform.TransformingClassGenerator; -import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.lang.Nullable; import org.springframework.objenesis.ObjenesisException; import org.springframework.objenesis.SpringObjenesis; @@ -317,8 +316,7 @@ class ConfigurationClassEnhancer { String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod); // Determine whether this bean is a scoped-proxy - Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class); - if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) { + if (BeanAnnotationHelper.isScopedProxy(beanMethod)) { String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName); if (beanFactory.isCurrentlyInCreation(scopedBeanName)) { beanName = scopedBeanName; diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index 82be49e7e8..6097fbfb8a 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -585,22 +585,20 @@ public abstract class AnnotatedElementUtils { * attributes of the same name from higher levels, and * {@link AliasFor @AliasFor} semantics are fully supported, both * within a single annotation and within the annotation hierarchy. - *

In contrast to {@link #getAllAnnotationAttributes}, the search - * algorithm used by this method will stop searching the annotation - * hierarchy once the first annotation of the specified - * {@code annotationType} has been found. As a consequence, additional - * annotations of the specified {@code annotationType} will be ignored. + *

In contrast to {@link #getAllAnnotationAttributes}, the search algorithm + * used by this method will stop searching the annotation hierarchy once the + * first annotation of the specified {@code annotationType} has been found. + * As a consequence, additional annotations of the specified + * {@code annotationType} will be ignored. *

This method follows find semantics as described in the * {@linkplain AnnotatedElementUtils class-level javadoc}. * @param element the annotated element * @param annotationType the annotation type to find * @param classValuesAsString whether to convert Class references into * Strings or to preserve them as Class references - * @param nestedAnnotationsAsMap whether to convert nested Annotation - * instances into {@code AnnotationAttributes} maps or to preserve them - * as Annotation instances - * @return the merged {@code AnnotationAttributes}, or {@code null} if - * not found + * @param nestedAnnotationsAsMap whether to convert nested Annotation instances into + * {@code AnnotationAttributes} maps or to preserve them as Annotation instances + * @return the merged {@code AnnotationAttributes}, or {@code null} if not found * @since 4.2 * @see #findMergedAnnotation(AnnotatedElement, Class) * @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean) diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java index 1e8561afbb..6737eef501 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java @@ -75,19 +75,26 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib } if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationClass.getName())) { Set visited = new LinkedHashSet<>(); - Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass); - if (!ObjectUtils.isEmpty(metaAnnotations)) { - for (Annotation metaAnnotation : metaAnnotations) { - if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) { - recursivelyCollectMetaAnnotations(visited, metaAnnotation); + try { + Annotation[] metaAnnotations = annotationClass.getAnnotations(); + if (!ObjectUtils.isEmpty(metaAnnotations)) { + for (Annotation metaAnnotation : metaAnnotations) { + if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) { + recursivelyCollectMetaAnnotations(visited, metaAnnotation); + } } } + Set metaAnnotationTypeNames = new LinkedHashSet<>(visited.size()); + for (Annotation ann : visited) { + metaAnnotationTypeNames.add(ann.annotationType().getName()); + } + this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames); } - Set metaAnnotationTypeNames = new LinkedHashSet<>(visited.size()); - for (Annotation ann : visited) { - metaAnnotationTypeNames.add(ann.annotationType().getName()); + catch (Throwable ex) { + if (logger.isDebugEnabled()) { + logger.debug("Failed to introspect meta-annotations on " + annotationClass + ": " + ex); + } } - this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames); } } } @@ -110,7 +117,7 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib } catch (Throwable ex) { if (logger.isDebugEnabled()) { - logger.debug("Failed to introspect meta-annotations on [" + annotation + "]: " + ex); + logger.debug("Failed to introspect meta-annotations on " + annotation + ": " + ex); } } } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java index 5f8cdd0ae4..c6087c1fe0 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java @@ -192,7 +192,6 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH } private DestinationHelper getDestinationHelper(MessageHeaders headers, MethodParameter returnType) { - SendToUser m1 = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendToUser.class); SendTo m2 = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendTo.class); if ((m1 != null && !ObjectUtils.isEmpty(m1.value())) || (m2 != null && !ObjectUtils.isEmpty(m2.value()))) { @@ -205,8 +204,8 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH return new DestinationHelper(headers, c1, c2); } - return m1 != null || m2 != null ? - new DestinationHelper(headers, m1, m2) : new DestinationHelper(headers, c1, c2); + return (m1 != null || m2 != null ? + new DestinationHelper(headers, m1, m2) : new DestinationHelper(headers, c1, c2)); } @Nullable @@ -291,9 +290,9 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH return this.sendToUser; } - public String expandTemplateVars(String destination) { return placeholderHelper.replacePlaceholders(destination, this.placeholderResolver); } } + } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java index df57b638f8..be3a21c48b 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import reactor.core.publisher.Mono; import org.springframework.core.MethodParameter; import org.springframework.core.ReactiveAdapterRegistry; -import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.reactive.HandlerResult; @@ -53,9 +53,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle * @param writers writers for serializing to the response body * @param resolver to determine the requested content type */ - public ResponseBodyResultHandler(List> writers, - RequestedContentTypeResolver resolver) { - + public ResponseBodyResultHandler(List> writers, RequestedContentTypeResolver resolver) { this(writers, resolver, ReactiveAdapterRegistry.getSharedInstance()); } @@ -75,10 +73,10 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle @Override public boolean supports(HandlerResult result) { - MethodParameter parameter = result.getReturnTypeSource(); - Class containingClass = parameter.getContainingClass(); - return (AnnotationUtils.findAnnotation(containingClass, ResponseBody.class) != null || - parameter.getMethodAnnotation(ResponseBody.class) != null); + MethodParameter returnType = result.getReturnTypeSource(); + Class containingClass = returnType.getContainingClass(); + return (AnnotatedElementUtils.hasAnnotation(containingClass, ResponseBody.class) || + returnType.hasMethodAnnotation(ResponseBody.class)); } @Override