Is it possible to autowire method arguments at runtime in Spring - java

Is it possible to inject new instances of prototype scoped beans to Controller's method arguments at runtime using annotations in Spring? So whenever the method is called, Spring would inject the qualifying bean as its argument, familiarly as it injects #ModelAttribute. As far as I know, #Autowired fields are injected only once when context is created. Obtaining the bean from context's factory method isn't an option, as that would expose framework to its component, thus violating the hollywood principle.
I have almost completed reading Spring in Action book and have been reading Spring Reference a lot, but haven't found any info regarding this question.

You have a couple of options.
Define a prototype bean and inject that wrapped in an ObjectFactory
#Autowired
private ObjectFactory<PrototypeBean> factory;
You can then retrieve it in your handler method. For example
#RequestMapping("/path")
public String handlerMethod() {
PrototypeBean instance = factory.getObject();
instance.someMethod();
return "view";
}
Every time you call factory.getObject(), you'll get a new instance.
As for doing this directly, no, Spring MVC does not have a built-in feature for having beans injected while invoking handler methods, with #Autowired or otherwise.
However, the HandlerMethodArgumentResolver API allows you to define an implementation for any type of parameter you want. You can define a new annotation and use it to annotate the appropriate handler method parameter(s). The implementation would look for the annotation and resolve an instance from an injected ApplicationContext. You could do this by name, by type, however you want.

Related

What is the difference between #Bean and Autowired in Spring? [duplicate]

This question already has answers here:
Difference between #Bean and #Autowired
(6 answers)
Closed 4 years ago.
What is the difference between #Bean and #Autowired in Spring?
As far as I understood we can use both to inject dependencies, #Autowired when the interface was implemented just in one class, and #Bean, when the interface was implemented in more than one class, in the last case #configuration, is required.
thanks in advance
In short #Bean is producer and #Autowired is consumer, #Bean annotation let spring know instance of this class and it hold for it and #Autowired annotation ask for please give me instance of class which we created with #Bean annotation.
more detailed answer find here
When you use #Bean you are telling to Spring that:
this is the object that I want you to put within your stack and later I will ask
about it from you
And When you use #Autowired you are telling to Spring that:
Now please give me the object that I already told you to keep it in your stack (means the #Bean object)
When you use #Bean you are responsible for providing an Id and calling that Id when you wish to use that particular object using getBean() method.
Autowired helps avoid the calling part and returns an object everytime it is needed. Spring handles the job of returning the appropriate object and helps reduce additional syntax for referring to a particular bean.
Spring provides a very nice documentation about Autowired and Bean API
#BEAN
#Target(value={METHOD,ANNOTATION_TYPE})
#Retention(value=RUNTIME)
#Documented
public #interface Bean
Indicates that a method produces a bean to be managed by the Spring
container.
On Bean #Target annotation confirms that it can be applied over a METHOD.
#AUTOWIRED
#Target(value={CONSTRUCTOR,METHOD,PARAMETER,FIELD,ANNOTATION_TYPE})
#Retention(value=RUNTIME)
#Documented
public #interface Autowired
Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities. This is an alternative to the JSR-330 Inject annotation.
On Autowired #Target confirms that it can be applied over a CONSTRUCTOR,METHOD,PARAMETER,FIELD.
IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean.

Spring Custom Converter - To Bean or Not to Bean

I am implementing Custom Converter in Spring so my beans can convert from java.util.Date to java.time.LocalDateTime. I have implemented Converter already (by implementing Spring Converter interface)
Here is bean definition in #Configuration class
#Bean
ConversionService conversionService(){
DefaultConversionService service = new DefaultConversionService();
service.addConverter(new DateToLocalDateTimeConverter());
return service;
}
My question is : shall I pass my custom converter as Java Object or Spring Bean to service.addConverter?
In general what are the guidelines (criterias) whether to bean or not to bean in such scenarios?
Making an object a Spring Bean makes sense as you want that this object may benefit from Spring features (injections, transaction, aop, etc...).
In your case, it seems not required.
As conversionService is a Spring bean singleton that will be instantiated once, creating during its instantiation a plain java instance of DateToLocalDateTimeConverter seems fine : new DateToLocalDateTimeConverter().
Now, if later you want to inject the DateToLocalDateTimeConverter instance in other Spring beans, it would make sense to transform it to a Spring Bean.
For information Spring provides already this utility task in the Jsr310Converters class (included in the spring-data-commons dependency) :
import static java.time.LocalDateTime.*;
public abstract class Jsr310Converters {
...
public static enum DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
INSTANCE;
#Override
public LocalDateTime convert(Date source) {
return source == null ? null : ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
...
}
You could directly use it.
If you intend to inject this as a dependency of some kind into your application, and/or you intend to reuse it in multiple places, then it makes sense to register it as a bean. If you're not, then newing an instance up is acceptable.
Dependency injection and inversion of control are just that - how you inject dependencies into your app, and an acknowledgment that you no longer control how that's instantiated. Should you desire either of these, beans are suitable; if you don't, then new it up.
In you simple case, it does not seem to be necessary to add DateToLocalDateTimeConverter as a spring bean.
Reasons to add DateToLocalDateTimeConverter as a spring bean:
If it would make the implementation of conversionService() more readable (not the case in the question example)
You need the DateToLocalDateTimeConverter in other beans
The implementation of DateToLocalDateTimeConverter itself would need to have Spring beans injected, i.e. using #Autowired

Spring auto inject with constructor via code or annotations

Given having next classes:
XRepository with declared a constructor with 1 argument (simple one,
not autowired), it has some autowired fields.
XService that uses XRepository as autowired.
XProcessor uses XService as autowired.
So I have to init XProcessor on runtime for specific value that will be used in XRepository constructor. On different calls I will have different arguments, so the injection should be on runtime.
Any idea how to achieve that using code configuration or annotations?
Remember that Spring needs to inject all the constructor parameters of Spring managed beans.
I believe you have two options:
Parse your URL info in controller and pass it through parameters down to persistence layer. This would be my preferred mechanism. You can create special DTO for passing various information down and keep your method signatures concise.
Your situation can alos be solved with request scope bean. You will
create one bean like this:
#Component
#Scope("request")
public class {
private String urlPart;
}
And you would autowire this component into XProcessor and
XRepository. Each request to your application will create new
instance of XRequestContext and you will parse your info in
XProcessor and store it into XRequestContext.
In XRepository you will use instance of XRequestContext to
retrieve information you stored in XProcessor.
You can read about request scope in Spring docs. It is like
ThreadLocal per request thread.

Autowire of prototype bean into prototype bean?

I'm working with some existing code and it is doing things I haven't seen before. I've dealt with autowiring prototype beans into singletons using method injection or getting the bean from the context using getBean(). What I am seeing in this code I am working on is a bean that is a prototype and retrieved using getBean(), and it has autowired dependencies. Most of these are singleton beans, which makes sense. But there is an autowire of another prototype bean, and from what I see, it does seem like it is getting a new bean. My question is when you autowire a prototype into a prototype, will that give you a new instance? Since the autowire request is not at startup but rather when this bean is created, does it go and create a new instance? This goes against what I thought about autowire and prototype beans and I wanted to hear an answer from out in the wild. Thanks for any insight. I'm trying to minimize my refactoring of this code as it is a bit spaghetti-ish.
example:
#Scope("prototype")
public class MyPrototypeClass {
#Autowired
private ReallyGoodSingletonService svc;
#Autowired
private APrototypeBean bean;
public void doSomething() {
bean.doAThing();
}
}
#Scope("prototype)
public class APrototypeBean {
private int stuffgoeshere;
public void doAThing() {
}
}
So when doSomething() in MyPrototypeClass is called, is that "bean" a singleton or a new one for each instance of MyPrototypeClass?
In your example, the APrototypeBean bean will be set to a brand new bean which will live through until the instance of MyPrototypeClass that you created is destroyed.
If you create a second instance of MyPrototypeClass then that second instance will receive its own APrototypeBean. With your current configuration, every time you call doSomething(), the method will be invoked on an instance of APrototypeBean that is unique for that MyPrototypeClass object.
Your understanding of #Autowired or autowiring in general is flawed. Autowiring occurs when an instance of the bean is created and not at startup.
If you would have a singleton bean that is lazy and that bean isn't directly used nothing would happen as soon as you would retrieve the bean using for instance getBean on the application context an instance would be created, dependencies get wired, BeanPostProcessors get applied etc.
This is the same for each and every type of bean it will be processed as soon as it is created not before that.
Now to answer your question a prototype bean is a prototype bean so yes you will receive fresh instances with each call to getBean.
Adding more explanation to #Mark Laren's answer.
As explained in Spring 4.1.6 docs
In most application scenarios, most beans in the container are
singletons. When a singleton bean needs to collaborate with another
singleton bean, or a non-singleton bean needs to collaborate with
another non-singleton bean, you typically handle the dependency by
defining one bean as a property of the other. A problem arises when
the bean lifecycles are different. Suppose singleton bean A needs to
use non-singleton (prototype) bean B, perhaps on each method
invocation on A. The container only creates the singleton bean A once,
and thus only gets one opportunity to set the properties. The
container cannot provide bean A with a new instance of bean B every
time one is needed.
Below approach will solve this problem, but this is not desirable because this code couples business code with Spring framework and violating IOC pattern. The following is an example of this approach:
// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;
// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
So, there are 2 desirable ways to solve this problem.
1. Using Spring's method injection
As name suggests, Spring will implement & inject our abstract method by using #Lookup annotation from Spring 4 or tag if you use xml version. Refer this DZone article.
By using #Lookup.
from Java Doc...
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
This is essentially an annotation-based version of the XML
lookup-method attribute, resulting in the same runtime arrangement.
Since:
4.1
#Component
public class MyClass1 {
doSomething() {
myClass2();
}
//I want this method to return MyClass2 prototype
#Lookup
public MyClass2 myClass2(){
return null; // No need to declare this method as "abstract" method as
//we were doing with earlier versions of Spring & <lookup-method> xml version.
//Spring will treat this method as abstract method and spring itself will provide implementation for this method dynamically.
}
}
The above example will create new myClass2 instance each time.
2. Using Provider from Java EE (Dependency Injection for Java (JSR 330)).
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public static class SomeRequest {}
#Service
public static class SomeService {
#Autowired
javax.inject.Provider<SomeRequest> someRequestProvider;
SomeRequest doSomething() {
return someRequestProvider.get();
}
}
The above example will create new SomeRequest instance each time.

Inject HttpServletRequest into Controller

As I know per default are controllers in Spring MVC singletons. HttpServletRequest passed offen to the controller handler method. And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets #Autowired into the controller field, like this:
#Controller("CMSProductComponentController")
#RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
#Autowired
private HttpServletRequest request;
}
Could be this a problem? And more general question: What happens if inject a reqeust-scoped component into a singleton?
No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory (RequestObjectFactory for HttpServletRequest) (YMMV) that knows how to retrieve the actual instance. When you use any of the methods of this proxy, they will delegate to that instance.
What's more, this is done lazily, so it won't fail at initialization. It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope).
The following is in response to the comments and to clarify in general.
Regarding the proxy-mode attribute of #Scope or the XML equivalent, the default is ScopedProxyMode.NO. However, as the javadoc states
This proxy-mode is not typically useful when used with a non-singleton
scoped instance, which should favor the use of the INTERFACES or
TARGET_CLASS proxy-modes instead if it is to be used as a dependency.
With request scoped beans, this proxy-mode value will not work. You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want.
With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST), Spring will use RequestScope which
Relies on a thread-bound RequestAttributes instance, which can be
exported through RequestContextListener, RequestContextFilter or
DispatcherServlet.
Let's take this simple example
#Component
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
#Autowired
private RequestScopedBean bean;
Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. when a method is called on the proxy. For example, when
bean.method();
is called.
This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. It will use these two to generate a new bean and then call method() on that instance.
The documentation states
The Spring IoC container manages not only the instantiation of your
objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject (for example) an HTTP request
scoped bean into another bean, you must inject an AOP proxy in place
of the scoped bean. That is, you need to inject a proxy object that
exposes the same public interface as the scoped object but that can
also retrieve the real, target object from the relevant scope (for
example, an HTTP request) and delegate method calls onto the real
object.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
What happens if inject a reqeust-scoped component into a singleton?
Try it and you'll get a BeanCreationException¹ during application context initialization. The error message clearly explains why this doesn't happen with HttpServletRequest:
Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;
So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies.
[1]: unless you didn't change the default behaviour for proxyMode, which is NO or try to inject it with #Lazy. The latter might result into a valid application context but might lead to request scoped beans acting like singletons (e.g. if a request scoped bean is injected into a singleton).

Categories

Resources