Remove instance suppliers in bean definitions

Remove instance suppliers in bean definitions and depend instead
on reflection. This allows the AOT engine to correctly process
the definitions.

Fixes gh-33763
pull/33886/head
Moritz Halbritter 2 years ago committed by Phillip Webb
parent 71efc55bf9
commit ae79c60619

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,8 +16,6 @@
package org.springframework.boot.autoconfigure.web.reactive; package org.springframework.boot.autoconfigure.web.reactive;
import java.util.function.Supplier;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
@ -102,14 +100,13 @@ public class ReactiveWebServerFactoryAutoConfiguration {
return; return;
} }
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class, WebServerFactoryCustomizerBeanPostProcessor.class);
WebServerFactoryCustomizerBeanPostProcessor::new);
} }
private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name,
Class<T> beanClass, Supplier<T> instanceSupplier) { Class<T> beanClass) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier); RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true); beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition); registry.registerBeanDefinition(name, beanDefinition);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,8 +16,6 @@
package org.springframework.boot.autoconfigure.web.servlet; package org.springframework.boot.autoconfigure.web.servlet;
import java.util.function.Supplier;
import jakarta.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletRequest;
@ -139,16 +137,15 @@ public class ServletWebServerFactoryAutoConfiguration {
return; return;
} }
registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class, WebServerFactoryCustomizerBeanPostProcessor.class);
WebServerFactoryCustomizerBeanPostProcessor::new);
registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new); ErrorPageRegistrarBeanPostProcessor.class);
} }
private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, private <T> void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name,
Class<T> beanClass, Supplier<T> instanceSupplier) { Class<T> beanClass) {
if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, instanceSupplier); RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true); beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition); registry.registerBeanDefinition(name, beanDefinition);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -81,8 +81,7 @@ public class BoundConfigurationProperties {
static void register(BeanDefinitionRegistry registry) { static void register(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "Registry must not be null"); Assert.notNull(registry, "Registry must not be null");
if (!registry.containsBeanDefinition(BEAN_NAME)) { if (!registry.containsBeanDefinition(BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(BoundConfigurationProperties.class)
.genericBeanDefinition(BoundConfigurationProperties.class, BoundConfigurationProperties::new)
.getBeanDefinition(); .getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, definition); registry.registerBeanDefinition(BEAN_NAME, definition);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2022 the original author or authors. * Copyright 2012-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -50,6 +50,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.PropertySources; import org.springframework.core.env.PropertySources;
import org.springframework.util.Assert;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -64,8 +65,6 @@ class ConfigurationPropertiesBinder {
private static final String BEAN_NAME = "org.springframework.boot.context.internalConfigurationPropertiesBinder"; private static final String BEAN_NAME = "org.springframework.boot.context.internalConfigurationPropertiesBinder";
private static final String FACTORY_BEAN_NAME = "org.springframework.boot.context.internalConfigurationPropertiesBinderFactory";
private static final String VALIDATOR_BEAN_NAME = EnableConfigurationProperties.VALIDATOR_BEAN_NAME; private static final String VALIDATOR_BEAN_NAME = EnableConfigurationProperties.VALIDATOR_BEAN_NAME;
private final ApplicationContext applicationContext; private final ApplicationContext applicationContext;
@ -189,18 +188,9 @@ class ConfigurationPropertiesBinder {
} }
static void register(BeanDefinitionRegistry registry) { static void register(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(FACTORY_BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder
.rootBeanDefinition(ConfigurationPropertiesBinder.Factory.class).getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ConfigurationPropertiesBinder.FACTORY_BEAN_NAME, definition);
}
if (!registry.containsBeanDefinition(BEAN_NAME)) { if (!registry.containsBeanDefinition(BEAN_NAME)) {
BeanDefinition definition = BeanDefinitionBuilder BeanDefinition definition = BeanDefinitionBuilder
.rootBeanDefinition(ConfigurationPropertiesBinder.class, .rootBeanDefinition(ConfigurationPropertiesBinderFactory.class).getBeanDefinition();
() -> ((BeanFactory) registry)
.getBean(FACTORY_BEAN_NAME, ConfigurationPropertiesBinder.Factory.class).create())
.getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ConfigurationPropertiesBinder.BEAN_NAME, definition); registry.registerBeanDefinition(ConfigurationPropertiesBinder.BEAN_NAME, definition);
} }
@ -211,44 +201,49 @@ class ConfigurationPropertiesBinder {
} }
/** /**
* Factory bean used to create the {@link ConfigurationPropertiesBinder}. The bean * {@link BindHandler} to deal with
* needs to be {@link ApplicationContextAware} since we can't directly inject an * {@link ConfigurationProperties @ConfigurationProperties} concerns.
* {@link ApplicationContext} into the constructor without causing eager
* {@link FactoryBean} initialization.
*/ */
static class Factory implements ApplicationContextAware { private static class ConfigurationPropertiesBindHandler extends AbstractBindHandler {
private ApplicationContext applicationContext; ConfigurationPropertiesBindHandler(BindHandler handler) {
super(handler);
}
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {
this.applicationContext = applicationContext; return isConfigurationProperties(target.getType().resolve())
? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target;
} }
ConfigurationPropertiesBinder create() { private boolean isConfigurationProperties(Class<?> target) {
return new ConfigurationPropertiesBinder(this.applicationContext); return target != null && MergedAnnotations.from(target).isPresent(ConfigurationProperties.class);
} }
} }
/** /**
* {@link BindHandler} to deal with * {@link FactoryBean} to create the {@link ConfigurationPropertiesBinder}.
* {@link ConfigurationProperties @ConfigurationProperties} concerns.
*/ */
private static class ConfigurationPropertiesBindHandler extends AbstractBindHandler { static class ConfigurationPropertiesBinderFactory
implements FactoryBean<ConfigurationPropertiesBinder>, ApplicationContextAware {
ConfigurationPropertiesBindHandler(BindHandler handler) { private ConfigurationPropertiesBinder binder;
super(handler);
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.binder = (this.binder != null) ? this.binder : new ConfigurationPropertiesBinder(applicationContext);
} }
@Override @Override
public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) { public Class<?> getObjectType() {
return isConfigurationProperties(target.getType().resolve()) return ConfigurationPropertiesBinder.class;
? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target;
} }
private boolean isConfigurationProperties(Class<?> target) { @Override
return target != null && MergedAnnotations.from(target).isPresent(ConfigurationProperties.class); public ConfigurationPropertiesBinder getObject() throws Exception {
Assert.state(this.binder != null, "Binder was not created due to missing setApplicationContext call");
return this.binder;
} }
} }

Loading…
Cancel
Save