Merge branch '6.0.x'

This commit is contained in:
Sam Brannen 2023-06-22 13:54:04 +02:00
commit 5598dd2c34
4 changed files with 100 additions and 78 deletions

View File

@ -1795,10 +1795,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
/**
* Give a bean a chance to react now all its properties are set,
* Give a bean a chance to initialize itself after all its properties are set,
* and a chance to know about its owning bean factory (this object).
* This means checking whether the bean implements InitializingBean or defines
* a custom init method, and invoking the necessary callback(s) if it does.
* <p>This means checking whether the bean implements {@link InitializingBean}
* or defines any custom init methods, and invoking the necessary callback(s)
* if it does.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the merged bean definition that the bean was created with
@ -1861,7 +1862,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
}
Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod, bean.getClass());

View File

@ -263,15 +263,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
@Nullable
private Method determineDestroyMethod(String name) {
private Method determineDestroyMethod(String destroyMethodName) {
try {
Class<?> beanClass = this.bean.getClass();
Method destroyMethod = findDestroyMethod(beanClass, name);
Method destroyMethod = findDestroyMethod(beanClass, destroyMethodName);
if (destroyMethod != null) {
return destroyMethod;
}
for (Class<?> beanInterface : beanClass.getInterfaces()) {
destroyMethod = findDestroyMethod(beanInterface, name);
destroyMethod = findDestroyMethod(beanInterface, destroyMethodName);
if (destroyMethod != null) {
return destroyMethod;
}

View File

@ -28,6 +28,8 @@ import java.util.function.Supplier;
import javax.lang.model.element.Modifier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GeneratedClass;
@ -61,6 +63,8 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Phillip Webb
* @author Stephane Nicoll
* @author Olga Maciaszek-Sharma
* @author Sam Brannen
* @since 6.0
*/
class BeanDefinitionPropertiesCodeGeneratorTests {
@ -212,56 +216,6 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
compile((actual, compiled) -> assertThat(actual.getRole()).isEqualTo(999));
}
@Test
void setInitMethodWhenSingleInitMethod() {
this.beanDefinition.setTargetType(InitDestroyBean.class);
this.beanDefinition.setInitMethodName("i1");
compile((actual, compiled) -> assertThat(actual.getInitMethodNames()).containsExactly("i1"));
assertHasMethodInvokeHints(InitDestroyBean.class, "i1");
}
@Test
void setInitMethodWhenNoInitMethod() {
this.beanDefinition.setTargetType(InitDestroyBean.class);
compile((actual, compiled) -> assertThat(actual.getInitMethodNames()).isNull());
}
@Test
void setInitMethodWhenMultipleInitMethods() {
this.beanDefinition.setTargetType(InitDestroyBean.class);
this.beanDefinition.setInitMethodNames("i1", "i2");
compile((actual, compiled) -> assertThat(actual.getInitMethodNames()).containsExactly("i1", "i2"));
assertHasMethodInvokeHints(InitDestroyBean.class, "i1", "i2");
}
@Test
void setDestroyMethodWhenDestroyInitMethod() {
this.beanDefinition.setTargetType(InitDestroyBean.class);
this.beanDefinition.setDestroyMethodName("d1");
compile((actual, compiled) -> assertThat(actual.getDestroyMethodNames()).containsExactly("d1"));
assertHasMethodInvokeHints(InitDestroyBean.class, "d1");
}
@Test
void setDestroyMethodWhenNoDestroyMethod() {
this.beanDefinition.setTargetType(InitDestroyBean.class);
compile((actual, compiled) -> assertThat(actual.getDestroyMethodNames()).isNull());
}
@Test
void setDestroyMethodWhenMultipleDestroyMethods() {
this.beanDefinition.setTargetType(InitDestroyBean.class);
this.beanDefinition.setDestroyMethodNames("d1", "d2");
compile((actual, compiled) -> assertThat(actual.getDestroyMethodNames()).containsExactly("d1", "d2"));
assertHasMethodInvokeHints(InitDestroyBean.class, "d1", "d2");
}
private void assertHasMethodInvokeHints(Class<?> beanType, String... methodNames) {
assertThat(methodNames).allMatch(methodName -> RuntimeHintsPredicates.reflection()
.onMethod(beanType, methodName).invoke()
.test(this.generationContext.getRuntimeHints()));
}
@Test
void constructorArgumentValuesWhenValues() {
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, String.class);
@ -419,6 +373,60 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
});
}
@Nested
class InitDestroyMethodTests {
@BeforeEach
void setTargetType() {
beanDefinition.setTargetType(InitDestroyBean.class);
}
@Test
void noInitMethod() {
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).isNull());
}
@Test
void singleInitMethod() {
beanDefinition.setInitMethodName("init");
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("init"));
assertHasMethodInvokeHints(InitDestroyBean.class, "init");
}
@Test
void multipleInitMethods() {
beanDefinition.setInitMethodNames("init", "init2");
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("init", "init2"));
assertHasMethodInvokeHints(InitDestroyBean.class, "init", "init2");
}
@Test
void noDestroyMethod() {
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).isNull());
}
@Test
void singleDestroyMethod() {
beanDefinition.setDestroyMethodName("destroy");
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy"));
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy");
}
@Test
void multipleDestroyMethods() {
beanDefinition.setDestroyMethodNames("destroy", "destroy2");
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", "destroy2"));
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "destroy2");
}
}
private void assertHasMethodInvokeHints(Class<?> beanType, String... methodNames) {
assertThat(methodNames).allMatch(methodName -> RuntimeHintsPredicates.reflection()
.onMethod(beanType, methodName).invoke()
.test(this.generationContext.getRuntimeHints()));
}
private void compile(BiConsumer<RootBeanDefinition, Compiled> result) {
compile(attribute -> true, result);
}
@ -450,16 +458,16 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
static class InitDestroyBean {
void i1() {
void init() {
}
void i2() {
void init2() {
}
void d1() {
void destroy() {
}
void d2() {
void destroy2() {
}
}

View File

@ -143,6 +143,7 @@ class InitDestroyMethodLifecycleTests {
assertThat(bean.initMethods).as("init-methods").containsExactly(
"PackagePrivateInitDestroyBean.postConstruct",
"SubPackagePrivateInitDestroyBean.postConstruct",
"InitializingBean.afterPropertiesSet",
"initMethod"
);
@ -150,6 +151,7 @@ class InitDestroyMethodLifecycleTests {
assertThat(bean.destroyMethods).as("destroy-methods").containsExactly(
"SubPackagePrivateInitDestroyBean.preDestroy",
"PackagePrivateInitDestroyBean.preDestroy",
"DisposableBean.destroy",
"destroyMethod"
);
}
@ -191,12 +193,12 @@ class InitDestroyMethodLifecycleTests {
InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
this.initMethods.add("InitializingBean.afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
public void destroy() {
this.destroyMethods.add("DisposableBean.destroy");
}
}
@ -206,11 +208,11 @@ class InitDestroyMethodLifecycleTests {
final List<String> initMethods = new ArrayList<>();
final List<String> destroyMethods = new ArrayList<>();
public void customInit() throws Exception {
public void customInit() {
this.initMethods.add("customInit");
}
public void customDestroy() throws Exception {
public void customDestroy() {
this.destroyMethods.add("customDestroy");
}
}
@ -218,12 +220,12 @@ class InitDestroyMethodLifecycleTests {
static class CustomAnnotatedPrivateInitDestroyBean extends CustomInitializingDisposableBean {
@PostConstruct
private void customInit1() throws Exception {
private void customInit1() {
this.initMethods.add("@PostConstruct.privateCustomInit1");
}
@PreDestroy
private void customDestroy1() throws Exception {
private void customDestroy1() {
this.destroyMethods.add("@PreDestroy.privateCustomDestroy1");
}
}
@ -232,13 +234,13 @@ class InitDestroyMethodLifecycleTests {
@PostConstruct
@SuppressWarnings("unused")
private void customInit1() throws Exception {
private void customInit1() {
this.initMethods.add("@PostConstruct.sameNameCustomInit1");
}
@PreDestroy
@SuppressWarnings("unused")
private void customDestroy1() throws Exception {
private void customDestroy1() {
this.destroyMethods.add("@PreDestroy.sameNameCustomDestroy1");
}
}
@ -247,12 +249,12 @@ class InitDestroyMethodLifecycleTests {
implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
this.initMethods.add("afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
public void destroy() {
this.destroyMethods.add("destroy");
}
}
@ -260,12 +262,12 @@ class InitDestroyMethodLifecycleTests {
static class CustomAnnotatedInitDestroyBean extends CustomInitializingDisposableBean {
@PostConstruct
public void postConstruct() throws Exception {
public void postConstruct() {
this.initMethods.add("postConstruct");
}
@PreDestroy
public void preDestroy() throws Exception {
public void preDestroy() {
this.destroyMethods.add("preDestroy");
}
}
@ -274,13 +276,13 @@ class InitDestroyMethodLifecycleTests {
@PostConstruct
@Override
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
this.initMethods.add("@PostConstruct.afterPropertiesSet");
}
@PreDestroy
@Override
public void destroy() throws Exception {
public void destroy() {
this.destroyMethods.add("@PreDestroy.destroy");
}
}
@ -292,18 +294,29 @@ class InitDestroyMethodLifecycleTests {
@PostConstruct
@Override
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
this.initMethods.add("afterPropertiesSet");
}
@PreDestroy
@Override
public void destroy() throws Exception {
public void destroy() {
this.destroyMethods.add("destroy");
}
}
static class SubPackagePrivateInitDestroyBean extends PackagePrivateInitDestroyBean {
static class SubPackagePrivateInitDestroyBean extends PackagePrivateInitDestroyBean
implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() {
this.initMethods.add("InitializingBean.afterPropertiesSet");
}
@Override
public void destroy() {
this.destroyMethods.add("DisposableBean.destroy");
}
@PostConstruct
void postConstruct() {