1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.batch.core.scope;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.springframework.aop.scope.ScopedProxyUtils;
21 import org.springframework.batch.core.scope.context.StepContext;
22 import org.springframework.batch.core.scope.context.StepSynchronizationManager;
23 import org.springframework.beans.BeanWrapper;
24 import org.springframework.beans.BeanWrapperImpl;
25 import org.springframework.beans.BeansException;
26 import org.springframework.beans.factory.ObjectFactory;
27 import org.springframework.beans.factory.config.BeanDefinition;
28 import org.springframework.beans.factory.config.BeanDefinitionHolder;
29 import org.springframework.beans.factory.config.BeanDefinitionVisitor;
30 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
31 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
32 import org.springframework.beans.factory.config.Scope;
33 import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
34 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
35 import org.springframework.core.Ordered;
36 import org.springframework.util.Assert;
37 import org.springframework.util.StringValueResolver;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered {
78
79 private Log logger = LogFactory.getLog(getClass());
80
81 private int order = Ordered.LOWEST_PRECEDENCE;
82
83 private boolean autoProxy = true;
84
85 private final Object mutex = new Object();
86
87
88
89
90
91 public void setOrder(int order) {
92 this.order = order;
93 }
94
95 @Override
96 public int getOrder() {
97 return order;
98 }
99
100
101
102
103 public static final String ID_KEY = "STEP_IDENTIFIER";
104
105 private String name = "step";
106
107 private boolean proxyTargetClass = false;
108
109
110
111
112
113
114
115
116 public void setProxyTargetClass(boolean proxyTargetClass) {
117 this.proxyTargetClass = proxyTargetClass;
118 }
119
120
121
122
123
124
125
126 public void setAutoProxy(boolean autoProxy) {
127 this.autoProxy = autoProxy;
128 }
129
130
131
132
133 @Override
134 public Object resolveContextualObject(String key) {
135 StepContext context = getContext();
136
137
138 return new BeanWrapperImpl(context).getPropertyValue(key);
139 }
140
141
142
143
144 @SuppressWarnings("rawtypes")
145 @Override
146 public Object get(String name, ObjectFactory objectFactory) {
147
148 StepContext context = getContext();
149 Object scopedObject = context.getAttribute(name);
150
151 if (scopedObject == null) {
152
153 synchronized (mutex) {
154 scopedObject = context.getAttribute(name);
155 if (scopedObject == null) {
156
157 logger.debug(String.format("Creating object in scope=%s, name=%s", this.name, name));
158
159 scopedObject = objectFactory.getObject();
160 context.setAttribute(name, scopedObject);
161
162 }
163
164 }
165
166 }
167 return scopedObject;
168 }
169
170
171
172
173 @Override
174 public String getConversationId() {
175 StepContext context = getContext();
176 return context.getId();
177 }
178
179
180
181
182 @Override
183 public void registerDestructionCallback(String name, Runnable callback) {
184 StepContext context = getContext();
185 logger.debug(String.format("Registered destruction callback in scope=%s, name=%s", this.name, name));
186 context.registerDestructionCallback(name, callback);
187 }
188
189
190
191
192 @Override
193 public Object remove(String name) {
194 StepContext context = getContext();
195 logger.debug(String.format("Removing from scope=%s, name=%s", this.name, name));
196 return context.removeAttribute(name);
197 }
198
199
200
201
202
203
204
205
206 private StepContext getContext() {
207 StepContext context = StepSynchronizationManager.getContext();
208 if (context == null) {
209 throw new IllegalStateException("No context holder available for step scope");
210 }
211 return context;
212 }
213
214
215
216
217
218
219
220
221
222 @Override
223 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
224
225 beanFactory.registerScope(name, this);
226
227 if(!autoProxy) {
228 return;
229 }
230
231 Assert.state(beanFactory instanceof BeanDefinitionRegistry,
232 "BeanFactory was not a BeanDefinitionRegistry, so StepScope cannot be used.");
233 BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
234
235 for (String beanName : beanFactory.getBeanDefinitionNames()) {
236 BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
237
238
239 boolean scoped = name.equals(definition.getScope());
240 Scopifier scopifier = new Scopifier(registry, name, proxyTargetClass, scoped);
241 scopifier.visitBeanDefinition(definition);
242 if (scoped) {
243 createScopedProxy(beanName, definition, registry, proxyTargetClass);
244 }
245 }
246
247 }
248
249
250
251
252
253
254
255 public void setName(String name) {
256 this.name = name;
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 private static BeanDefinitionHolder createScopedProxy(String beanName, BeanDefinition definition,
274 BeanDefinitionRegistry registry, boolean proxyTargetClass) {
275
276 BeanDefinitionHolder proxyHolder;
277
278 proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry,
279 proxyTargetClass);
280
281 registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
282
283 return proxyHolder;
284
285 }
286
287
288
289
290
291
292
293
294 private static class Scopifier extends BeanDefinitionVisitor {
295
296 private final boolean proxyTargetClass;
297
298 private final BeanDefinitionRegistry registry;
299
300 private final String scope;
301
302 private final boolean scoped;
303
304 public Scopifier(BeanDefinitionRegistry registry, String scope, boolean proxyTargetClass, boolean scoped) {
305 super(new StringValueResolver() {
306 @Override
307 public String resolveStringValue(String value) {
308 return value;
309 }
310 });
311 this.registry = registry;
312 this.proxyTargetClass = proxyTargetClass;
313 this.scope = scope;
314 this.scoped = scoped;
315 }
316
317 @Override
318 protected Object resolveValue(Object value) {
319
320 BeanDefinition definition = null;
321 String beanName = null;
322 if (value instanceof BeanDefinition) {
323 definition = (BeanDefinition) value;
324 beanName = BeanDefinitionReaderUtils.generateBeanName(definition, registry);
325 }
326 else if (value instanceof BeanDefinitionHolder) {
327 BeanDefinitionHolder holder = (BeanDefinitionHolder) value;
328 definition = holder.getBeanDefinition();
329 beanName = holder.getBeanName();
330 }
331
332 if (definition != null) {
333 boolean nestedScoped = scope.equals(definition.getScope());
334 boolean scopeChangeRequiresProxy = !scoped && nestedScoped;
335 if (scopeChangeRequiresProxy) {
336
337
338 return createScopedProxy(beanName, definition, registry, proxyTargetClass);
339 }
340 }
341
342
343 value = super.resolveValue(value);
344 return value;
345
346 }
347
348 }
349 }