Skip to content

Commit 268b7a8

Browse files
committed
Revise TargetSource implementations for proper nullability
Includes hashCode optimization in AbstractBeanFactoryBasedTargetSource. Includes ThreadLocal naming fix in ThreadLocalTargetSource. Closes gh-30576 Closes gh-30581 (cherry picked from commit c685525)
1 parent 1240fb6 commit 268b7a8

File tree

7 files changed

+39
-27
lines changed

7 files changed

+39
-27
lines changed

spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/target/AbstractBeanFactoryBasedTargetSourceCreator.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3535
import org.springframework.beans.factory.support.GenericBeanDefinition;
3636
import org.springframework.lang.Nullable;
37+
import org.springframework.util.Assert;
3738

3839
/**
3940
* Convenient superclass for
@@ -81,6 +82,11 @@ protected final BeanFactory getBeanFactory() {
8182
return this.beanFactory;
8283
}
8384

85+
private ConfigurableBeanFactory getConfigurableBeanFactory() {
86+
Assert.state(this.beanFactory != null, "BeanFactory not set");
87+
return this.beanFactory;
88+
}
89+
8490

8591
//---------------------------------------------------------------------
8692
// Implementation of the TargetSourceCreator interface
@@ -104,7 +110,7 @@ public final TargetSource getTargetSource(Class<?> beanClass, String beanName) {
104110
// We need to override just this bean definition, as it may reference other beans
105111
// and we're happy to take the parent's definition for those.
106112
// Always use prototype scope if demanded.
107-
BeanDefinition bd = this.beanFactory.getMergedBeanDefinition(beanName);
113+
BeanDefinition bd = getConfigurableBeanFactory().getMergedBeanDefinition(beanName);
108114
GenericBeanDefinition bdCopy = new GenericBeanDefinition(bd);
109115
if (isPrototypeBased()) {
110116
bdCopy.setScope(BeanDefinition.SCOPE_PROTOTYPE);
@@ -126,7 +132,7 @@ public final TargetSource getTargetSource(Class<?> beanClass, String beanName) {
126132
protected DefaultListableBeanFactory getInternalBeanFactoryForBean(String beanName) {
127133
synchronized (this.internalBeanFactories) {
128134
return this.internalBeanFactories.computeIfAbsent(beanName,
129-
name -> buildInternalBeanFactory(this.beanFactory));
135+
name -> buildInternalBeanFactory(getConfigurableBeanFactory()));
130136
}
131137
}
132138

spring-aop/src/main/java/org/springframework/aop/target/AbstractBeanFactoryBasedTargetSource.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
2424
import org.springframework.aop.TargetSource;
2525
import org.springframework.beans.factory.BeanFactory;
2626
import org.springframework.beans.factory.BeanFactoryAware;
27+
import org.springframework.lang.Nullable;
28+
import org.springframework.util.Assert;
2729
import org.springframework.util.ObjectUtils;
2830

2931
/**
@@ -57,15 +59,18 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
5759
protected final Log logger = LogFactory.getLog(getClass());
5860

5961
/** Name of the target bean we will create on each invocation. */
62+
@Nullable
6063
private String targetBeanName;
6164

6265
/** Class of the target. */
66+
@Nullable
6367
private volatile Class<?> targetClass;
6468

6569
/**
6670
* BeanFactory that owns this TargetSource. We need to hold onto this
6771
* reference so that we can create new prototype instances as necessary.
6872
*/
73+
@Nullable
6974
private BeanFactory beanFactory;
7075

7176

@@ -86,6 +91,7 @@ public void setTargetBeanName(String targetBeanName) {
8691
* Return the name of the target bean in the factory.
8792
*/
8893
public String getTargetBeanName() {
94+
Assert.state(this.targetBeanName != null, "Target bean name not set");
8995
return this.targetBeanName;
9096
}
9197

@@ -115,11 +121,13 @@ public void setBeanFactory(BeanFactory beanFactory) {
115121
* Return the owning BeanFactory.
116122
*/
117123
public BeanFactory getBeanFactory() {
124+
Assert.state(this.beanFactory != null, "BeanFactory not set");
118125
return this.beanFactory;
119126
}
120127

121128

122129
@Override
130+
@Nullable
123131
public Class<?> getTargetClass() {
124132
Class<?> targetClass = this.targetClass;
125133
if (targetClass != null) {
@@ -128,7 +136,7 @@ public Class<?> getTargetClass() {
128136
synchronized (this) {
129137
// Full check within synchronization, entering the BeanFactory interaction algorithm only once...
130138
targetClass = this.targetClass;
131-
if (targetClass == null && this.beanFactory != null) {
139+
if (targetClass == null && this.beanFactory != null && this.targetBeanName != null) {
132140
// Determine type of the target bean.
133141
targetClass = this.beanFactory.getType(this.targetBeanName);
134142
if (targetClass == null) {
@@ -182,18 +190,16 @@ public boolean equals(Object other) {
182190

183191
@Override
184192
public int hashCode() {
185-
int hashCode = getClass().hashCode();
186-
hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.beanFactory);
187-
hashCode = 13 * hashCode + ObjectUtils.nullSafeHashCode(this.targetBeanName);
188-
return hashCode;
193+
return getClass().hashCode() * 13 + ObjectUtils.nullSafeHashCode(this.targetBeanName);
189194
}
190195

191196
@Override
192197
public String toString() {
193198
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
194199
sb.append(" for target bean '").append(this.targetBeanName).append('\'');
195-
if (this.targetClass != null) {
196-
sb.append(" of type [").append(this.targetClass.getName()).append(']');
200+
Class<?> targetClass = this.targetClass;
201+
if (targetClass != null) {
202+
sb.append(" of type [").append(targetClass.getName()).append(']');
197203
}
198204
return sb.toString();
199205
}

spring-aop/src/main/java/org/springframework/aop/target/AbstractLazyCreationTargetSource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ public abstract class AbstractLazyCreationTargetSource implements TargetSource {
4646
protected final Log logger = LogFactory.getLog(getClass());
4747

4848
/** The lazily initialized target object. */
49+
@Nullable
4950
private Object lazyTarget;
5051

5152

spring-aop/src/main/java/org/springframework/aop/target/EmptyTargetSource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -70,6 +70,7 @@ public static EmptyTargetSource forClass(@Nullable Class<?> targetClass, boolean
7070
// Instance implementation
7171
//---------------------------------------------------------------------
7272

73+
@Nullable
7374
private final Class<?> targetClass;
7475

7576
private final boolean isStatic;

spring-aop/src/main/java/org/springframework/aop/target/HotSwappableTargetSource.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -95,8 +95,7 @@ public synchronized Object swap(Object newTarget) throws IllegalArgumentExceptio
9595

9696

9797
/**
98-
* Two HotSwappableTargetSources are equal if the current target
99-
* objects are equal.
98+
* Two HotSwappableTargetSources are equal if the current target objects are equal.
10099
*/
101100
@Override
102101
public boolean equals(Object other) {

spring-aop/src/main/java/org/springframework/aop/target/SingletonTargetSource.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -82,14 +82,8 @@ public boolean isStatic() {
8282
*/
8383
@Override
8484
public boolean equals(Object other) {
85-
if (this == other) {
86-
return true;
87-
}
88-
if (!(other instanceof SingletonTargetSource)) {
89-
return false;
90-
}
91-
SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
92-
return this.target.equals(otherTargetSource.target);
85+
return (this == other || (other instanceof SingletonTargetSource &&
86+
this.target.equals(((SingletonTargetSource) other).target)));
9387
}
9488

9589
/**

spring-aop/src/main/java/org/springframework/aop/target/ThreadLocalTargetSource.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -58,7 +58,12 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
5858
* is meant to be per thread per instance of the ThreadLocalTargetSource class.
5959
*/
6060
private final ThreadLocal<Object> targetInThread =
61-
new NamedThreadLocal<>("Thread-local instance of bean '" + getTargetBeanName() + "'");
61+
new NamedThreadLocal<Object>("Thread-local instance of bean") {
62+
@Override
63+
public String toString() {
64+
return super.toString() + " '" + getTargetBeanName() + "'";
65+
}
66+
};
6267

6368
/**
6469
* Set of managed targets, enabling us to keep track of the targets we've created.

0 commit comments

Comments
 (0)