diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java index 6dbb6d8bd972..650b40736cd6 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java @@ -34,6 +34,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * Convenient superclass for @@ -82,6 +83,11 @@ protected final BeanFactory getBeanFactory() { return this.beanFactory; } + private ConfigurableBeanFactory getConfigurableBeanFactory() { + Assert.state(this.beanFactory != null, "BeanFactory not set"); + return this.beanFactory; + } + //--------------------------------------------------------------------- // Implementation of the TargetSourceCreator interface @@ -105,7 +111,7 @@ public final TargetSource getTargetSource(Class beanClass, String beanName) { // We need to override just this bean definition, as it may reference other beans // and we're happy to take the parent's definition for those. // Always use prototype scope if demanded. - BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName); + BeanDefinition bd = getConfigurableBeanFactory().getMergedBeanDefinition(beanName); GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd); if (isPrototypeBased()) { bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE); @@ -127,7 +133,7 @@ public final TargetSource getTargetSource(Class beanClass, String beanName) { protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) { synchronized (this.internalBeanFactories) { return this.internalBeanFactories.computeIfAbsent(beanName, - name -> buildInternalBeanFactory(this.beanFactory)); + name -> buildInternalBeanFactory(getConfigurableBeanFactory())); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java index 9a9679fd2918..4c789587955f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** @@ -58,16 +59,18 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour protected final transient Log logger = LogFactory.getLog(getClass()); /** Name of the target bean we will create on each invocation. */ + @Nullable private String targetBeanName; /** Class of the target. */ + @Nullable private volatile Class targetClass; /** * BeanFactory that owns this TargetSource. We need to hold onto this * reference so that we can create new prototype instances as necessary. */ - @SuppressWarnings("serial") + @Nullable private BeanFactory beanFactory; @@ -88,6 +91,7 @@ public void setTargetBeanName(String targetBeanName) { * Return the name of the target bean in the factory. */ public String getTargetBeanName() { + Assert.state(this.targetBeanName != null, "Target bean name not set"); return this.targetBeanName; } @@ -117,11 +121,13 @@ public void setBeanFactory(BeanFactory beanFactory) { * Return the owning BeanFactory. */ public BeanFactory getBeanFactory() { + Assert.state(this.beanFactory != null, "BeanFactory not set"); return this.beanFactory; } @Override + @Nullable public Class getTargetClass() { Class targetClass = this.targetClass; if (targetClass != null) { @@ -130,7 +136,7 @@ public Class getTargetClass() { synchronized (this) { // Full check within synchronization, entering the BeanFactory interaction algorithm only once... targetClass = this.targetClass; - if (targetClass == null && this.beanFactory != null) { + if (targetClass == null && this.beanFactory != null && this.targetBeanName != null) { // Determine type of the target bean. targetClass = this.beanFactory.getType(this.targetBeanName); if (targetClass == null) { @@ -184,18 +190,16 @@ public boolean equals(@Nullable Object other) { @Override public int hashCode() { - int hashCode = getClass().hashCode(); - hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.beanFactory); - hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.targetBeanName); - return hashCode; + return getClass().hashCode() * 13 + ObjectUtils.nullSafeHashCode(this.targetBeanName); } @Override public String toString() { StringBuilder sb = new StringBuilder(getClass().getSimpleName()); sb.append(" for target bean '").append(this.targetBeanName).append('\''); - if (this.targetClass != null) { - sb.append(" of type [").append(this.targetClass.getName()).append(']'); + Class targetClass = this.targetClass; + if (targetClass != null) { + sb.append(" of type [").append(targetClass.getName()).append(']'); } return sb.toString(); } diff --git a/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java index f742a106bab8..8246e1e6268f 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2023 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. @@ -46,6 +46,7 @@ public abstract class AbstractLazyCreationTargetSource implements TargetSource { protected final Log logger = LogFactory.getLog(getClass()); /** The lazily initialized target object. */ + @Nullable private Object lazyTarget; diff --git a/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java index a78e6e4b40e2..b9f45e2a57fd 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java @@ -70,6 +70,7 @@ public static EmptyTargetSource forClass(@Nullable Class targetClass, boolean // Instance implementation //--------------------------------------------------------------------- + @Nullable private final Class targetClass; private final boolean isStatic; diff --git a/spring-aop/src/main/java/org/springframework/aop/target/HotSwappableTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/HotSwappableTargetSource.java index 8242bbfcac4e..1a1a2fa7552a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/HotSwappableTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/HotSwappableTargetSource.java @@ -97,12 +97,11 @@ public synchronized Object swap(Object newTarget) throws IllegalArgumentExceptio /** - * Two HotSwappableTargetSources are equal if the current target - * objects are equal. + * Two HotSwappableTargetSources are equal if the current target objects are equal. */ @Override - public boolean equals(@Nullable Object obj) { - return (this == obj || (obj instanceof HotSwappableTargetSource that && + public boolean equals(@Nullable Object other) { + return (this == other || (other instanceof HotSwappableTargetSource that && this.target.equals(that.target))); } diff --git a/spring-aop/src/main/java/org/springframework/aop/target/SingletonTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/SingletonTargetSource.java index 8ebe6d2991ce..e1b2ae6a56c7 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/SingletonTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/SingletonTargetSource.java @@ -84,13 +84,8 @@ public boolean isStatic() { */ @Override public boolean equals(@Nullable Object other) { - if (this == other) { - return true; - } - if (!(other instanceof SingletonTargetSource otherTargetSource)) { - return false; - } - return this.target.equals(otherTargetSource.target); + return (this == other || (other instanceof SingletonTargetSource that && + this.target.equals(that.target))); } /** diff --git a/spring-aop/src/main/java/org/springframework/aop/target/ThreadLocalTargetSource.java b/spring-aop/src/main/java/org/springframework/aop/target/ThreadLocalTargetSource.java index 5c4b03c78495..7edfc0aff608 100644 --- a/spring-aop/src/main/java/org/springframework/aop/target/ThreadLocalTargetSource.java +++ b/spring-aop/src/main/java/org/springframework/aop/target/ThreadLocalTargetSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2023 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. @@ -58,7 +58,12 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource * is meant to be per thread per instance of the ThreadLocalTargetSource class. */ private final ThreadLocal targetInThread = - new NamedThreadLocal<>("Thread-local instance of bean '" + getTargetBeanName() + "'"); + new NamedThreadLocal<>("Thread-local instance of bean") { + @Override + public String toString() { + return super.toString() + " '" + getTargetBeanName() + "'"; + } + }; /** * Set of managed targets, enabling us to keep track of the targets we've created.