Avoid using reflection with manual bean definitions

Closes gh-22318
This commit is contained in:
Andy Wilkinson
2020-07-14 12:37:19 +01:00
parent e3b839a48a
commit 2af550ef73
9 changed files with 120 additions and 76 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@ import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.properties.source.ConfigurationProperty;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.context.ApplicationContext;
@@ -81,8 +81,9 @@ public class BoundConfigurationProperties {
static void register(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "Registry must not be null");
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(BoundConfigurationProperties.class);
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(BoundConfigurationProperties.class, BoundConfigurationProperties::new)
.getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, definition);
}

View File

@@ -24,8 +24,8 @@ import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -83,8 +83,8 @@ public class ConfigurationBeanFactoryMetadata implements ApplicationContextAware
static void register(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationBeanFactoryMetadata.class);
BeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(
ConfigurationBeanFactoryMetadata.class, ConfigurationBeanFactoryMetadata::new).getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ConfigurationBeanFactoryMetadata.BEAN_NAME, definition);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,10 @@ import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.properties.bind.BindHandler;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Bindable;
@@ -186,17 +188,20 @@ class ConfigurationPropertiesBinder {
static void register(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(FACTORY_BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBinder.Factory.class);
AbstractBeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(ConfigurationPropertiesBinder.Factory.class,
ConfigurationPropertiesBinder.Factory::new)
.getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(ConfigurationPropertiesBinder.FACTORY_BEAN_NAME, definition);
}
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBinder.class);
AbstractBeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(ConfigurationPropertiesBinder.class,
() -> ((DefaultListableBeanFactory) registry)
.getBean(FACTORY_BEAN_NAME, ConfigurationPropertiesBinder.Factory.class).create())
.getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
definition.setFactoryBeanName(FACTORY_BEAN_NAME);
definition.setFactoryMethodName("create");
registry.registerBeanDefinition(ConfigurationPropertiesBinder.BEAN_NAME, definition);
}
}

View File

@@ -20,8 +20,8 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.properties.ConfigurationPropertiesBean.BindMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@@ -107,8 +107,10 @@ public class ConfigurationPropertiesBindingPostProcessor
public static void register(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "Registry must not be null");
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBindingPostProcessor.class);
BeanDefinition definition = BeanDefinitionBuilder
.genericBeanDefinition(ConfigurationPropertiesBindingPostProcessor.class,
ConfigurationPropertiesBindingPostProcessor::new)
.getBeanDefinition();
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, definition);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,11 +17,12 @@
package org.springframework.boot.web.servlet;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Supplier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@@ -52,20 +53,15 @@ class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
}
private void updatePostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {
BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME);
ValueHolder constructorArguments = definition.getConstructorArgumentValues().getGenericArgumentValue(Set.class);
@SuppressWarnings("unchecked")
Set<String> mergedPackages = (Set<String>) constructorArguments.getValue();
mergedPackages.addAll(packagesToScan);
constructorArguments.setValue(mergedPackages);
ServletComponentRegisteringPostProcessorBeanDefinition definition = (ServletComponentRegisteringPostProcessorBeanDefinition) registry
.getBeanDefinition(BEAN_NAME);
definition.addPackageNames(packagesToScan);
}
private void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packagesToScan);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
ServletComponentRegisteringPostProcessorBeanDefinition definition = new ServletComponentRegisteringPostProcessorBeanDefinition(
packagesToScan);
registry.registerBeanDefinition(BEAN_NAME, definition);
}
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
@@ -83,4 +79,25 @@ class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
return packagesToScan;
}
static final class ServletComponentRegisteringPostProcessorBeanDefinition extends GenericBeanDefinition {
private Set<String> packageNames = new LinkedHashSet<>();
ServletComponentRegisteringPostProcessorBeanDefinition(Collection<String> packageNames) {
setBeanClass(ServletComponentRegisteringPostProcessor.class);
setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
addPackageNames(packageNames);
}
@Override
public Supplier<?> getInstanceSupplier() {
return () -> new ServletComponentRegisteringPostProcessor(this.packageNames);
}
private void addPackageNames(Collection<String> additionalPackageNames) {
this.packageNames.addAll(additionalPackageNames);
}
}
}