From 21267e56b7b4645e145422ee918eb75fab250f56 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 21 Jun 2019 18:27:33 +0300 Subject: [PATCH] Cache resolved bean instance in ControllerAdviceBean Prior to this commit, the resolveBean() method in ControllerAdviceBean looked up the @ControllerAdvice bean instance in the ApplicationContext by name for every web request that involved lookups for global methods annotated with @ExceptionHandler, @InitBinder, and @ModelAttribute. This commit avoids the need for such repeated lookups in the ApplicationContext by caching the resolved @ControllerAdvice bean instance within ControllerAdviceBean once it has been resolved. --- .../web/method/ControllerAdviceBean.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java index 440cecdacd..c2e2a691be 100644 --- a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java +++ b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java @@ -46,8 +46,19 @@ import org.springframework.web.bind.annotation.ControllerAdvice; */ public class ControllerAdviceBean implements Ordered { + /** + * Declared as {@code Object} since this may be a reference to a + * {@code String} representing the bean name or a reference to the actual + * bean instance. + */ private final Object bean; + /** + * A reference to the resolved bean instance, potentially lazily retrieved + * via the {@code BeanFactory}. + */ + private Object resolvedBean; + @Nullable private final Class beanType; @@ -99,6 +110,7 @@ public class ControllerAdviceBean implements Ordered { else { Assert.notNull(bean, "Bean must not be null"); beanType = ClassUtils.getUserClass(bean.getClass()); + this.resolvedBean = bean; this.order = initOrderFromBean(bean); } @@ -143,9 +155,16 @@ public class ControllerAdviceBean implements Ordered { /** * Get the bean instance for this {@code ControllerAdviceBean}, if necessary * resolving the bean name through the {@link BeanFactory}. + *

As of Spring Framework 5.2, once the bean instance has been resolved it + * will be cached, thereby avoiding repeated lookups in the {@code BeanFactory}. */ public Object resolveBean() { - return (this.bean instanceof String ? obtainBeanFactory().getBean((String) this.bean) : this.bean); + if (this.resolvedBean == null) { + // this.bean must be a String representing the bean name if + // this.resolvedBean is null. + this.resolvedBean = obtainBeanFactory().getBean((String) this.bean); + } + return this.resolvedBean; } private BeanFactory obtainBeanFactory() {