Provide a flag to disable SpEL support

This commit introduces a spring.spel.ignore system property
which when set to true avoid initializing SpEL infrastructure.

A typical use case is optimizing GraalVM native image footprint
for applications not using SpEL. In order to be effective, those
classes should be initialized at build time:

- org.springframework.context.support.AbstractApplicationContext
- org.springframework.core.SpringProperties
- org.springframework.context.event.EventListenerMethodProcessor

Closes gh-25153
This commit is contained in:
Sébastien Deleuze 2020-06-18 15:57:58 +02:00
parent dc3801043f
commit 1c75f95be0
3 changed files with 36 additions and 5 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 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.
@ -142,7 +142,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
/** /**
* Initialize this instance. * Initialize this instance.
*/ */
void init(ApplicationContext applicationContext, EventExpressionEvaluator evaluator) { void init(ApplicationContext applicationContext, @Nullable EventExpressionEvaluator evaluator) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.evaluator = evaluator; this.evaluator = evaluator;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 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.
@ -40,6 +40,7 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.MethodIntrospector; import org.springframework.core.MethodIntrospector;
import org.springframework.core.SpringProperties;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
@ -56,6 +57,7 @@ import org.springframework.util.CollectionUtils;
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sebastien Deleuze
* @since 4.2 * @since 4.2
* @see EventListenerFactory * @see EventListenerFactory
* @see DefaultEventListenerFactory * @see DefaultEventListenerFactory
@ -63,6 +65,14 @@ import org.springframework.util.CollectionUtils;
public class EventListenerMethodProcessor public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor { implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
/**
* Boolean flag controlled by a {@code spring.spel.ignore} system property that instructs Spring to
* ignore SpEL, i.e. to not initialize the SpEL infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
protected final Log logger = LogFactory.getLog(getClass()); protected final Log logger = LogFactory.getLog(getClass());
@Nullable @Nullable
@ -74,11 +84,21 @@ public class EventListenerMethodProcessor
@Nullable @Nullable
private List<EventListenerFactory> eventListenerFactories; private List<EventListenerFactory> eventListenerFactories;
private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator(); @Nullable
private final EventExpressionEvaluator evaluator;
private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64)); private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
public EventListenerMethodProcessor() {
if (shouldIgnoreSpel) {
this.evaluator = null;
}
else {
this.evaluator = new EventExpressionEvaluator();
}
}
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) { public void setApplicationContext(ApplicationContext applicationContext) {
Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext, Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext,

View File

@ -67,6 +67,7 @@ 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.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.SpringProperties;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
@ -117,6 +118,7 @@ import org.springframework.util.ReflectionUtils;
* @author Mark Fisher * @author Mark Fisher
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Sam Brannen * @author Sam Brannen
* @author Sebastien Deleuze
* @since January 21, 2001 * @since January 21, 2001
* @see #refreshBeanFactory * @see #refreshBeanFactory
* @see #getBeanFactory * @see #getBeanFactory
@ -152,6 +154,13 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
*/ */
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster"; public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
/**
* Boolean flag controlled by a {@code spring.spel.ignore} system property that instructs Spring to
* ignore SpEL, i.e. to not initialize the SpEL infrastructure.
* <p>The default is "false".
*/
private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore");
static { static {
// Eagerly load the ContextClosedEvent class to avoid weird classloader issues // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
@ -647,7 +656,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc. // Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanClassLoader(getClassLoader());
if (!shouldIgnoreSpel) {
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks. // Configure the bean factory with context callbacks.