Support for pre-generated CGLIB proxy classes (in AOT scenarios)

Includes runtime storing of generated classes to a directory specified by the "cglib.generatedClasses" system property. Avoids lazy CGLIB fast-class generation and replaces generated Enhancer and MethodWrapper key classes with equivalent record types. Introduces support for early type determination in InstantiationStrategy, AopProxy and SmartInstantiationAwareBeanPostProcessor - in order to trigger CGLIB class generation in refreshForAotProcessing (through early determineBeanType calls for bean definitions).

Closes gh-28115
This commit is contained in:
Juergen Hoeller
2022-08-10 23:30:19 +02:00
parent 496b1879ab
commit b31a15851e
25 changed files with 364 additions and 173 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@@ -422,6 +422,11 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
String filename = resource.getFilename();
if (filename != null && filename.contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
// Ignore CGLIB-generated classes in the classpath
continue;
}
if (traceEnabled) {
logger.trace("Scanning " + resource);
}

View File

@@ -123,6 +123,7 @@ class ConfigurationClassEnhancer {
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setAttemptLoad(true);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
@@ -508,6 +509,7 @@ class ConfigurationClassEnhancer {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(factoryBean.getClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setAttemptLoad(true);
enhancer.setCallbackType(MethodInterceptor.class);
// Ideally create enhanced FactoryBean proxy without constructor side effects,

View File

@@ -64,7 +64,6 @@ import org.springframework.context.ApplicationStartupAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
import org.springframework.core.NativeDetector;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.Environment;
@@ -286,11 +285,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
}
@Override
public BeanFactoryInitializationAotContribution processAheadOfTime(
ConfigurableListableBeanFactory beanFactory) {
return (beanFactory.containsBean(IMPORT_REGISTRY_BEAN_NAME)
? new AotContribution(beanFactory) : null);
public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
return (beanFactory.containsBean(IMPORT_REGISTRY_BEAN_NAME) ? new AotContribution(beanFactory) : null);
}
/**
@@ -452,7 +448,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
configBeanDefs.put(beanName, abd);
}
}
if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
enhanceConfigClasses.end();
return;
@@ -514,8 +510,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private static final String BEAN_FACTORY_VARIABLE = BeanFactoryInitializationCode.BEAN_FACTORY_VARIABLE;
private static final ParameterizedTypeName STRING_STRING_MAP = ParameterizedTypeName
.get(Map.class, String.class, String.class);
private static final ParameterizedTypeName STRING_STRING_MAP =
ParameterizedTypeName.get(Map.class, String.class, String.class);
private static final String MAPPINGS_VARIABLE = "mappings";
@@ -523,15 +519,12 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private static final String BEAN_NAME = "org.springframework.context.annotation.internalImportAwareAotProcessor";
private final ConfigurableListableBeanFactory beanFactory;
public AotContribution(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void applyTo(GenerationContext generationContext,
BeanFactoryInitializationCode beanFactoryInitializationCode) {
@@ -550,11 +543,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
}
}
private void generateAddPostProcessorMethod(MethodSpec.Builder method,
Map<String, String> mappings) {
method.addJavadoc(
"Add ImportAwareBeanPostProcessor to support ImportAware beans");
private void generateAddPostProcessorMethod(MethodSpec.Builder method, Map<String, String> mappings) {
method.addJavadoc("Add ImportAwareBeanPostProcessor to support ImportAware beans");
method.addModifiers(Modifier.PRIVATE);
method.addParameter(DefaultListableBeanFactory.class, BEAN_FACTORY_VARIABLE);
method.addCode(generateAddPostProcessorCode(mappings));

View File

@@ -18,6 +18,7 @@ package org.springframework.context.support;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -29,6 +30,7 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -408,8 +410,29 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
invokeBeanFactoryPostProcessors(this.beanFactory);
this.beanFactory.freezeConfiguration();
PostProcessorRegistrationDelegate.invokeMergedBeanDefinitionPostProcessors(this.beanFactory);
preDetermineBeanTypes();
}
/**
* Pre-determine bean types in order to trigger early proxy class creation.
* @see org.springframework.beans.factory.BeanFactory#getType
* @see SmartInstantiationAwareBeanPostProcessor#determineBeanType
*/
private void preDetermineBeanTypes() {
List<SmartInstantiationAwareBeanPostProcessor> bpps =
PostProcessorRegistrationDelegate.loadBeanPostProcessors(
this.beanFactory, SmartInstantiationAwareBeanPostProcessor.class);
for (String beanName : this.beanFactory.getBeanDefinitionNames()) {
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType != null) {
for (SmartInstantiationAwareBeanPostProcessor bpp : bpps) {
beanType = bpp.determineBeanType(beanType, beanName);
}
}
}
}
//---------------------------------------------------------------------
// Convenient methods for registering individual beans
//---------------------------------------------------------------------