Browse Source

Introduce a NativeDetector utility class

With the introduction of the -H:+InlineBeforeAnalysis native image
compiler flag in GraalVM 21.0.0, it is now possible to use an utility method and get code
removal at build time.

This flag will be enabled as of Spring Native 0.9.0.

closes gh-25795
pull/26556/head
Sébastien Deleuze 4 years ago
parent
commit
3524401bf1
  1. 12
      spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java
  2. 11
      spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  3. 12
      spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
  4. 18
      spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
  5. 12
      spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java
  6. 39
      spring-core/src/main/java/org/springframework/core/NativeDetector.java
  7. 11
      spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java

12
spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2021 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.
@ -20,6 +20,7 @@ import java.io.Serializable;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy; import org.springframework.aop.SpringProxy;
import org.springframework.core.NativeDetector;
/** /**
* Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy * Default {@link AopProxyFactory} implementation, creating either a CGLIB proxy
@ -47,17 +48,10 @@ import org.springframework.aop.SpringProxy;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
@Override @Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!IN_NATIVE_IMAGE && if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass(); Class<?> targetClass = config.getTargetClass();
if (targetClass == null) { if (targetClass == null) {

11
spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

@ -73,6 +73,7 @@ import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.NamedThreadLocal; import org.springframework.core.NamedThreadLocal;
import org.springframework.core.NativeDetector;
import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PriorityOrdered; import org.springframework.core.PriorityOrdered;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
@ -123,14 +124,6 @@ import org.springframework.util.StringUtils;
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory { implements AutowireCapableBeanFactory {
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
/** Strategy for creating bean instances. */ /** Strategy for creating bean instances. */
private InstantiationStrategy instantiationStrategy; private InstantiationStrategy instantiationStrategy;
@ -184,7 +177,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class);
if (IN_NATIVE_IMAGE) { if (NativeDetector.inNativeImage()) {
this.instantiationStrategy = new SimpleInstantiationStrategy(); this.instantiationStrategy = new SimpleInstantiationStrategy();
} }
else { else {

12
spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 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.
@ -52,6 +52,7 @@ import org.springframework.context.ApplicationStartupAware;
import org.springframework.context.EnvironmentAware; import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware; import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration; import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration;
import org.springframework.core.NativeDetector;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered; import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@ -104,13 +105,6 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private static final String IMPORT_REGISTRY_BEAN_NAME = private static final String IMPORT_REGISTRY_BEAN_NAME =
ConfigurationClassPostProcessor.class.getName() + ".importRegistry"; ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
private final Log logger = LogFactory.getLog(getClass()); private final Log logger = LogFactory.getLog(getClass());
@ -427,7 +421,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
} }
} }
if (configBeanDefs.isEmpty() || IN_NATIVE_IMAGE) { if (configBeanDefs.isEmpty() || NativeDetector.inNativeImage()) {
// nothing to enhance -> return immediately // nothing to enhance -> return immediately
enhanceConfigClasses.end(); enhanceConfigClasses.end();
return; return;

18
spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 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.
@ -66,6 +66,7 @@ import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.expression.StandardBeanExpressionResolver; import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.context.weaving.LoadTimeWeaverAware; import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor; import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
import org.springframework.core.NativeDetector;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.SpringProperties; import org.springframework.core.SpringProperties;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
@ -164,13 +165,6 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
*/ */
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore"); private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
static { static {
// Eagerly load the ContextClosedEvent class to avoid weird classloader issues // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
@ -711,7 +705,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found. // Detect a LoadTimeWeaver and prepare for weaving, if found.
if (!IN_NATIVE_IMAGE && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching. // Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
@ -752,7 +746,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
} }
@ -943,7 +937,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
publishEvent(new ContextRefreshedEvent(this)); publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active. // Participate in LiveBeansView MBean, if active.
if (!IN_NATIVE_IMAGE) { if (!NativeDetector.inNativeImage()) {
LiveBeansView.registerApplicationContext(this); LiveBeansView.registerApplicationContext(this);
} }
} }
@ -1054,7 +1048,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
logger.debug("Closing " + this); logger.debug("Closing " + this);
} }
if (!IN_NATIVE_IMAGE) { if (!NativeDetector.inNativeImage()) {
LiveBeansView.unregisterApplicationContext(this); LiveBeansView.unregisterApplicationContext(this);
} }

12
spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 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.
@ -39,15 +39,9 @@ package org.springframework.core;
*/ */
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer { public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
public DefaultParameterNameDiscoverer() { public DefaultParameterNameDiscoverer() {
if (KotlinDetector.isKotlinReflectPresent() && !IN_NATIVE_IMAGE) { // TODO Remove this conditional inclusion when upgrading to Kotlin 1.5, see https://youtrack.jetbrains.com/issue/KT-44594
if (KotlinDetector.isKotlinReflectPresent() && !NativeDetector.inNativeImage()) {
addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
} }
addDiscoverer(new StandardReflectionParameterNameDiscoverer()); addDiscoverer(new StandardReflectionParameterNameDiscoverer());

39
spring-core/src/main/java/org/springframework/core/NativeDetector.java

@ -0,0 +1,39 @@
/*
* Copyright 2002-2021 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core;
/**
* A common delegate for detecting a GraalVM native image environment.
*
* <p>Requires using the {@code -H:+InlineBeforeAnalysis} native image compiler flag in order to allow code removal at
* build time.
*
* @author Sebastien Deleuze
* @since 5.3.4
*/
public abstract class NativeDetector {
// See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
private static final boolean imageCode = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
/**
* Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}.
*/
public static boolean inNativeImage() {
return imageCode;
}
}

11
spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 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.
@ -59,13 +59,6 @@ final class SerializableTypeWrapper {
private static final Class<?>[] SUPPORTED_SERIALIZABLE_TYPES = { private static final Class<?>[] SUPPORTED_SERIALIZABLE_TYPES = {
GenericArrayType.class, ParameterizedType.class, TypeVariable.class, WildcardType.class}; GenericArrayType.class, ParameterizedType.class, TypeVariable.class, WildcardType.class};
/**
* Whether this environment lives within a native image.
* Exposed as a private static field rather than in a {@code NativeImageDetector.inNativeImage()} static method due to https://github.com/oracle/graal/issues/2594.
* @see <a href="https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java">ImageInfo.java</a>
*/
private static final boolean IN_NATIVE_IMAGE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
static final ConcurrentReferenceHashMap<Type, Type> cache = new ConcurrentReferenceHashMap<>(256); static final ConcurrentReferenceHashMap<Type, Type> cache = new ConcurrentReferenceHashMap<>(256);
@ -116,7 +109,7 @@ final class SerializableTypeWrapper {
// No serializable type wrapping necessary (e.g. for java.lang.Class) // No serializable type wrapping necessary (e.g. for java.lang.Class)
return providedType; return providedType;
} }
if (IN_NATIVE_IMAGE || !Serializable.class.isAssignableFrom(Class.class)) { if (NativeDetector.inNativeImage() || !Serializable.class.isAssignableFrom(Class.class)) {
// Let's skip any wrapping attempts if types are generally not serializable in // Let's skip any wrapping attempts if types are generally not serializable in
// the current runtime environment (even java.lang.Class itself, e.g. on GraalVM native images) // the current runtime environment (even java.lang.Class itself, e.g. on GraalVM native images)
return providedType; return providedType;

Loading…
Cancel
Save