Skip to content

Commit 1735300

Browse files
committed
Efficient concurrency in MethodOverrides through CopyOnWriteArraySet
Also restores immediate MethodOverrides instance in AbstractBeanDefinition, avoiding potential lazy-init race condition. Closes gh-23448
1 parent 8f90f65 commit 1735300

File tree

2 files changed

+16
-38
lines changed

2 files changed

+16
-38
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
179179
@Nullable
180180
private MutablePropertyValues propertyValues;
181181

182-
@Nullable
183-
private MethodOverrides methodOverrides;
182+
private MethodOverrides methodOverrides = new MethodOverrides();
184183

185184
@Nullable
186185
private String initMethodName;
@@ -869,9 +868,6 @@ public void setMethodOverrides(MethodOverrides methodOverrides) {
869868
* <p>Never returns {@code null}.
870869
*/
871870
public MethodOverrides getMethodOverrides() {
872-
if (this.methodOverrides == null) {
873-
this.methodOverrides = new MethodOverrides();
874-
}
875871
return this.methodOverrides;
876872
}
877873

@@ -880,7 +876,7 @@ public MethodOverrides getMethodOverrides() {
880876
* @since 5.0.2
881877
*/
882878
public boolean hasMethodOverrides() {
883-
return (this.methodOverrides != null && !this.methodOverrides.isEmpty());
879+
return !this.methodOverrides.isEmpty();
884880
}
885881

886882
/**
@@ -1058,10 +1054,9 @@ public BeanDefinition getOriginatingBeanDefinition() {
10581054
public void validate() throws BeanDefinitionValidationException {
10591055
if (hasMethodOverrides() && getFactoryMethodName() != null) {
10601056
throw new BeanDefinitionValidationException(
1061-
"Cannot combine static factory method with method overrides: " +
1062-
"the static factory method must create the instance");
1057+
"Cannot combine factory method with container-generated method overrides: " +
1058+
"the factory method must create the concrete bean instance.");
10631059
}
1064-
10651060
if (hasBeanClass()) {
10661061
prepareMethodOverrides();
10671062
}
@@ -1073,14 +1068,9 @@ public void validate() throws BeanDefinitionValidationException {
10731068
* @throws BeanDefinitionValidationException in case of validation failure
10741069
*/
10751070
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
1076-
// Check that lookup methods exists.
1071+
// Check that lookup methods exist and determine their overloaded status.
10771072
if (hasMethodOverrides()) {
1078-
Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
1079-
synchronized (overrides) {
1080-
for (MethodOverride mo : overrides) {
1081-
prepareMethodOverride(mo);
1082-
}
1083-
}
1073+
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
10841074
}
10851075
}
10861076

spring-beans/src/main/java/org/springframework/beans/factory/support/MethodOverrides.java

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -17,9 +17,8 @@
1717
package org.springframework.beans.factory.support;
1818

1919
import java.lang.reflect.Method;
20-
import java.util.Collections;
21-
import java.util.LinkedHashSet;
2220
import java.util.Set;
21+
import java.util.concurrent.CopyOnWriteArraySet;
2322

2423
import org.springframework.lang.Nullable;
2524

@@ -37,9 +36,7 @@
3736
*/
3837
public class MethodOverrides {
3938

40-
private final Set<MethodOverride> overrides = Collections.synchronizedSet(new LinkedHashSet<>(2));
41-
42-
private volatile boolean modified = false;
39+
private final Set<MethodOverride> overrides = new CopyOnWriteArraySet<>();
4340

4441

4542
/**
@@ -61,7 +58,6 @@ public MethodOverrides(MethodOverrides other) {
6158
*/
6259
public void addOverrides(@Nullable MethodOverrides other) {
6360
if (other != null) {
64-
this.modified = true;
6561
this.overrides.addAll(other.overrides);
6662
}
6763
}
@@ -70,25 +66,23 @@ public void addOverrides(@Nullable MethodOverrides other) {
7066
* Add the given method override.
7167
*/
7268
public void addOverride(MethodOverride override) {
73-
this.modified = true;
7469
this.overrides.add(override);
7570
}
7671

7772
/**
7873
* Return all method overrides contained by this object.
79-
* @return Set of MethodOverride objects
74+
* @return a Set of MethodOverride objects
8075
* @see MethodOverride
8176
*/
8277
public Set<MethodOverride> getOverrides() {
83-
this.modified = true;
8478
return this.overrides;
8579
}
8680

8781
/**
8882
* Return whether the set of method overrides is empty.
8983
*/
9084
public boolean isEmpty() {
91-
return (!this.modified || this.overrides.isEmpty());
85+
return this.overrides.isEmpty();
9286
}
9387

9488
/**
@@ -98,18 +92,13 @@ public boolean isEmpty() {
9892
*/
9993
@Nullable
10094
public MethodOverride getOverride(Method method) {
101-
if (!this.modified) {
102-
return null;
103-
}
104-
synchronized (this.overrides) {
105-
MethodOverride match = null;
106-
for (MethodOverride candidate : this.overrides) {
107-
if (candidate.matches(method)) {
108-
match = candidate;
109-
}
95+
MethodOverride match = null;
96+
for (MethodOverride candidate : this.overrides) {
97+
if (candidate.matches(method)) {
98+
match = candidate;
11099
}
111-
return match;
112100
}
101+
return match;
113102
}
114103

115104

@@ -123,7 +112,6 @@ public boolean equals(Object other) {
123112
}
124113
MethodOverrides that = (MethodOverrides) other;
125114
return this.overrides.equals(that.overrides);
126-
127115
}
128116

129117
@Override

0 commit comments

Comments
 (0)