Spring bean get initialized twice by xml and component-scan - java

I have created few singleton bean in spring. I added log inside constructor. I could see log is getting printed twice.
#Component
public class User{
public User() {
System.out.println(" Bean got initialized"+this);
}
private Integer userid;
private String username;
//getter and setter
}
I have defined bean in XML and configured auto-scan.
<context:component-scan base-package="com.demo" />
<bean id="user" class="com.demo.User"/>
Since I have initialized bean in context xml and package scan, bean is getting initialized twice. After removing #Component from class, I am seeing only once log.
Please confirm my understanding is correct or not?

That's correct; the component scan will pick it up, and then you explicitly create another copy.

#Component annotation was introduced in spring 2.5 in order to get rid of XML bean definition by using classpath scanning. if the class is annotated with #Component, it will auto detected in the classpath scanning and an instance will be created(instantiated). Since #Component does the job for creating the bean, you do not have to declare the bean in XML. So remove the XML bean declaration. so it will not create duplicate objects.
Note: if you do the annotation based bean declaration with #Component, you do not need to use XML based declaration as you have done. If you are doing the XML based bean declaration, you do not need to do the annotation based bean declaration. So make sure that you declare only one of these options. not with both.

Related

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.

How setter works inside Spring Framework?

I'm new in spring Framework. And actually i was doing an experiment with spring actually.
Look at this HelloWorld.java:
public class HelloWorld {
private String messageee;
public void setMessage(String messageee){
this.messageee=messageee;
}
public void show(){
System.out.println("message: "+messageee);
}
}
You see in this program, I've one variable which is outside declared as private named as messageee and next variable which is parametrized with setter named as messageee. You see both have same name.
Okay.. Now look at this bean file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloWorld" class="com.springframework.HelloWorld">
<property name="message" value="Hello.. This is Spring Framework example."></property>
</bean>
</beans>
Here you see inside bean tag. I've declared the property name as message. I don't understand, when i give the name as messageee it gives an error as:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloWorld' defined in class path resource [beans.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'messageee' of bean class [com.springframework.HelloWorld]: Bean property 'messageee' is not writable or has an invalid setter method. Did you mean 'message'?
But when i give the name as message. It runs successfully. But i don't have any message's method or any kind of variables with this similar name. So, How setter works actually? Will you please elaborate?
Help would be appreciated!
You're confusing fields (or instance variables) with properties.
property is a term coming from the Java Beans specification. A property foo of a bean is data that can be accessed using a getter method called getFoo() (or isFoo() for a boolean) and/or set using a setter method called setFoo().
What these methods do internally, whether they get/set a variable or not, whether the variable is also named foo or anything else, is completely irrelevant. What matters is the name of the getter/setter.
So, when you define your bean and tell Spring to set the property named message, Spring will look for a method called setMessage(). It doesn't care about the private fields of your bean class.
The Spring IoC container also supports setter injection, which is the preferred method of dependency injection in Spring. Setter injection uses the set* methods in a class file to garner property names that are configurable in the spring XML config.
From a configuration standpoint, setter injection is easier to read because the property name being set is assigned as an attribute to the bean, along with the value being injected.
To determine the property names, Spring follows the JavaBeans Specification.
First of all, you are mixing up fields with properties - also your property name in the applicationContext.xml is wrong (it should be messageee)
You need to use #Autowired annotation with either:
1) fields i.e. messageee
or
2) setter i.e. setMessage()
If you are thinking "what is that!!???" Read about Spring's basic features with beans and how Spring is capable of taking POJOs (Plain Old Java Objects) to and configure them using the IoC framework. Read about #Autowired here - How does autowiring work in Spring?
Then you should be fine with this:
<bean id="helloWorld" class="com.springframework.HelloWorld">
<property name="message" value="Hello.. This is Spring Framework example."></property>
</bean>
BTW...good approach for looking into Spring by using the very basic Java stuff....good luck!

Spring: Xml based Autowiring a list of beans by interface type

With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.

How do I set a property on a bean annotated with #Component after creation?

I have an annotated bean with #Component that gets built using <context:component-scan/>, however I wish to set a boolean property after this has been created from a value within a properties file using <context:property-placeholder/>.
Annotate the field with #Value("propertyName").
See related question: Spring #Value annotation in #Controller class not evaluating to value inside properties file

Spring annotations and XML configuration

I was reading Spring 3.0 documentation and I came to the sentence -
Annotation injection is performed before XML injection, thus the latter configuration
will override the former for properties wired through both approaches.
Next the question came to my mind:
If I use an annotation in a bean (like #Service("myService")), now I am using the other bean and it uses "myService", and "myService" would be injected through XML configuration.
Would this work? I tried but it is giving me
BeanCreationException (Cannot resolve reference to bean 'myService' while setting bean property 'myService')
Later, I went through this question Wiring Spring bean through annotations and xml context, but in the solution it is told that "Just leave all your annotated fields unspecified, and they'll get injected auto-magically." (I didn't try out this solution)
But what if I want to specify all annotated fields, like I specified #Service annotation above?
Any suggestions??
I figured out the answer, it works very well. Actually I forgot to add tag in xml configuration. We need to add this tag in each config file i.e. if you have written config file for service layer beans, add tag for service layer annotated beans. Similar for dao and controller layers.
You need to autowire your constructor like below...
#Autowired(required=true)
public UserService(DataSource dataSource){
this.userDS = new UserDS(dataSource);
}
So, in the above code the DataSource will be injected in the UserService automatically.

Categories

Resources