Polishing

This commit is contained in:
Sam Brannen 2023-06-22 13:48:07 +02:00
parent 9b5cbc1334
commit 32f061a3e0
4 changed files with 100 additions and 78 deletions

View File

@ -1794,10 +1794,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). * and a chance to know about its owning bean factory (this object).
* This means checking whether the bean implements InitializingBean or defines * <p>This means checking whether the bean implements {@link InitializingBean}
* a custom init method, and invoking the necessary callback(s) if it does. * 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 beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize * @param bean the new bean instance we may need to initialize
* @param mbd the merged bean definition that the bean was created with * @param mbd the merged bean definition that the bean was created with
@ -1860,7 +1861,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
} }
if (logger.isTraceEnabled()) { 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()); Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod, bean.getClass());

View File

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

View File

@ -28,6 +28,8 @@ import java.util.function.Supplier;
import javax.lang.model.element.Modifier; 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.junit.jupiter.api.Test;
import org.springframework.aot.generate.GeneratedClass; import org.springframework.aot.generate.GeneratedClass;
@ -61,6 +63,8 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Olga Maciaszek-Sharma * @author Olga Maciaszek-Sharma
* @author Sam Brannen
* @since 6.0
*/ */
class BeanDefinitionPropertiesCodeGeneratorTests { class BeanDefinitionPropertiesCodeGeneratorTests {
@ -212,56 +216,6 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
compile((actual, compiled) -> assertThat(actual.getRole()).isEqualTo(999)); 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 @Test
void constructorArgumentValuesWhenValues() { void constructorArgumentValuesWhenValues() {
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, String.class); 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) { private void compile(BiConsumer<RootBeanDefinition, Compiled> result) {
compile(attribute -> true, result); compile(attribute -> true, result);
} }
@ -450,16 +458,16 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
static class InitDestroyBean { 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( assertThat(bean.initMethods).as("init-methods").containsExactly(
"PackagePrivateInitDestroyBean.postConstruct", "PackagePrivateInitDestroyBean.postConstruct",
"SubPackagePrivateInitDestroyBean.postConstruct", "SubPackagePrivateInitDestroyBean.postConstruct",
"InitializingBean.afterPropertiesSet",
"initMethod" "initMethod"
); );
@ -150,6 +151,7 @@ class InitDestroyMethodLifecycleTests {
assertThat(bean.destroyMethods).as("destroy-methods").containsExactly( assertThat(bean.destroyMethods).as("destroy-methods").containsExactly(
"SubPackagePrivateInitDestroyBean.preDestroy", "SubPackagePrivateInitDestroyBean.preDestroy",
"PackagePrivateInitDestroyBean.preDestroy", "PackagePrivateInitDestroyBean.preDestroy",
"DisposableBean.destroy",
"destroyMethod" "destroyMethod"
); );
} }
@ -191,12 +193,12 @@ class InitDestroyMethodLifecycleTests {
InitializingBean, DisposableBean { InitializingBean, DisposableBean {
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() {
this.initMethods.add("InitializingBean.afterPropertiesSet"); this.initMethods.add("InitializingBean.afterPropertiesSet");
} }
@Override @Override
public void destroy() throws Exception { public void destroy() {
this.destroyMethods.add("DisposableBean.destroy"); this.destroyMethods.add("DisposableBean.destroy");
} }
} }
@ -206,11 +208,11 @@ class InitDestroyMethodLifecycleTests {
final List<String> initMethods = new ArrayList<>(); final List<String> initMethods = new ArrayList<>();
final List<String> destroyMethods = new ArrayList<>(); final List<String> destroyMethods = new ArrayList<>();
public void customInit() throws Exception { public void customInit() {
this.initMethods.add("customInit"); this.initMethods.add("customInit");
} }
public void customDestroy() throws Exception { public void customDestroy() {
this.destroyMethods.add("customDestroy"); this.destroyMethods.add("customDestroy");
} }
} }
@ -218,12 +220,12 @@ class InitDestroyMethodLifecycleTests {
static class CustomAnnotatedPrivateInitDestroyBean extends CustomInitializingDisposableBean { static class CustomAnnotatedPrivateInitDestroyBean extends CustomInitializingDisposableBean {
@PostConstruct @PostConstruct
private void customInit1() throws Exception { private void customInit1() {
this.initMethods.add("@PostConstruct.privateCustomInit1"); this.initMethods.add("@PostConstruct.privateCustomInit1");
} }
@PreDestroy @PreDestroy
private void customDestroy1() throws Exception { private void customDestroy1() {
this.destroyMethods.add("@PreDestroy.privateCustomDestroy1"); this.destroyMethods.add("@PreDestroy.privateCustomDestroy1");
} }
} }
@ -232,13 +234,13 @@ class InitDestroyMethodLifecycleTests {
@PostConstruct @PostConstruct
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void customInit1() throws Exception { private void customInit1() {
this.initMethods.add("@PostConstruct.sameNameCustomInit1"); this.initMethods.add("@PostConstruct.sameNameCustomInit1");
} }
@PreDestroy @PreDestroy
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void customDestroy1() throws Exception { private void customDestroy1() {
this.destroyMethods.add("@PreDestroy.sameNameCustomDestroy1"); this.destroyMethods.add("@PreDestroy.sameNameCustomDestroy1");
} }
} }
@ -247,12 +249,12 @@ class InitDestroyMethodLifecycleTests {
implements InitializingBean, DisposableBean { implements InitializingBean, DisposableBean {
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() {
this.initMethods.add("afterPropertiesSet"); this.initMethods.add("afterPropertiesSet");
} }
@Override @Override
public void destroy() throws Exception { public void destroy() {
this.destroyMethods.add("destroy"); this.destroyMethods.add("destroy");
} }
} }
@ -260,12 +262,12 @@ class InitDestroyMethodLifecycleTests {
static class CustomAnnotatedInitDestroyBean extends CustomInitializingDisposableBean { static class CustomAnnotatedInitDestroyBean extends CustomInitializingDisposableBean {
@PostConstruct @PostConstruct
public void postConstruct() throws Exception { public void postConstruct() {
this.initMethods.add("postConstruct"); this.initMethods.add("postConstruct");
} }
@PreDestroy @PreDestroy
public void preDestroy() throws Exception { public void preDestroy() {
this.destroyMethods.add("preDestroy"); this.destroyMethods.add("preDestroy");
} }
} }
@ -274,13 +276,13 @@ class InitDestroyMethodLifecycleTests {
@PostConstruct @PostConstruct
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() {
this.initMethods.add("@PostConstruct.afterPropertiesSet"); this.initMethods.add("@PostConstruct.afterPropertiesSet");
} }
@PreDestroy @PreDestroy
@Override @Override
public void destroy() throws Exception { public void destroy() {
this.destroyMethods.add("@PreDestroy.destroy"); this.destroyMethods.add("@PreDestroy.destroy");
} }
} }
@ -292,18 +294,29 @@ class InitDestroyMethodLifecycleTests {
@PostConstruct @PostConstruct
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() {
this.initMethods.add("afterPropertiesSet"); this.initMethods.add("afterPropertiesSet");
} }
@PreDestroy @PreDestroy
@Override @Override
public void destroy() throws Exception { public void destroy() {
this.destroyMethods.add("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 @PostConstruct
void postConstruct() { void postConstruct() {