Spring auto inject with constructor via code or annotations - java

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.

Related

Access BeanNameGenerator

i want to register a spring bean programatically via
((GenericApplicationContext) applicationContext).registerBeanDefinition(name, beanDefinition);.
However, to have a consistent bean name I want to access the BeanNameGenerator to generate the name with it.
But how do I get this?
Classes implementing the interface BeanNameGenerator are not available to get from the Spring context as they are used during the context initialization. Instead, each of the classes is exposed as a singleton (actual Java singleton, not a Spring bean with singleton scope) in a public (and static) field INSTANCE:
DefaultBeanNameGenerator.INSTANCE
AnnotationBeanNameGenerator.INSTANCE
FullyQualifiedAnnotationBeanNameGenerator.INSTANCE
See the BeanNameGenerator docs - there you can find the implementing classes and their docs as well. The INSTANCE fields in each class are described with more details there.

How to add POJO to Spring context to enable injecting dependencies?

I have a class that would otherwise be a very generic POJO but I would like to inject a dependency in it because I would like to avoid passing that dependency as a (constructor) parameter:
//no managed context annotation because it's a simple POJO
public class QueuedBatch {
//however, I would like to inject the context managed bean below
#Autowired
AsyncActionQueue asyncActionQueue;
Currently, no exception is thrown at deploy time but asyncActionQueue is null at runtime so I get a NullPointer when I hit the POJO.
How can I annotate my POJO to add it to the Spring managed context so that I can inject dependencies into it? AsyncActionQueue is a singleton and I would rather not be passing it to QueuedBatch as a (constructor) parameter.
This post is similar, except that I want to add my POJO into the managed context.
As the comments suggested you have 2 ways of dealing with this
Pass the AsyncActionQueue as a parameter in the constructor of QueuedBatch. This doesnt require Spring to know anything about QueuedBatch, but enforces the dependency to be provided when an instance of QueuedBatch is created.
Annotate the QueuedBatch class with #Component. And ensure that the package which contains QueuedBatch is included in the component scan when initializing the spring context. In this way, it becomes a spring managed bean allowing AsyncActionQueue to be autowired into it. You may change the scope of QueuedBatch component based on your requirement.

Spring prototype beans with parameters?

Is it possible to define a prototype bean, using XML config or annotation-based config such that I can get an instance of the bean with a custom parameter value? My use case is a message queue handler that makes API calls with different parameter values that are supplied in the inbound message.
In this case it seems I can do one of two things:
Get an instance of my prototype-scope bean and then call setters to customize it to be specific to the inbound message.
Construct a new instance of the bean class using a plain new MyPrototypeBean() and then call setters to customize the instance.
Perhaps a different way of wording my question is: What is the benefit of using a prototype-scope bean vs. using a simple Java constructor?
To get a prototype bean from another bean while passing arguments to constructor you can use <lookup-method> (XML Configuration) or #Lookup (annotation-based configuration).
If you want to get the prototype instance from "unmanaged" code (not from a bean) or you don't want to use the lookup methods, you can achieve the same using org.springframework.beans.factory.BeanFactory.getBean(String beanName, Object...).
Answering your second question, difference between a prototype-scope bean and using a simple Java constructor is that the prototype-scope bean still have access to Spring container's features. This includes, but it's not limited to the following: it can have collaborators provided in XML configuration (<property name="someCollaborator" ref="..."/>) or with annotations (#Resource, #Autowired, ...), t can implement Spring-aware interfaces (like ApplicationContextAware so that the prototype bean itself has access to the container).

Is it possible to autowire method arguments at runtime in Spring

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.

Instantiating arbitrary classes thru Spring

I'm writing a service registry class. This service registry will scan packages for annotated classes and then populate some internal map. What I need then, is to be able to query for services (by String name) using some method (let's say Object get(String name)). This method will then search internal map for a service with such name and returns instance.
What I'm doing right now, is having this ServiceRegistryBean implement ApplicationContextAware and BeanDefinitionRegistryPostProcessor and a list of Strings (package names) given on construct.
Then, as soon as the bean is constructed, registry post processor kicks in (see note) and the registry class adds the service classes as new beans (singleton, lazy loaded) to the spring bean registry. Then, getting the service instance is as simple as requesting a bean from context, returning singleton instance.
My question is: is there a better way in Spring to do this? I've looked into bean factories, but it does not seem to me the same. Support for auto-wiring and DI in service instances is essential, that's why I want Spring to instantiate it. Also, I like the idea of Spring taking care of singletons.
Note: I've found out, that when I inline the bean creation in <constructor-arg> (that is, bean is not named and is just an instance passed as constructor argument of other bean - in my case, I'm passing registry as a parameter to other constructor), BeanDefinitionRegistryPostProcessor interface methods (namely public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)) is not called at all! I'm quite sure, it is some behavior of Spring I don't know about, but I was not able to find proper documentation for the post-processor.
Thank you for any hints or insights!
Scanning for custom annotations it's already supported, you only need to add a include-filter to <context:component-scan> tag, ie
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="some.Annotation"/>
</context:component-scan>
see http://static.springsource.org/spring/docs/current/spring-framework-reference/html/beans.html#beans-scanning-filters
If you turn on default-lazy-init I suppose that the DI Container is ready to use as Service Locator Registry.
About the note, only root bean definitions are taken into account when looking for BeanFactoryPostProcessors, inner beans are ignored.
Usually, scanning and registering beans is done by BeanDefinitionParsers instead because you known when the beans are registered and beans are visible for tools, like STS Spring Bean Explorer, but using a BeanDefinitionRegistryPostProcessor is correct. The interface ensures that beans are defined before other BeanFactoryPostProcessors run.

Categories

Resources