2

When I defined a 'MethodInvokingFactory' bean with 'scope=step', I got an error that the type of the bean can't be determined. It worked fine when I replaced 'scope=step' with 'lazy-init=true'. As per my knowledge, both are used for the late binding of the beans, except for that one difference. Are there any other differences between these two ways? Also, is my usage correct?

Please let me know your thoughts about this.

dma_k
  • 10,431
  • 16
  • 76
  • 128
Java Bean
  • 404
  • 1
  • 5
  • 12

3 Answers3

4

To answer to your question from low-level perspective:

lazy-init="true" means that bean will not be instantiated when the context is created, but will be created when it is referred e.g. by another bean. I think this is clear, also from @AravindA comment.

Scoped bean works in different manner. When context is created this bean is wrapped into additional proxy object (by default created by CGLIB), which is passed to the bean that refers it (this proxy is by default singleton, e.g. shared). So each time the method is invoked on the proxy in runtime Spring intersects the call, requests the factory to return the instance of the bean and invokes the method on that bean. The factory in its turn may lookup for "real" bean instance e.g. in HTTP request ("request" scope) or HTTP session ("session" scope) and/or create new instance if necessary. Late instantiation allows to initialize the scoped bean with "runtime" (scope) values, e.g. values from HTTP request/session which are obviously undefined when context was created. In particular "step"-scoped beans are bound to thread local (remember that steps are run in parallel for partitioning). So, scoped beans are dereferred when you call a method on them. Finally one can easily break this elegant Spring "ideology" by calling any method on scoped bean just after it is set to another bean (e.g. in the setter) :)

dma_k
  • 10,431
  • 16
  • 76
  • 128
  • Thanks @dma_k . It makes sense now. But when I used 'scope=step' on all the referred beans, I faced this error. **Error Msg**-`Cannot convert value of type [$Proxy5 implementing org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy, org.springframework.aop.framework.Advised] to required type [XXX.XXX.MyClass]: no matching editors or conversion strategy found.` Could you please tell me why this is happening? Isn't Spring supposed to return the bean automatically, when the bean is referred? – Java Bean Jan 09 '12 at 05:22
  • I think, I know what the problem is: as your bean is wrapped, it does not match the requested class. So: Either do autowiring by type, but **use interfaces** (interfaces are automatically propagated to proxy) (`@Autowire MyInterface bean`), or use autowiring by name (`@Resource("myBean") bean`). If that is constructor autowiring that caused the problem, then interface is the only option, I think. – dma_k Jan 09 '12 at 16:25
  • @ dma_k Instead of autowiring,(with the help of Google) I've added this bean and surprisingly this has worked like a charm. ` `. I no longer get any errors on proxy conversion as above. Still I don't see how this is solving the issue. Could you please throw some light? – Java Bean Jan 10 '12 at 11:09
  • I think, this discussion falls apart from original subject. Create new question (include your Spring config + stack trace) and you will get the answer. – dma_k Jan 10 '12 at 15:47
  • thanks @dma_k for all your help. You've cleared most of my doubts. Regarding my last question why making 'proxyTargetclass=true' for StepScope is solving the problem, there is no stack trace as I don't get any error now. – Java Bean Jan 12 '12 at 10:27
  • @JavaBean: `proxyTargetclass=true` creates the CGLIB wrapper for your class, that is why it still casts to original class. Without this option Java proxy is created (= default behaviour), so only interfaces can be "emulated". PS: Consider accepting one of the answers for the post to close it. – dma_k Jan 12 '12 at 17:25
2
      One thing to understand about lazy-initialization is that even though a bean 
      definition may be marked up as being lazy-initialized, if the lazy-initialized     
      bean is the dependency of a singleton bean that is not lazy-initialized, when the
      ApplicationContext is eagerly pre-instantiating the singleton, it will have to 
      satisfy all of the singletons dependencies, one of which will be the 
      lazy-initialized bean!

      Using a scope of Step is required in order to use late binding since the bean 
      cannot actually be instantiated until the Step starts, which allows the   
      attributes to be found. Because it is not part of the Spring container by   
      default, the scope must be added explicitly, either by using the batch namespace 
      or by including a bean definition explicitly for the StepScope (but not both):

      <bean class="org.springframework.batch.core.scope.StepScope" />

Read here and here for more info

The scope="step" has nothing to do with Lazy initialization . It is use for late binding of parameters inside a "Step" .

Aravind A
  • 9,507
  • 4
  • 36
  • 45
  • Thanks for taking your time in answering. But, my question is what the **differences between these two ways of achieving lazy binding** are. – Java Bean Jan 06 '12 at 09:34
  • @Java Bean , the scope="step" is used in the context of Spring batch above to bind resources within a Step scope . A Step is a domain object that encapsulates an independent, sequential phase of a batch job . It is not part of the spring container by default whereas lazy-init is . In spring batch , Any bean that uses late-binding must be declared with scope="step". – Aravind A Jan 06 '12 at 10:41
  • I would rather say "any beans that refers step-specific variables (e.g. that @MichaelLange shown) should be in step scope". – dma_k Jan 06 '12 at 15:27
1

the step scope is specifically for latebinding of job/step attributes and not really for late-binding of beans, meaning the spring bean context/factory will enhance stepscoped beans and look for attributes to set, e.g.

value="#{jobParameters[input.file.name]}
Michael Pralow
  • 6,560
  • 2
  • 30
  • 46
  • @Micheal Lange Is it fine if I use step scope for achieving lazy binding of beans(instead of attributes, i.e when all attributes are already set)? Or is this gonna cause some other problems? – Java Bean Jan 10 '12 at 11:15
  • lazy binding of beans is different than lazy binding of attributes in spring batch, please refer to http://stackoverflow.com/a/8761244/62201, i would not use StepScope if lazy-binding of beans is the only requirement – Michael Pralow Jan 11 '12 at 09:52
  • thanks for all your help @Micheal Lange .If only you could tell me why you wouldn't use stepScope for lazy-binding.. :) – Java Bean Jan 12 '12 at 10:32
  • i thought thats clear after reading the doc, stepScope is lazy in context of step lifecycle, say 3 steps each use a stepScope bean, the bean will get lazy binding of attributes and acts almost like a prototype bean, with a real prototype bean, it works outside of step lifecycle too – Michael Pralow Jan 12 '12 at 10:37