This repository has been archived by the owner on Feb 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 354
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic support for parsing the bean definitions at build time
- Loading branch information
Showing
9 changed files
with
230 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
...n/java/org/springframework/context/annotation/AnnotatedMetadataGenericBeanDefinition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package org.springframework.context.annotation; | ||
|
||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; | ||
import org.springframework.beans.factory.support.GenericBeanDefinition; | ||
import org.springframework.core.type.AnnotationMetadata; | ||
import org.springframework.core.type.MethodMetadata; | ||
import org.springframework.core.type.classreading.MetadataReader; | ||
import org.springframework.lang.Nullable; | ||
import org.springframework.util.Assert; | ||
|
||
/** | ||
* A {@link GenericBeanDefinition} that also provides the {@link AnnotatedBeanDefinition} | ||
* contract using ASM only. | ||
* | ||
* @author Stephane Nicoll | ||
*/ | ||
public class AnnotatedMetadataGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition { | ||
|
||
private final AnnotationMetadata metadata; | ||
|
||
public AnnotatedMetadataGenericBeanDefinition(MetadataReader metadataReader) { | ||
Assert.notNull(metadataReader, "MetadataReader must not be null"); | ||
this.metadata = metadataReader.getAnnotationMetadata(); | ||
setBeanClassName(this.metadata.getClassName()); | ||
setResource(metadataReader.getResource()); | ||
} | ||
|
||
@Override | ||
public final AnnotationMetadata getMetadata() { | ||
return this.metadata; | ||
} | ||
|
||
@Override | ||
@Nullable | ||
public MethodMetadata getFactoryMethodMetadata() { | ||
return null; | ||
} | ||
|
||
} |
91 changes: 91 additions & 0 deletions
91
spring-aot/src/main/java/org/springframework/context/build/BuildTimeBeanFactoryProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package org.springframework.context.build; | ||
|
||
import java.io.IOException; | ||
|
||
import org.springframework.beans.factory.BeanDefinitionStoreException; | ||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; | ||
import org.springframework.beans.factory.config.BeanDefinitionHolder; | ||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | ||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; | ||
import org.springframework.beans.factory.support.BeanNameGenerator; | ||
import org.springframework.context.annotation.AnnotatedMetadataGenericBeanDefinition; | ||
import org.springframework.context.annotation.AnnotationBeanNameGenerator; | ||
import org.springframework.context.annotation.ConfigurationClassPostProcessor; | ||
import org.springframework.context.support.GenericApplicationContext; | ||
import org.springframework.core.type.classreading.MetadataReader; | ||
import org.springframework.core.type.classreading.MetadataReaderFactory; | ||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; | ||
import org.springframework.core.type.classreading.TypeDescriptor; | ||
import org.springframework.core.type.classreading.TypeSystem; | ||
|
||
/** | ||
* A prototype of {@link GenericApplicationContext} that is intended to be used at build | ||
* time. | ||
* | ||
* @author Stephane Nicoll | ||
*/ | ||
public class BuildTimeBeanFactoryProvider { | ||
|
||
private final GenericApplicationContext context; | ||
|
||
private final TypeSystem typeSystem; | ||
|
||
private final MetadataReaderFactory metadataReaderFactory; | ||
|
||
private final BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE; | ||
|
||
public BuildTimeBeanFactoryProvider(GenericApplicationContext context, TypeSystem typeSystem) { | ||
this.context = context; | ||
this.typeSystem = typeSystem; | ||
this.metadataReaderFactory = new SimpleMetadataReaderFactory(); | ||
} | ||
|
||
/** | ||
* Register root component classes that are meant to bootstrap the context. | ||
* @param componentClasses the root component classes | ||
*/ | ||
public void register(String... componentClasses) { | ||
for (String componentClass : componentClasses) { | ||
TypeDescriptor componentTypeDescriptor = this.typeSystem.resolve(componentClass); | ||
if (componentTypeDescriptor != null) { | ||
register(componentTypeDescriptor); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Process bean definitions without creating any instance and return the | ||
* {@link ConfigurableListableBeanFactory bean factory}. | ||
* @return the bean factory with the result of the processing | ||
*/ | ||
public ConfigurableListableBeanFactory processBeanDefinitions() { | ||
parseConfigurationClasses(); | ||
return this.context.getBeanFactory(); | ||
} | ||
|
||
private void parseConfigurationClasses() { | ||
ConfigurationClassPostProcessor configurationClassPostProcessor = new ConfigurationClassPostProcessor(); | ||
configurationClassPostProcessor.setApplicationStartup(this.context.getApplicationStartup()); | ||
configurationClassPostProcessor.setBeanClassLoader(this.context.getClassLoader()); | ||
configurationClassPostProcessor.setEnvironment(this.context.getEnvironment()); | ||
configurationClassPostProcessor.setResourceLoader(this.context); | ||
configurationClassPostProcessor.postProcessBeanFactory(this.context.getBeanFactory()); | ||
} | ||
|
||
private void register(TypeDescriptor typeDescriptor) { | ||
MetadataReader metadataReader = getMetadataReader(typeDescriptor); | ||
AnnotatedBeanDefinition beanDefinition = new AnnotatedMetadataGenericBeanDefinition(metadataReader); | ||
String beanName = this.beanNameGenerator.generateBeanName(beanDefinition, this.context); | ||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(beanDefinition, beanName); | ||
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.context); | ||
} | ||
|
||
private MetadataReader getMetadataReader(TypeDescriptor typeDescriptor) { | ||
try { | ||
return this.metadataReaderFactory.getMetadataReader(typeDescriptor.getTypeName()); | ||
} | ||
catch (IOException ex) { | ||
throw new BeanDefinitionStoreException(String.format("Failure while reading metadata for %s.", typeDescriptor), ex); | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
...ot/src/test/java/org/springframework/context/build/BuildTimeBeanFactoryProviderTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.springframework.context.build; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | ||
import org.springframework.context.support.GenericApplicationContext; | ||
import org.springframework.core.io.DefaultResourceLoader; | ||
import org.springframework.core.type.classreading.TypeSystem; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* Tests for {@link BuildTimeBeanFactoryProvider}. | ||
* | ||
* @author Stephane Nicoll | ||
*/ | ||
class BuildTimeBeanFactoryProviderTests { | ||
|
||
private static final String CONFIGURATION_ONE = "org.springframework.context.build.samples.simple.ConfigurationOne"; | ||
|
||
private static final String CONFIGURATION_TWO = "org.springframework.context.build.samples.simple.ConfigurationTwo"; | ||
|
||
private final TypeSystem typeSystem = TypeSystem.getTypeSystem(new DefaultResourceLoader()); | ||
|
||
@Test | ||
void refreshWithRegisteredConfigurationClasses() { | ||
BuildTimeBeanFactoryProvider beanFactoryProvider = forApplicationContext(new GenericApplicationContext()); | ||
beanFactoryProvider.register(CONFIGURATION_ONE, CONFIGURATION_TWO); | ||
ConfigurableListableBeanFactory beanFactory = beanFactoryProvider.processBeanDefinitions(); | ||
assertThat(beanFactory.getBeanDefinitionNames()).containsOnly("configurationOne", | ||
"configurationTwo", "beanOne", "beanTwo"); | ||
} | ||
|
||
@Test | ||
void refreshWithRegisteredConfigurationClassWithImport() { | ||
BuildTimeBeanFactoryProvider context = forApplicationContext(new GenericApplicationContext()); | ||
context.register("org.springframework.context.build.samples.compose.ImportConfiguration"); | ||
ConfigurableListableBeanFactory beanFactory = context.processBeanDefinitions(); | ||
assertThat(beanFactory.getBeanDefinitionNames()).containsOnly("importConfiguration", | ||
CONFIGURATION_ONE, CONFIGURATION_TWO, "beanOne", "beanTwo"); | ||
} | ||
|
||
private BuildTimeBeanFactoryProvider forApplicationContext(GenericApplicationContext context) { | ||
return new BuildTimeBeanFactoryProvider(context, this.typeSystem); | ||
} | ||
|
||
} |
11 changes: 11 additions & 0 deletions
11
.../src/test/java/org/springframework/context/build/samples/compose/ImportConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.springframework.context.build.samples.compose; | ||
|
||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Import; | ||
import org.springframework.context.build.samples.simple.ConfigurationOne; | ||
import org.springframework.context.build.samples.simple.ConfigurationTwo; | ||
|
||
@Configuration(proxyBeanMethods = false) | ||
@Import({ ConfigurationOne.class, ConfigurationTwo.class }) | ||
public class ImportConfiguration { | ||
} |
14 changes: 14 additions & 0 deletions
14
...-aot/src/test/java/org/springframework/context/build/samples/simple/ConfigurationOne.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.springframework.context.build.samples.simple; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration(proxyBeanMethods = false) | ||
public class ConfigurationOne { | ||
|
||
@Bean | ||
String beanOne() { | ||
return "one"; | ||
} | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
...-aot/src/test/java/org/springframework/context/build/samples/simple/ConfigurationTwo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.springframework.context.build.samples.simple; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration(proxyBeanMethods = false) | ||
public class ConfigurationTwo { | ||
|
||
@Bean | ||
String beanTwo() { | ||
return "two"; | ||
} | ||
|
||
} |
8 changes: 8 additions & 0 deletions
8
...g-aot/src/test/java/org/springframework/context/build/samples/simple/SimpleComponent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.springframework.context.build.samples.simple; | ||
|
||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class SimpleComponent { | ||
|
||
} |