Skip to content

Commit 6517517

Browse files
committed
Refactor to lazy Environment creation where possible
This commit avoids eager creation of Environment instances, favoring delegation of already existing Environment objects where possible. For example, FrameworkServlet creates an ApplicationContext; both require a StandardServletEnvironment instance, and prior to this change, two instances were created where one would suffice - indeed these two instances may reasonably be expected to be the same. Now, the FrameworkServlet defers creation of its Environment, allowing users to supply a custom instance via its #setEnvironment method (e.g. within a WebApplicationInitializer); the FrameworkServlet then takes care to delegate that instance to the ApplicationContext created in #createWebApplicationContext. This behavior produces more consistent behavior with regard to delegation of the environment, saves unnecessary cycles by avoiding needless instantiation and calls to methods like StandardServletEnvironment#initPropertySources and leads to better logging output, as the user sees only one Environment created and initialized when working with the FrameworkServlet/DispatcherServlet. This commit also mirrors these changes across the corresponding Portlet* classes. Issue: SPR-9763
1 parent 9f8d219 commit 6517517

File tree

8 files changed

+117
-23
lines changed

8 files changed

+117
-23
lines changed

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import org.springframework.core.PriorityOrdered;
7474
import org.springframework.core.convert.ConversionService;
7575
import org.springframework.core.env.ConfigurableEnvironment;
76+
import org.springframework.core.env.Environment;
7677
import org.springframework.core.env.StandardEnvironment;
7778
import org.springframework.core.io.DefaultResourceLoader;
7879
import org.springframework.core.io.Resource;
@@ -224,7 +225,6 @@ public AbstractApplicationContext() {
224225
public AbstractApplicationContext(ApplicationContext parent) {
225226
this.parent = parent;
226227
this.resourcePatternResolver = getResourcePatternResolver();
227-
this.environment = this.createEnvironment();
228228
}
229229

230230

@@ -276,7 +276,15 @@ public ApplicationContext getParent() {
276276
return this.parent;
277277
}
278278

279+
/**
280+
* {@inheritDoc}
281+
* <p>If {@code null}, a new environment will be initialized via
282+
* {@link #createEnvironment()}.
283+
*/
279284
public ConfigurableEnvironment getEnvironment() {
285+
if (this.environment == null) {
286+
this.environment = this.createEnvironment();
287+
}
280288
return this.environment;
281289
}
282290

@@ -387,9 +395,9 @@ protected ResourcePatternResolver getResourcePatternResolver() {
387395
public void setParent(ApplicationContext parent) {
388396
this.parent = parent;
389397
if (parent != null) {
390-
Object parentEnvironment = parent.getEnvironment();
398+
Environment parentEnvironment = parent.getEnvironment();
391399
if (parentEnvironment instanceof ConfigurableEnvironment) {
392-
this.environment.merge((ConfigurableEnvironment)parentEnvironment);
400+
this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
393401
}
394402
}
395403
}
@@ -505,7 +513,7 @@ protected void prepareRefresh() {
505513

506514
// Validate that all properties marked as required are resolvable
507515
// see ConfigurablePropertyResolver#setRequiredProperties
508-
this.environment.validateRequiredProperties();
516+
this.getEnvironment().validateRequiredProperties();
509517
}
510518

511519
/**

spring-web/src/main/java/org/springframework/web/context/support/AbstractRefreshableWebApplicationContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ public String[] getConfigLocations() {
134134
}
135135

136136
/**
137-
* Create and return a new {@link StandardServletEnvironment}.
137+
* Create and return a new {@link StandardServletEnvironment}. Subclasses may override
138+
* in order to configure the environment or specialize the environment type returned.
138139
*/
139140
@Override
140141
protected ConfigurableEnvironment createEnvironment() {

spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/FrameworkPortlet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -345,6 +345,7 @@ protected ApplicationContext createPortletApplicationContext(ApplicationContext
345345
pac.setId(ConfigurablePortletApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getPortletName());
346346
}
347347

348+
pac.setEnvironment(this.getEnvironment());
348349
pac.setParent(parent);
349350
pac.setPortletContext(getPortletContext());
350351
pac.setPortletConfig(getPortletConfig());

spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/GenericPortletBean.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@
3434
import org.springframework.beans.PropertyValue;
3535
import org.springframework.beans.PropertyValues;
3636
import org.springframework.context.EnvironmentAware;
37+
import org.springframework.core.env.ConfigurableEnvironment;
3738
import org.springframework.core.env.Environment;
39+
import org.springframework.core.env.EnvironmentCapable;
3840
import org.springframework.core.io.Resource;
3941
import org.springframework.core.io.ResourceEditor;
4042
import org.springframework.core.io.ResourceLoader;
43+
import org.springframework.util.Assert;
4144
import org.springframework.util.StringUtils;
42-
import org.springframework.web.portlet.context.StandardPortletEnvironment;
4345
import org.springframework.web.portlet.context.PortletContextResourceLoader;
46+
import org.springframework.web.portlet.context.StandardPortletEnvironment;
4447

4548
/**
4649
* Simple extension of <code>javax.portlet.GenericPortlet</code> that treats
@@ -65,7 +68,8 @@
6568
* @see #processAction
6669
* @see FrameworkPortlet
6770
*/
68-
public abstract class GenericPortletBean extends GenericPortlet implements EnvironmentAware {
71+
public abstract class GenericPortletBean extends GenericPortlet
72+
implements EnvironmentCapable, EnvironmentAware {
6973

7074
/** Logger available to subclasses */
7175
protected final Log logger = LogFactory.getLog(getClass());
@@ -76,7 +80,7 @@ public abstract class GenericPortletBean extends GenericPortlet implements Envir
7680
*/
7781
private final Set<String> requiredProperties = new HashSet<String>();
7882

79-
private Environment environment = new StandardPortletEnvironment();
83+
private ConfigurableEnvironment environment;
8084

8185

8286
/**
@@ -107,7 +111,7 @@ public final void init() throws PortletException {
107111
PropertyValues pvs = new PortletConfigPropertyValues(getPortletConfig(), this.requiredProperties);
108112
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
109113
ResourceLoader resourceLoader = new PortletContextResourceLoader(getPortletContext());
110-
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
114+
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
111115
initBeanWrapper(bw);
112116
bw.setPropertyValues(pvs, true);
113117
}
@@ -167,17 +171,39 @@ protected void initPortletBean() throws PortletException {
167171

168172
/**
169173
* {@inheritDoc}
170-
* <p>Any environment set here overrides the {@link StandardPortletEnvironment}
171-
* provided by default.
174+
* @throws IllegalArgumentException if environment is not assignable to
175+
* {@code ConfigurableEnvironment}.
172176
*/
173177
public void setEnvironment(Environment environment) {
174-
this.environment = environment;
178+
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
179+
this.environment = (ConfigurableEnvironment)environment;
180+
}
181+
182+
/**
183+
* {@inheritDoc}
184+
* <p>If {@code null}, a new environment will be initialized via
185+
* {@link #createEnvironment()}.
186+
*/
187+
public ConfigurableEnvironment getEnvironment() {
188+
if (this.environment == null) {
189+
this.environment = this.createEnvironment();
190+
}
191+
return this.environment;
192+
}
193+
194+
/**
195+
* Create and return a new {@link StandardPortletEnvironment}. Subclasses may override
196+
* in order to configure the environment or specialize the environment type returned.
197+
*/
198+
protected ConfigurableEnvironment createEnvironment() {
199+
return new StandardPortletEnvironment();
175200
}
176201

177202

178203
/**
179204
* PropertyValues implementation created from PortletConfig init parameters.
180205
*/
206+
@SuppressWarnings("serial")
181207
private static class PortletConfigPropertyValues extends MutablePropertyValues {
182208

183209
/**

spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/context/StandardPortletEnvironment.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -75,7 +75,6 @@ public class StandardPortletEnvironment extends StandardEnvironment {
7575
* @see org.springframework.core.env.AbstractEnvironment#customizePropertySources
7676
* @see PortletConfigPropertySource
7777
* @see PortletContextPropertySource
78-
* @see AbstractRefreshablePortletApplicationContext#initPropertySources
7978
* @see PortletApplicationContextUtils#initPortletPropertySources
8079
*/
8180
@Override

spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,7 @@ protected WebApplicationContext createWebApplicationContext(ApplicationContext p
588588
ConfigurableWebApplicationContext wac =
589589
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
590590

591+
wac.setEnvironment(this.getEnvironment());
591592
wac.setParent(parent);
592593
wac.setConfigLocation(getContextConfigLocation());
593594

spring-webmvc/src/main/java/org/springframework/web/servlet/HttpServletBean.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,11 +35,15 @@
3535
import org.springframework.beans.PropertyValue;
3636
import org.springframework.beans.PropertyValues;
3737
import org.springframework.context.EnvironmentAware;
38+
import org.springframework.core.env.ConfigurableEnvironment;
3839
import org.springframework.core.env.Environment;
40+
import org.springframework.core.env.EnvironmentCapable;
3941
import org.springframework.core.io.Resource;
4042
import org.springframework.core.io.ResourceEditor;
4143
import org.springframework.core.io.ResourceLoader;
44+
import org.springframework.util.Assert;
4245
import org.springframework.util.StringUtils;
46+
import org.springframework.web.context.ConfigurableWebEnvironment;
4347
import org.springframework.web.context.support.StandardServletEnvironment;
4448
import org.springframework.web.context.support.ServletContextResourceLoader;
4549

@@ -76,7 +80,8 @@
7680
* @see #doPost
7781
*/
7882
@SuppressWarnings("serial")
79-
public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware {
83+
public abstract class HttpServletBean extends HttpServlet
84+
implements EnvironmentCapable, EnvironmentAware {
8085

8186
/** Logger available to subclasses */
8287
protected final Log logger = LogFactory.getLog(getClass());
@@ -87,7 +92,7 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
8792
*/
8893
private final Set<String> requiredProperties = new HashSet<String>();
8994

90-
private Environment environment = new StandardServletEnvironment();
95+
private ConfigurableWebEnvironment environment;
9196

9297

9398
/**
@@ -120,7 +125,7 @@ public final void init() throws ServletException {
120125
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
121126
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
122127
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
123-
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
128+
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
124129
initBeanWrapper(bw);
125130
bw.setPropertyValues(pvs, true);
126131
}
@@ -182,11 +187,32 @@ protected void initServletBean() throws ServletException {
182187

183188
/**
184189
* {@inheritDoc}
185-
* <p>Any environment set here overrides the {@link StandardServletEnvironment}
186-
* provided by default.
190+
* @throws IllegalArgumentException if environment is not assignable to
191+
* {@code ConfigurableWebEnvironment}.
187192
*/
188193
public void setEnvironment(Environment environment) {
189-
this.environment = environment;
194+
Assert.isInstanceOf(ConfigurableWebEnvironment.class, environment);
195+
this.environment = (ConfigurableWebEnvironment)environment;
196+
}
197+
198+
/**
199+
* {@inheritDoc}
200+
* <p>If {@code null}, a new environment will be initialized via
201+
* {@link #createEnvironment()}.
202+
*/
203+
public ConfigurableWebEnvironment getEnvironment() {
204+
if (this.environment == null) {
205+
this.environment = this.createEnvironment();
206+
}
207+
return this.environment;
208+
}
209+
210+
/**
211+
* Create and return a new {@link StandardServletEnvironment}. Subclasses may override
212+
* in order to configure the environment or specialize the environment type returned.
213+
*/
214+
protected ConfigurableWebEnvironment createEnvironment() {
215+
return new StandardServletEnvironment();
190216
}
191217

192218

spring-webmvc/src/test/java/org/springframework/web/servlet/DispatcherServletTests.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.util.Locale;
21+
2122
import javax.servlet.Servlet;
2223
import javax.servlet.ServletConfig;
2324
import javax.servlet.ServletContext;
@@ -33,14 +34,18 @@
3334
import org.springframework.beans.TestBean;
3435
import org.springframework.context.ConfigurableApplicationContext;
3536
import org.springframework.context.support.DefaultMessageSourceResolvable;
37+
import org.springframework.core.env.ConfigurableEnvironment;
38+
import org.springframework.core.env.StandardEnvironment;
3639
import org.springframework.mock.web.MockHttpServletRequest;
3740
import org.springframework.mock.web.MockHttpServletResponse;
3841
import org.springframework.mock.web.MockServletConfig;
3942
import org.springframework.mock.web.MockServletContext;
4043
import org.springframework.web.bind.EscapedErrors;
44+
import org.springframework.web.context.ConfigurableWebEnvironment;
4145
import org.springframework.web.context.ServletConfigAwareBean;
4246
import org.springframework.web.context.ServletContextAwareBean;
4347
import org.springframework.web.context.WebApplicationContext;
48+
import org.springframework.web.context.support.StandardServletEnvironment;
4449
import org.springframework.web.context.support.StaticWebApplicationContext;
4550
import org.springframework.web.multipart.MaxUploadSizeExceededException;
4651
import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -55,6 +60,9 @@
5560
import org.springframework.web.servlet.view.InternalResourceViewResolver;
5661
import org.springframework.web.util.WebUtils;
5762

63+
import static org.hamcrest.CoreMatchers.*;
64+
import static org.junit.Assert.*;
65+
5866
/**
5967
* @author Rod Johnson
6068
* @author Juergen Hoeller
@@ -823,6 +831,30 @@ public void testDispatcherServletContextRefresh() throws ServletException {
823831
servlet.destroy();
824832
}
825833

834+
public void testEnvironmentOperations() {
835+
DispatcherServlet servlet = new DispatcherServlet();
836+
ConfigurableWebEnvironment defaultEnv = servlet.getEnvironment();
837+
assertThat(defaultEnv, notNullValue());
838+
ConfigurableEnvironment env1 = new StandardServletEnvironment();
839+
servlet.setEnvironment(env1); // should succeed
840+
assertThat(servlet.getEnvironment(), sameInstance(env1));
841+
try {
842+
servlet.setEnvironment(new StandardEnvironment());
843+
fail("expected exception");
844+
}
845+
catch (IllegalArgumentException ex) {
846+
}
847+
class CustomServletEnvironment extends StandardServletEnvironment { }
848+
@SuppressWarnings("serial")
849+
DispatcherServlet custom = new DispatcherServlet() {
850+
@Override
851+
protected ConfigurableWebEnvironment createEnvironment() {
852+
return new CustomServletEnvironment();
853+
}
854+
};
855+
assertThat(custom.getEnvironment(), instanceOf(CustomServletEnvironment.class));
856+
}
857+
826858

827859
public static class ControllerFromParent implements Controller {
828860

0 commit comments

Comments
 (0)