Spring autowire and prototype scope - java

I have a class named Bar with the following annotation:
#Configurable(autowire = Autowire.BY_TYPE)
On a private member I have the following annotation:
#Autowired(required = true)
private Foo foo;
In the spring configuration I have a bean of class Foo. If the bean is defined with scope="prototype" it doesn't work and I get the following exception:
NoSuchBeanDefinitionException: No matching bean of type Foo found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency
Once I change the injected bean scope to "singleton" it works fine.
Isn't auto wiring of prototype scoped bean allowed?
Is there any workaround (beside getting the bean manually)?
Thanks in advance,
Avner

The following link provide alternative solutions for such scenarios:
http://whyjava.wordpress.com/2010/10/30/spring-scoped-proxy-beans-an-alternative-to-method-injection/
The link talks about adding to Foo:
#Component
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")
class Foo
Which will cause a new instance for every call.

I believe its the prototype/singleton thing declared in your xml for that bean is the issue.
Isn't auto wiring of prototype scoped bean allowed?
I think it is not allowed. The logic is if it is allowed, then whenever you use that class, then it needs to reinstantiate that bean always as its field. Which is weird especially if the class that this bean is autowired as a field is a singleton itself.
is there any workaround (beside getting the bean manually)?
Just try to remove the scope attribute, cause if it is of prototype attribute, it won't be retrieved. If those beans(services and DAO) are declared in your applicationContext, just let the autowire annotation get it as singleton since by default beans are singleton, which it should be.

If the injected bean scope is 'Singleton', the same instance of the bean will be auto-wired. If the injected bean scope is 'prototype', new instance will be created as part of auto-wire process.
What version of Spring you are using and also attach the spring-context.xml for more details.

Related

DI: No qualifying bean of type available

I start to learn Spring.
In my beginner project I want to inject dependency of beans.
https://github.com/anatoliy19/2.1.4.git
To do that, 1) I add in AppConfig method
#Bean
public static Duck5 getDuck(Egg6 egg) {return new Duck5(egg);}
and 2)
add a private field in class Duck5:
#Autowired
private Egg6 egg;
To my regret, an error has come out:
[No qualifying bean of type 'koschei.models.Duck5' available][1]: expected single matching bean but found 2: duck5,getDuck
Project is here: https://github.com/anatoliy19/2.1.4.git
So from the exception found 2 I assume you have the bean defined and taking from the Autowired field egg Duck5 is annotated with something like Component.
So the Component annotation already tells spring that it should create a bean for this class and then you create another one in your configuration and thereby Spring doesn't know which bean to take
Notice the bean names in the exception getDuck (your own bean) and duck5 (just the class name in lower case)
So now you have the options to either just remove the bean you create, remove the annotation and use your bean or use a Qualifer to identify the bean so Spring knows which to use.

Why scope in Spring affects loading of class in Spring

Class Student Depends on class Result
<bean id = "result" lazy-init = "false">
</bean>
<bean id = "student" lazy-init = "true">
</bean>
Result: result bean will be loaded at container start-up and student will be loaded when we call getBean method.
<bean id = "result" lazy-init = "false" scope = "prototype">
</bean>
<bean id = "student" lazy-init = "true" scope = "Singleton">
</bean>
Result: No bean will be loaded at container start-up.
Question: Why scope is affecting class load; what does scope have to do with class load time?
According to documentation
The non-singleton, prototype scope of bean deployment results in the
creation of a new bean instance every time a request for that specific
bean is made. That is, the bean is injected into another bean or you
request it through a getBean() method call on the container. As a
rule, use the prototype scope for all stateful beans and the singleton
scope for stateless beans.
Since you didn't yet call getBean or inject it to another bean, this bean is not been created.
By the way, even when you declared your singletone bean as lazy-init="true", it will be created, if you'll inject it (for example with #Autowired annotation) to other non-lazy bean.
A bean of scope singleton is a bean that is created once per application context. A bean of scope prototype is a bean that is instantiated every time.
In other words if your have two classes that autowire a singleton scoped bean, all instances of those two classes will reference the same single instance of the bean. Doing the same with autowiring a prototype scoped bean will create a new instance for each instance that is autowired.
The property for lazy-init defines when the bean is instantiated: As a prototype scoped bean is instantiated each time there is no difference if the property is set to true or false, because the bean is instanciated when it is used (either by being autowired or by programmatic retrieval from the context). For a singleton scoped bean however it does make a difference:
If lazy-init is set to false (which is the default), the bean is instantiated on startup.
If the property is set to true, the bean is instantiated on the first use (through autowiring or programmatic retrieval from the context).
Defining a lazy load singleton bean may come in handy in cases where the bean may be costly to create and may only be used in special cases, the the application may actually run without ever calling any method on that bean.
Take a look at the Spring IoC container documentation, which goes into great detail.
I would like to put the theory in a simple manner which will help you understand better,
Only Singleton beans are eager loaded | prototype beans are lazily loaded(every req or indirect references)
If singleton bean is defined as lazy-init=true (by-default its false) then bean will be instantiated on first usage(using getBean or any indirect reference)
But for prototype bean lazy-init does not make any diff if making lazy-init=true or false as it will be lazily loaded always
You can try using #PostConstruct to play around different combinations in spring bean injections to know when beans are getting instantiated.

Matching bean id with instance member variable in java code for #Autowired

I have below bean defined in application context xml file:
<bean id="logRoutingTable" class="com.symantec.cas.ucf.plugin.router.RoutingTable">
</bean>
And using it in java file with #Autowired
#Autowired
private RoutingTable routingTable;
The above code is working properly. But now I realized that instance name routingTable is different than bean id logRoutingTable. So is it not necessary to match both bean id and instance member?
No. It is not required. The instance variable can have any name. Spring framework automatically searches for matching bean. In case you have more than one bean for same class then you have to use
#Qualifier("beanName")
for matching by bean Name.
As long as there is only one bean matching (IS-A) RoutingTable, Spring will allow the injection.
If you had another bean matching, there would be a conflict that you could solve with #Qualifier(See mykong example) or by renaming the instance variable to match the bean id.

Spring #Autowired - what is happening in the background

Excuse me if this is has already been discussed, I could not find a satisfying answer.
I do not understand whats happening when i create a bean in Springframework and #Autowired it to a field in another bean. I understand the result of #Autowired and other annotations but i do not know how its done by Spring.
class Sample1{
//
}
class Sample2{
#Autowired
Sample1 sample1Bean;
}
<bean id="sample1Bean" class="...Sample1"/>
<bean id="sample2Bean" class="...Sample2"/>
My question is how does spring set the field sample1Bean in Sample2? i am not expecting a complete explanation, but a direction where i have to look would be great. Thanks.
The #Autowired, #Inject annotations are resolved by a BeanPostProcessor - specifically AutowiredAnnotationBeanPostProcessor. This bean post processor intercepts the creation(for cases where #Autowired is on constructors) of beans, setting of property on the beans to ensure that all the autowired fields are appropriately set.
Im no expert in Spring but I will answer what I know. When a spring powered web application starts up, Spring framework goes through bean instantiation process in the application context. While creating beans Spring checks the required dependencies for a given bean. It looks up a matching bean based on the required type of bean and autowires it when #Autowired annotation is specified.
In the above example, Spring will go through application context and create a bean(object) of type Sample1. When it will construct bean Sample2 it sees #Autowiredannotation and will look for instantiated bean of type Sample1. When it finds bean of type Sample1 it will inject that bean on Sample2 and finish creating Sample2. This is called dependency injection and is one of the very popular features of Spring framework.
Hope this helps.

Can Spring's ObjectFactoryCreatingFactoryBean work with generics that refer to interfaces?

I'm using Spring's ObjectFactoryCreatingFactoryBean to retrieve a prototype scoped bean, as described in the Spring Documentation. Below is my applicationContext.
<bean id="exportFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName">
<idref local="export" />
</property>
</bean>
<bean id="export" class="com.someorg.ExportImpl" scope="prototype"/>
I autowire the exportFactory into a class like so:
#Autowired
#Qualifier("exportFactory")
private ObjectFactory<?> exportFactory;
And this works as expected. Each call to the exportFactory.getObject() method returns a new ExportImpl. On further inspect, a call to getObject() actually returns the following instance: org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean$TargetBeanObjectFactory
Now, ExportImpl is an implementation of an Export interface. And when I attempt to to declare the exportFactory using generics, described below, I get an exception.
#Autowired
#Qualifier("exportFactory")
private ObjectFactory<Export> exportFactory;
Stacktrace:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.someorg.Export] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=exportFactory)}
The application context successfully loads with this configuration, and the exception is thrown when I call exportFactory.getObject(). Using the same configuration I can successfully retrieve an instance of ExportImpl, so I know that bean is correctly wired.
I'd like to know a) what is Spring doing here and b) is there a reason I'm unable to use an ObjectFactory with type parameter that's an interface?
It turns out that ObjectFactoryCreatingFactoryBean is not necessary when you obtain ObjectFactory via #Autowired. In this case ObjectFactory for your bean is created automatically, though I can't find any reference of this behaviour in the documentation.
So, the behaviour you observe can be explained as follows:
When you write #Autowired #Qualifier("exportFactory") ObjectFactory<?>, Spring creates ObjectFactory that returns a bean named exportFactory, which itself is an ObjectFactory returned by the ObjectFactoryCreatingFactoryBean (its class is org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean$TargetBeanObjectFactory).
When you write #Autowired #Qualifier("exportFactory") ObjectFactory<Export>, Spring tries to find bean of type Export named exportFactory, and the search fails.
Change the qualifier to:
#Qualifier("export")

Categories

Resources