Difference b/w primary and autowire-candidate attribute of bean tag in spring - spring

I am new to spring. When i am going through auto wiring byType i came to know about these attributes primary and autowire-candidate.
I didn't get the exact difference b/w these two as setting these parameter to false will make the other bean a candidate for autowiring.
Can anybody help me in understanding these two.
Thanks

Let say there is interface
interface Translator { String translate(String word);}
Your application use the translator widely to translate from English to Polish. However, is some specific case you want to use dedicated translator, because vocabulary is specific. For example, string always means "sequence of characters" but never "underwear".
Sample configuration:
<bean class="EnglishToPolishTranslator" />
<bean class="ComputerScienceEnglishToPolishTranslator" autowire-candidate="false"/>
Everywhere EnglishToPolishTranslator will be autowired except some concrete place where ComputerScienceEnglishToPolishTranslator will be injected by reference.
Some day next customer arrive with requirement: use simpler words. The requirement is achieved by class SimpleEnglishToPolishTranslator. But computer science translator should remain unchanged: it is too costly to modify it.
Your company want keep product easy to maintain. Base application will not be modified, but for the customer the product will extended with extra library configured:
<bean class="SimpleEnglishToPolishTranslator" primary="true"/>
In result, everywhere SimpleEnglishToPolishTranslator will be used except computer science area.
Maybe it is overcomplicated, but shows a difference I found between autowire-candidate and primary
BTW, "autowire-candidate" doesn't have corresponding annotation. It looks to me that "autowire-candidate" is dead end in Spring evolution

if we configure bean for more than one time with different ids then IOC will throw an Exception. To overcome this duplicate beans problem, we can use autowire-candidate=”false” or primanry="true"
Example: i have two classes Mobile and Processor
Case -1: autowire-candidate=”false”
<bean id="mobile" class="com.Mobile" autowire="byType">
<property name="mobileName" value="Redmi"></property>
<property name="mobileModel" value="Note 5"></property>
</bean>
<bean id="process1" class="com.Processor"
autowire-candidate="false">
<property name="process" value="2GHz"></property>
<property name="ram" value="4GB"></property>
</bean>
<bean id="process2" class="com.Processor">
<property name="process" value="1GHz"></property>
<property name="ram" value="3GB"></property>
</bean>
As per above configuration, process1 bean will be ignored and process2 bean will be injected.
Case -2: primanry="true"
<bean id="mobile" class="com.Mobile" autowire="byType">
<property name="mobileName" value="Redmi"></property>
<property name="mobileModel" value="Note 5"></property>
</bean>
<bean id="process1" class="com.Processor" primary="true">
<property name="process" value="2GHz"></property>
<property name="ram" value="4GB"></property>
</bean>
<bean id="process2" class="com.Processor">
<property name="process" value="1GHz"></property>
<property name="ram" value="3GB"></property>
</bean>
As per above configuration, process2 bean will be ignored and process1 bean will be injected.

Related

How to define a PropertyPlaceholderConfigurer local to a specific bean?

I've been using org.springframework.beans.factory.config.PropertyPlaceholderConfigurer and in my experience ("citation needed" LOL) it sets the property values globally.
Is there a way to specify different PropertyPlaceholderConfigurer instances for different beans within the same application context xml?
My current code is similar to
<bean id="a" class="X">
<property name="foo" value="bar"/>
<property name="many" value="more"/>
</bean>
<bean id="b" class="X">
<property name="foo" value="baz"/>
<property name="number_of_properties" value="a zillion"/>
</bean>
I would like to do something like (pseudo-code below):
<bean id="a" class="X">
... parse the contents of "a.properties" here ...
</bean>
<bean id="b" class="X">
... parse the contents of "b.properties" here ...
</bean>
The above is non-working pseudo code to illustrate the concept; the point being, I want a different properties file to feed each bean.
WHY?
I want to have those specific properties in separate properties file and not in XML.
I think the following link can br helpful to you.
Reference Link
where #Value("${my.property.name}") annotation is used to bind the property file to a variable of type Properties which will reside in your bean class where you intend to use that properties file.
and you can define multiplte proprtiesplaceholder as below:
<bean id="myProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath*:my.properties</value>
</list>
</property>
</bean>
and use the id as reference in your bean variable to initialize properties file to the bean.
And it will be handy to include with placeholder bean.
Kindly refer Importance of Unresolvable Placeholder link for detailed info regarding its usage.
Hope this was helpful.

Spring injecting one reference bean into another reference bean

In the below spring configuration snippet, injecting reference of "SomeManager" into bean "SomeWorker" and "SomeLocal". The reference of "SomeLocal" is also injected into "SomeWorker".
My doubt is is it possible to inject the same reference of "SomeManager" injected into "SomeWorker" into another bean, like here in "SomeLocal".
Problem is if i inject it separately into "SomeWorker" and "SomeLocal" than unnecessarily there will be two instances of "SomeManager" which is basically not required in this scenario as "SomeLocal" is referred only within the "SomeWorker"
<bean id="SomeWorker" class="com.test.worker.SomeWorker">
<property name="someManager" ref="SomeManager" />
<property name="someLocal" ref="SomeLocal"/>
<bean id="SomeLocal" class="com.test.local.SomeLocal">
<property name="someManager" ref="SomeManager" />
</bean>
<bean id="SomeManager" class="com.test.manager.SomeManager"/>

Injecting additional values after initial bean initialization

I have a situation where a bean is originally defined by a project to be used in a specific runtime environment. However, this project is also used in a different runtime environment that would either
like to redefine a specific bean
or (better) inject some additional values into the already initialized bean.
I hate overwriting beans, can get very confusing, so I want to try the second option.
A more concrete example:
base.xml might include
<bean id="xxx" class="yyy">
<constructor-arg>
<map>
<entry key="key1" value="val1"/>
</map>
</constructor-arg>
</bean>
This bean is used all over the place in project A.
Project B uses project A, loads all its spring configuration, but needs to add
another value to the bean's map.
Something like.. I dunno
<bean id="xxx1" class="yyy" parent="xxx">
<property name="additionalMapValues">
<map>
<entry key="key1" value="val1"/>
</map>
</property>
</bean>
Don't really care about the new bean, I want to affect the original bean. Any way to do this?
Thanks.
If it's just additional map properties (or other collection properties) that you need in the new bean, you can use Spring's collection merging functionality. For example - similar to what you'd already shown, project A might declare:
<bean id="xxx" class="yyy">
<property name="mapValues">
<map>
<entry key="key1" value="val1"/>
</map>
</property>
</bean>
And then in project B, you can create a new bean definition that extends this - and merge in any new properties using the merge="true" attribute.
<bean id="xxx1" parent="xxx">
<property name="mapValues">
<map merge="true">
<entry key="key2" value="val2"/>
</map>
</property>
</bean>
Note that both beans would be concrete in this case. So parent bean xxx would only include key1 whereas child bean xxx1 would just include both key1 and key2.
More info here and another example here

injecting a spring bean property different values according to its context

I have a spring bean my_bean with a property my_map, and I want to inject it with the value "X" or with the value "Y". The bean:
<bean id="my_bean">
<property name="my_map">
<map>
<entry key="p" value="X" />
</map>
</property>
</bean>
It's referenced in a very deep hierarchy by the bean root_a:
<bean id="root_a">
<ref bean="root_a_a"/>
</bean>
<bean id="root_a_a">
<ref bean="root_a_a_a"/>
</bean>
<bean id="root_a_a_a">
<ref bean="my_bean"/>
</bean>
and this entire deep hierarchy is referenced again from the bean root_b. In the ref of my_bean from this hierarchy I would the property to be injected with the value "Y", but I would not like to duplicate the entire hierarchy twice.
<bean id="root_b">
<ref bean="root_a_a"/>
</bean>
How do I do this in the spring XML? can you think of a clever spring EL solution? something else? I prefer all my configuration to be done in the XML and no Java code...
By default Spring beans are singletons, which means that once bean="my_bean" is created it is shared between other components e.g. shared between A => bean id="root_a_a_a" and B => bean id="root_b_b_b"
The answer to your question depends on what exactly you are trying to achieve.
Two Beans
If bean="my_bean" does not need to be shared between A and B, then create two beans:
inject this one to A
<bean id="myBeanX" class="My">
<property name="culprit" value="X"/>
</bean>
and this one to B
<bean id="myBeanY" class="My">
<property name="culprit" value="Y"/>
</bean>
notice they both are instances of the same class.
You can also inline them into collaborators (A / B) if you don't need them for anything else:
<bean id="root_a_a_a">
<constructor-arg>
<bean class="My">
<property name="culprit" value="X"/>
</bean>
</constructor-arg>
</bean>
You can also have a factory bean that creates root_a_a_a given the property for a class My, but that would be an overkill.
Single Bean
In case A and B needs to share the exact same reference to bean="my_bean", the question is: are you ok with A and B changing my_bean's state after my_bean is created? Probably not.
If you are, which would be 0.41172% chance, you can change my_bean's value to whatever you need in A's or B's constructors => would not recommend
Hence you either would go with the Two Bean approach (which is most likely what you want), or you would need to refactor a property for "X" and "Y" into another e.g. myConfig component.
EDIT after the question was edited
If root_a and root_b will not be used together in the same instance of the context,you can use Spring Profiles (example), or SpEL / Property Based solutions (example)
e.g.
<bean id="my_bean">
<property name="my_map">
<map>
<entry key="p" value="${ENV_SYSTEM:X}" />
</map>
</property>
</bean>
It will set it to X by default, unless a ENV_SYSTEM system variable is set (e.g. to Y).

How to refer to the returned type

I want to create a spring bean as below.
<bean id="qNameString" class="javax.xml.xpath.XPathConstants.STRING"/>
Here I want the reference to return type which is a QName but I understand the way I referred is wrong. Can someone please help on this.
That won't work, because class="javax.xml.xpath.XPathConstants.STRING" makes no sense, since what you're referring to isn't a class.
You can refer to static fields using <util:constant>, as documented here:
<property name="...">
<util:constant static-field="javax.xml.xpath.XPathConstants.STRING"/>
</property>
Spring can create a QName for you like this:
<bean id="qName" class="java.xml.namespace.QName">
<constructor index="0" value="localpart"/>
<constructor index="1" value="namespaceURI"/>
</bean>
Replace localpart and namespaceURI with the local name and namespace.
To reference a constant in a class, like javax.xml.xpath.XPathConstants.STRING
<bean id="qNameString" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="targetField" value="javax.xml.xpath.XPathConstants.STRING"/>
</bean>
A shorter version is available with the util schema:
<util:constant static-field="java.xml.xpath.XPathConstants.STRING"/>
Apart from being shorter, the id of the bean will be java.xml.xpath.XPathConstants.STRING rather than qNameString.
See FieldRetrievingFactoryBean and The util schema

Resources