25
25
import org .springframework .aot .BuildContext ;
26
26
import org .springframework .aot .SourceFiles ;
27
27
import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
28
+ import org .springframework .boot .DefaultBootstrapContext ;
29
+ import org .springframework .boot .SpringApplication ;
30
+ import org .springframework .boot .WebApplicationType ;
31
+ import org .springframework .boot .context .config .ConfigDataEnvironmentPostProcessor ;
32
+ import org .springframework .boot .context .properties .source .ConfigurationPropertySources ;
33
+ import org .springframework .boot .convert .ApplicationConversionService ;
34
+ import org .springframework .boot .logging .DeferredLogs ;
28
35
import org .springframework .boot .web .reactive .context .AnnotationConfigReactiveWebServerApplicationContext ;
36
+ import org .springframework .boot .web .reactive .context .StandardReactiveWebEnvironment ;
29
37
import org .springframework .boot .web .servlet .context .AnnotationConfigServletWebServerApplicationContext ;
30
38
import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
31
39
import org .springframework .context .annotation .BuildTimeBeanDefinitionsRegistrar ;
32
40
import org .springframework .context .bootstrap .generator .BootstrapGenerationResult ;
33
41
import org .springframework .context .bootstrap .generator .ContextBootstrapGenerator ;
34
42
import org .springframework .context .support .GenericApplicationContext ;
35
- import org .springframework .core .env .ConfigurableEnvironment ;
36
43
import org .springframework .core .env .PropertiesPropertySource ;
37
44
import org .springframework .core .env .StandardEnvironment ;
38
- import org .springframework .core .type .classreading .ClassDescriptor ;
39
- import org .springframework .core .type .classreading .TypeSystem ;
45
+ import org .springframework .core .io .ResourceLoader ;
40
46
import org .springframework .nativex .AotOptions ;
41
47
import org .springframework .util .ClassUtils ;
48
+ import org .springframework .web .context .support .StandardServletEnvironment ;
42
49
43
50
/**
44
51
* @author Brian Clozel
48
55
public class ContextBootstrapContributor implements BootstrapContributor {
49
56
50
57
// Copied from Spring Boot WebApplicationType
51
- private static final String [] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet" ,
52
- "org.springframework.web.context.ConfigurableWebApplicationContext" };
58
+ private static final String [] SERVLET_INDICATOR_CLASSES = {"javax.servlet.Servlet" ,
59
+ "org.springframework.web.context.ConfigurableWebApplicationContext" };
60
+
53
61
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet" ;
62
+
54
63
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler" ;
64
+
55
65
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer" ;
56
66
57
67
private static final Log logger = LogFactory .getLog (ContextBootstrapContributor .class );
58
68
59
69
@ Override
60
70
public void contribute (BuildContext context , AotOptions aotOptions ) {
61
- TypeSystem typeSystem = context .getTypeSystem ();
62
- ClassLoader classLoader = typeSystem .getResourceLoader ().getClassLoader ();
71
+ ResourceLoader resourceLoader = context .getTypeSystem ().getResourceLoader ();
72
+ ClassLoader classLoader = resourceLoader .getClassLoader ();
73
+ Class <?> mainClass ;
74
+ String mainClassName = context .getMainClass ();
75
+ try {
76
+ logger .info ("Detected main class: " + mainClassName );
77
+ mainClass = ClassUtils .forName (mainClassName , classLoader );
78
+ }
79
+ catch (ClassNotFoundException exc ) {
80
+ throw new IllegalStateException ("Could not load main class" + mainClassName , exc );
81
+ }
63
82
64
- // TODO: detect correct type of application context
65
- GenericApplicationContext applicationContext = createApplicationContext (typeSystem );
66
- applicationContext .setResourceLoader (typeSystem .getResourceLoader ());
83
+ WebApplicationType webApplicationType = deduceWebApplicationType (classLoader );
84
+ GenericApplicationContext applicationContext = createApplicationContext (webApplicationType );
85
+ applicationContext .setResourceLoader (resourceLoader );
86
+
87
+ StandardEnvironment environment = createEnvironment (webApplicationType );
88
+ configureEnvironment (environment , resourceLoader , mainClass );
67
89
68
- // TODO: pre-compute environment from properties?
69
- ConfigurableEnvironment environment = new StandardEnvironment ();
70
- Properties properties = new Properties ();
71
- properties .put ("spring.aop.proxy-target-class" , "false" ); // Not supported in native images
72
- properties .put ("spring.cloud.refresh.enabled" , "false" ); // Sampler is a class and can't be proxied
73
- properties .put ("spring.sleuth.async.enabled" , "false" ); // Too much proxy created
74
- properties .put ("spring.devtools.restart.enabled" , "false" ); // Deactivate dev tools
75
- environment .getPropertySources ().addFirst (new PropertiesPropertySource ("native" , properties ));
76
90
applicationContext .setEnvironment (environment );
91
+ applicationContext .registerBean (mainClass );
77
92
78
- // TODO: auto-detect main class
79
- String mainClassName = context .getMainClass ();
80
- if (mainClassName != null ) {
81
- ClassDescriptor mainClass = typeSystem .resolveClass (mainClassName );
82
- logger .info ("Detected main class: " + mainClass .getCanonicalClassName ());
83
- try {
84
- applicationContext .registerBean (ClassUtils .forName (mainClass .getCanonicalClassName (), classLoader ));
85
- }
86
- catch (ClassNotFoundException exc ) {
87
- throw new IllegalStateException ("Could not load main class" + mainClass .getCanonicalClassName (), exc );
88
- }
89
- }
90
93
ConfigurableListableBeanFactory beanFactory = new BuildTimeBeanDefinitionsRegistrar ().processBeanDefinitions (applicationContext );
91
94
ContextBootstrapGenerator bootstrapGenerator = new ContextBootstrapGenerator (classLoader );
92
95
BootstrapGenerationResult bootstrapGenerationResult = bootstrapGenerator .generateBootstrapClass (beanFactory , "org.springframework.aot" );
93
96
bootstrapGenerationResult .getSourceFiles ().forEach (javaFile -> context .addSourceFiles (SourceFiles .fromJavaFile (javaFile )));
94
97
context .describeReflection ((reflectionDescriptor ) -> bootstrapGenerationResult .getClassDescriptors ().forEach (reflectionDescriptor ::merge ));
95
98
}
96
99
100
+ private void configureEnvironment (StandardEnvironment environment , ResourceLoader resourceLoader , Class <?> mainClass ) {
101
+ environment .setConversionService (new ApplicationConversionService ());
102
+ ConfigurationPropertySources .attach (environment );
103
+ ConfigDataEnvironmentPostProcessor configDataEnvironmentPostProcessor =
104
+ new ConfigDataEnvironmentPostProcessor (new DeferredLogs (), new DefaultBootstrapContext ());
105
+
106
+ SpringApplication application = new SpringApplication (resourceLoader , mainClass );
107
+ configDataEnvironmentPostProcessor .postProcessEnvironment (environment , application );
108
+
109
+ Properties properties = new Properties ();
110
+ properties .put ("spring.aop.proxy-target-class" , "false" ); // Not supported in native images
111
+ properties .put ("spring.cloud.refresh.enabled" , "false" ); // Sampler is a class and can't be proxied
112
+ properties .put ("spring.sleuth.async.enabled" , "false" ); // Too much proxy created
113
+ properties .put ("spring.devtools.restart.enabled" , "false" ); // Deactivate dev tools
114
+ environment .getPropertySources ().addFirst (new PropertiesPropertySource ("native" , properties ));
115
+ }
116
+
97
117
// TODO Avoid duplication with WebApplicationType and SpringAotApplication.AOT_FACTORY
98
- private GenericApplicationContext createApplicationContext (TypeSystem typeSystem ) {
99
- if (typeSystem .resolveClass (WEBFLUX_INDICATOR_CLASS ) != null && typeSystem .resolveClass (WEBMVC_INDICATOR_CLASS ) == null
100
- && typeSystem .resolveClass (JERSEY_INDICATOR_CLASS ) == null ) {
101
- return ReactiveContextDelegate .createApplicationContext ();
118
+ private GenericApplicationContext createApplicationContext (WebApplicationType webApplicationType ) {
119
+ switch (webApplicationType ) {
120
+ case REACTIVE :
121
+ return ReactiveContextDelegate .createApplicationContext ();
122
+ case SERVLET :
123
+ return ServletContextDelegate .createApplicationContext ();
124
+ }
125
+ return new AnnotationConfigApplicationContext ();
126
+ }
127
+
128
+ private StandardEnvironment createEnvironment (WebApplicationType webApplicationType ) {
129
+ switch (webApplicationType ) {
130
+ case SERVLET :
131
+ return ServletEnvironmentDelegate .createServletEnvironment ();
132
+ case REACTIVE :
133
+ return new StandardReactiveWebEnvironment ();
134
+ default :
135
+ return new StandardEnvironment ();
136
+ }
137
+ }
138
+
139
+ private WebApplicationType deduceWebApplicationType (ClassLoader classLoader ) {
140
+ if (ClassUtils .isPresent (WEBFLUX_INDICATOR_CLASS , classLoader ) && !ClassUtils .isPresent (WEBMVC_INDICATOR_CLASS , classLoader )
141
+ && !ClassUtils .isPresent (JERSEY_INDICATOR_CLASS , classLoader )) {
142
+ return WebApplicationType .REACTIVE ;
102
143
}
103
144
for (String className : SERVLET_INDICATOR_CLASSES ) {
104
- if (typeSystem . resolveClass (className ) == null ) {
105
- return new AnnotationConfigApplicationContext () ;
145
+ if (! ClassUtils . isPresent (className , classLoader ) ) {
146
+ return WebApplicationType . NONE ;
106
147
}
107
148
}
108
- return ServletContextDelegate . createApplicationContext () ;
149
+ return WebApplicationType . SERVLET ;
109
150
}
110
151
111
152
// To avoid NoClassDefFoundError:
@@ -116,6 +157,14 @@ public static GenericApplicationContext createApplicationContext() {
116
157
}
117
158
}
118
159
160
+ // To avoid NoClassDefFoundError:
161
+ static class ServletEnvironmentDelegate {
162
+
163
+ public static StandardEnvironment createServletEnvironment () {
164
+ return new StandardServletEnvironment ();
165
+ }
166
+ }
167
+
119
168
// To avoid NoClassDefFoundError:
120
169
static class ReactiveContextDelegate {
121
170
0 commit comments