Skip to content

Commit f968724

Browse files
committed
Ensure private init/destroy method is invoked only once
Closes gh-28083
1 parent a7d5fbf commit f968724

File tree

3 files changed

+67
-5
lines changed

3 files changed

+67
-5
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,7 +1844,7 @@ protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBea
18441844
throws Throwable {
18451845

18461846
boolean isInitializingBean = (bean instanceof InitializingBean);
1847-
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
1847+
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
18481848
if (logger.isTraceEnabled()) {
18491849
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
18501850
}
@@ -1868,7 +1868,7 @@ protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBea
18681868
String initMethodName = mbd.getInitMethodName();
18691869
if (StringUtils.hasLength(initMethodName) &&
18701870
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
1871-
!mbd.isExternallyManagedInitMethod(initMethodName)) {
1871+
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
18721872
invokeCustomInitMethod(beanName, bean, mbd);
18731873
}
18741874
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
* @author Juergen Hoeller
5353
* @author Costin Leau
5454
* @author Stephane Nicoll
55+
* @author Sam Brannen
5556
* @since 2.0
5657
* @see AbstractBeanFactory
5758
* @see org.springframework.beans.factory.DisposableBean
@@ -109,12 +110,12 @@ public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition be
109110
this.beanName = beanName;
110111
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
111112
this.invokeDisposableBean = (bean instanceof DisposableBean &&
112-
!beanDefinition.isExternallyManagedDestroyMethod(DESTROY_METHOD_NAME));
113+
!beanDefinition.hasAnyExternallyManagedDestroyMethod(DESTROY_METHOD_NAME));
113114

114115
String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);
115116
if (destroyMethodName != null &&
116117
!(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodName)) &&
117-
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
118+
!beanDefinition.hasAnyExternallyManagedDestroyMethod(destroyMethodName)) {
118119

119120
this.invokeAutoCloseable = (bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodName));
120121
if (!this.invokeAutoCloseable) {

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

Lines changed: 62 additions & 1 deletion
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-2022 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.
@@ -49,6 +49,7 @@
4949
*
5050
* @author Rod Johnson
5151
* @author Juergen Hoeller
52+
* @author Sam Brannen
5253
* @see GenericBeanDefinition
5354
* @see ChildBeanDefinition
5455
*/
@@ -479,6 +480,36 @@ public boolean isExternallyManagedInitMethod(String initMethod) {
479480
}
480481
}
481482

483+
/**
484+
* Determine if the given method name indicates an externally managed
485+
* initialization method, regardless of method visibility.
486+
* <p>In contrast to {@link #isExternallyManagedInitMethod(String)}, this
487+
* method also returns {@code true} if there is a {@code private} external
488+
* init method that has been
489+
* {@linkplain #registerExternallyManagedInitMethod(String) registered}
490+
* using a fully qualified method name instead of a simple method name.
491+
* @since 5.3.17
492+
*/
493+
boolean hasAnyExternallyManagedInitMethod(String initMethod) {
494+
synchronized (this.postProcessingLock) {
495+
if (isExternallyManagedInitMethod(initMethod)) {
496+
return true;
497+
}
498+
if (this.externallyManagedInitMethods != null) {
499+
for (String candidate : this.externallyManagedInitMethods) {
500+
int indexOfDot = candidate.lastIndexOf(".");
501+
if (indexOfDot >= 0) {
502+
String methodName = candidate.substring(indexOfDot + 1);
503+
if (methodName.equals(initMethod)) {
504+
return true;
505+
}
506+
}
507+
}
508+
}
509+
return false;
510+
}
511+
}
512+
482513
/**
483514
* Return all externally managed initialization methods (as an immutable Set).
484515
* @since 5.3.11
@@ -513,6 +544,36 @@ public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
513544
}
514545
}
515546

547+
/**
548+
* Determine if the given method name indicates an externally managed
549+
* destruction method, regardless of method visibility.
550+
* <p>In contrast to {@link #isExternallyManagedDestroyMethod(String)}, this
551+
* method also returns {@code true} if there is a {@code private} external
552+
* destroy method that has been
553+
* {@linkplain #registerExternallyManagedDestroyMethod(String) registered}
554+
* using a fully qualified method name instead of a simple method name.
555+
* @since 5.3.17
556+
*/
557+
boolean hasAnyExternallyManagedDestroyMethod(String destroyMethod) {
558+
synchronized (this.postProcessingLock) {
559+
if (isExternallyManagedDestroyMethod(destroyMethod)) {
560+
return true;
561+
}
562+
if (this.externallyManagedDestroyMethods != null) {
563+
for (String candidate : this.externallyManagedDestroyMethods) {
564+
int indexOfDot = candidate.lastIndexOf(".");
565+
if (indexOfDot >= 0) {
566+
String methodName = candidate.substring(indexOfDot + 1);
567+
if (methodName.equals(destroyMethod)) {
568+
return true;
569+
}
570+
}
571+
}
572+
}
573+
return false;
574+
}
575+
}
576+
516577
/**
517578
* Return all externally managed destruction methods (as an immutable Set).
518579
* @since 5.3.11

0 commit comments

Comments
 (0)