First things first, when we talk out spring it is necessary to understand concept of "Dependency Injection". In any non trivial application java objects collaborate to pursue a given piece of work, In this process objects depends on few other objects. Consider the below example:
Spring strongly supports idea of test driven application where testing should not be compromised because of dependent objects. So spring provides implementation of Dependency Injection where object does not need to look for its dependent objects rather spring will provide you objects you are depending on. i.e in short, it is inverting the process of how objects will be given its dependencies (hence some people call it as Inversion of Control) too.
In Spring you define object's dependents (objects they work with) in the form of
Spring bean configuration file is just a blue print/recipe on how objects need to be created. Container looks in to it and instantiated objects based on below:
In the above example class ConsoleMessageWisher is depending on an object called "wishingMessage" (of type String) so when we write test cases for this object we are entirely depending up on this dependent object. Imagine a situation when you are depending upon some Datasource object, you must provide implementation of it during testing. This make objects as "tightly coupled" with each other.
Spring strongly supports idea of test driven application where testing should not be compromised because of dependent objects. So spring provides implementation of Dependency Injection where object does not need to look for its dependent objects rather spring will provide you objects you are depending on. i.e in short, it is inverting the process of how objects will be given its dependencies (hence some people call it as Inversion of Control) too.
In Spring you define object's dependents (objects they work with) in the form of
- arguments to constructors (a)
- arguments to factory method (b)
- arguments set on an object after constructed (c)
- arguments set on an object after created via a factory/static method.(d)
we could see it as spring framework dependency injection concept telling us it is "injecting" its dependencies to the objects. In the above bullet list (a) is called as "Constructor Injection", (c) is called as "setter method" injection. Where as (b) and (d) are usually referred as variants of (a) and (c). "Spring Container" manages all these beans and their dependencies and provide you fully packed bean instance when you ask for (i.e all its dependencies are injected completely.)
Consider spring constrainer is the machine responsible for configuring/assembling, instantiating, managing all beans in the container. Spring comes with several implementation of bean factory our of org.springframework.beans.factory.BeanFacory is the basis of bean factory. It is not certainly the most widely used container. Typically you use one of the implementations of ApplicationContext (org.springframework.context package have this) such as ClassPathXMLApplicationContext or AnnotationConfigApplicationContext. ApplicationContext provides advanced features than BeanFactory such as i18n, Event handing, application layer specific contexts such as WebApplicationContext. Container (either BeanFactory/ ApplicationContext) receives meta data information (as XML/Annotations/Java Class) regarding how beans need to composed with dependencies populated.
(source: spring reference)
From the above XML, for a top level <beans> element we would have usually one or more child <bean> element which represents beans to be managed by this container. Each <bean> element would have an "id" attribute used to indicate a unique bean (you could have optional "name" attribute which are comma/space separated string used for referencing same bean with multiple names. Its like aliasing) . "class" attribute defines the fully qualified class name form which the instance need to be created. This bean is depending on one property called "wishingMessage" and it provided with its definition inside a <bean> element.Consider spring constrainer is the machine responsible for configuring/assembling, instantiating, managing all beans in the container. Spring comes with several implementation of bean factory our of org.springframework.beans.factory.BeanFacory is the basis of bean factory. It is not certainly the most widely used container. Typically you use one of the implementations of ApplicationContext (org.springframework.context package have this) such as ClassPathXMLApplicationContext or AnnotationConfigApplicationContext. ApplicationContext provides advanced features than BeanFactory such as i18n, Event handing, application layer specific contexts such as WebApplicationContext. Container (either BeanFactory/ ApplicationContext) receives meta data information (as XML/Annotations/Java Class) regarding how beans need to composed with dependencies populated.
(source: spring reference)
Sample Spring Bean Configuration (XML style)
Firing up Container
Once above bean definition's meta data is given to container, we need to instantiate container to do its work (like creating a bean with its dependencies populated). It is always preferable to write classes by their interfaces reason is we could use run time polymorphism to provide custom implementations with out changing client's code. For example consider below code:
From this its clear that we are firing one of the implementations of ApplicationContext and passing input meta information. Once we run this code we get below output.
Spring Bean Overview
When we pass multiple <bean> elements under <beans> element, internally each <bean> element represents an BeanDefinition object. This object consists of all metadata of a bean like its name, fully qualified class, references to other beans etc... Each <bean> will have a unique id and possible multiple names given under "name" attribute separated by comma or semicolon or space character. Prior to spring 3.1 id was of type xsd:ID but in spring 3.1 its made as xsd:string so no restrictions on characters you choose for name and id attributes of a <bean> element.You are not required to give id or name (in this case container will give a name to it, this is the motivation for inner beans and auto-wiring collaborators). Following piece explains us how to use alias tag to refer same bean with multiple names/aliasing (quite useful when we assemble multiple systems where each sub system refers same bean with different name)
Instantiating Bean in Container
Spring bean configuration file is just a blue print/recipe on how objects need to be created. Container looks in to it and instantiated objects based on below:
- calling constructor of a given class specified under "class" attribute using reflection (its like creating object using "new" operator)
- calling static factory method given under "factory-method" attribute of given class under "class" attribute. This is a rare case. Note: Object returned form this method may not be the same class or altogether a separate entity.
- (third variety but very less) is instantiating beans using factory method of an given instance.
Instantiation with constructor
Spring can manage technically any bean inside the container. The class does not need to implement any classes/interfaces as such. Depending upon type of IOC (constructor/setter method) you may need to provide a empty constructor. As you notice, if you provide any non-default constructor java will not provide any default constructor hence when you instantiate beans, it fails due to non availability of default constructor (you get Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.mastspring.lesson01.ConsoleMessageWisher]: No default constructor found;).
with this you get above mentioned error when you try to instantiate bean form container. So you must provide a default constructor as we are using constructor based IOC here.
Above example outlines various ways to set constructor or property arg values to beans. Inner beans are a special concept where bean definitions are written inside <bean> element itself (these beans can not be access from other bean elements). We cant inject inner beans into any other beans except enclosing bean where inner bean id defined..
when container is creating beans if it find a circular dependency such as Bean A depends on Bean B and at the same time, Bean B depending on Bean A then we get BeanCurrentlyInCreationException.
Inner Bean are beans with <bean> element inside a <constructor-arg> or <property> tag. It does not require a id or name attribute. Even if we keep container ignores them. Even if we keep id we cant inject these beans to other beans except the one enclosed to it.
We can configure lists, maps, properties and sets as bean properties as well. Below example show that. While in this example observer wherever we are referring a bean reference, we are keeping value-ref rather value
Based on this this example its clear that we can keep any following element like "bean, ref, idref, list, map, set, proprs, null,value". We can not keep blank strings wherever it is needed to pass null values so spring gives us a special element called <null/> to denote we are intending to pass null value to the bean property. Starting spring 2.0 concept called "Collection Merging" is used for merging collections inherited from parent to child, but this involves understanding of parent-child container mechanism. So we will see this in detail when we get there..
Instantiation with static factory method
Spring allows instantiation of objects through factory method in support of legacy code where instantiation is done by factory methods. In this case we use "factory-method" attribute to denote the name of the method to be called to instantiate the object. Note that, parameters you are passing to the bean definition are NOT to constructor. Rather you are passing to create bean instance so factory method receive them (Imp to remember this) Consider below bean definition.
then consider respective code too.. Below outcome generated form execution...
So the same logic applies to instantiating object using factory-method of factory bean whose reference is given under "factory-bean" property of the bean..
then consider respective code too.. Below outcome generated form execution...
So the same logic applies to instantiating object using factory-method of factory bean whose reference is given under "factory-bean" property of the bean..
Understanding Dependencies:
Constructor Based DI (Setting dependencies by Constructor)
It is the process of container invoking constructor with number of arguments (each argument represents a dependency) to instantiate the bean object. This approach is same as calling a static method with arguments and is very near to this approach (including the way you pass arguments to constructor/static-method). In this tutorial following examples show you how to instantiate a bean by providing all dependencies as constructor arguments. Constructor argument resolution matching happens by "type". If there is no ambiguity the order arguments are defined, the same order arguments will be passed to underlying constructor. Occasionally, you could use "type" attribute or "index" (zero based) attribute to solve ambiguity problem. Say if you have argument of type Boolean and you need to pass "true" value then by default it assumes "true" as a string. But you could mention its type by setting "type" attribute as "boolean"
Setter Based DI (Setting dependencies by calling setter methods)
in this process, container calls setter methods on bean once its created by calling a default constructor or no argument static factory method.You can always mix and match constructor based and setter based DI. Following example covers all theory in detail:
Fro the above example, once we run the main program output would be like below:Above example outlines various ways to set constructor or property arg values to beans. Inner beans are a special concept where bean definitions are written inside <bean> element itself (these beans can not be access from other bean elements). We cant inject inner beans into any other beans except enclosing bean where inner bean id defined..
when container is creating beans if it find a circular dependency such as Bean A depends on Bean B and at the same time, Bean B depending on Bean A then we get BeanCurrentlyInCreationException.
Dependencies and Configuration in Detail:
as mentioned in previous example, we can define bean properties and constructor arguments as references to other managed beans or defined values. We have <property> and <constructor-arg> to support this.. The value attribute of <property> tag specifies human readable string representation of the bean properties. Underlying PropertyEditors will convert these string to respective data types (like int/double etc...)
idref: this element allow to pass "id" of an bean as a constructor argument/property to another bean. Here we are passing the string value not the reference as such. The advantage of this tag is container performs a check at deployment time that whether referenced bean really exists or not
Similarly we use <ref element to refer another spring managed bean as an cons argument or property for another bean. The referenced bean is a dependency of the bean whose property will be set, and it gets initialised before the property has been set.
<ref bean="MyBeanName"/>Above usage indicates that MyBeanName is the id of another spring manager bean in the container. You could specify it as local like below to make sure XML parser ensures that there is another bean with given name exists in the container... In the below example Parser validates whether a bean with id CoffeeBean exists in the container.
<ref local="CoffeeBean"/>
Inner Bean are beans with <bean> element inside a <constructor-arg> or <property> tag. It does not require a id or name attribute. Even if we keep container ignores them. Even if we keep id we cant inject these beans to other beans except the one enclosed to it.
<bean id="id1" class="com.test.FunnyBean"> <property name="person"> <bean class="com.test.Person"> <!-- inner bean --> <property name="name" value="Rowan Atkinson"/> </bean> </property> </bean>
We can configure lists, maps, properties and sets as bean properties as well. Below example show that. While in this example observer wherever we are referring a bean reference, we are keeping value-ref rather value
Based on this this example its clear that we can keep any following element like "bean, ref, idref, list, map, set, proprs, null,value". We can not keep blank strings wherever it is needed to pass null values so spring gives us a special element called <null/> to denote we are intending to pass null value to the bean property. Starting spring 2.0 concept called "Collection Merging" is used for merging collections inherited from parent to child, but this involves understanding of parent-child container mechanism. So we will see this in detail when we get there..
Depends-on, Lazy Initialised Beans, Auto Wiring of Bean:
In the previous example I mentioned about parent child bean definitions. So let us take an example and understand this concepts along with auto wiring of beans. Before that lets understand "depends-on" and lazy initialised beans. By default spring container created beans as "singletons" i.e there will be only instance of bean in the given container (not per class loader but per container) this is desirable to identify error at the instantiation time itself. We can tell container to NOT to instantiate the bean on start up but to do when its first time needed by setting a flag called "lazy-init" to "true". However if bean A is a singleton and depending on Bean B which is a lazy init, in this case sprig container instantiates B irrespective of its lazy init because A is a singleton.<bean id="myCostlyStarbuckBean" class="com.coffee.StarBucksBean" lazy-init="true"/>Similarly, when we are passing dependencies, they might not be direct references or so, take an example like a static method need to be triggered before setting this object as a dependency on another bean then depends-on comes for rescues. The "depends-on" attribute can force beans to be initialised before they are used by other beans.
<bean id="beanA" class="com.springlearning.A" depends-on="B,C"> <property name="test" ref="B" /> </bean> <bean id="B" class="com.springlearning.B" /><bean id="C" class="com.springlearning.C" />
now comes the interesting bits of auto wiring.. In this same example we go through parent, child beans as well.. First of all auto-wiring is the process of container resolving bean dependencies for you. i.e you no need to explicitly mention bean's constructor arguments or properties using tags. There are 4 different ways to achieve this:
Mode | Explanation |
---|---|
no | (Default) No autowiring. Developer need to explicitly set using ref element. For larger deployments better not change this setting so you get clarity on which bean depending on other bean, |
byName | Spring looks for a bean with the same name as the property that needs to be autowired. |
byType | Allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown, which indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set. |
constructor | Analogous to byType, but applies to constructor arguments. If there is not exactly one bean of the constructor argument type in the container, a fatal error is raised. |
Following example explains this is much better way
in the above example if you simply delete "autowire" attribute from XML then you get following output, because container no way knows how to perform auto write the 2 constructor arguments to FunnyCompany bean.
if you keep it as "byName" you get below output.. Because there is one bean called "canteenService" whose name matching with FunnyCompany's constructor's first argument name
if you keep it as "byType"/"constructor" then outcome would be and the moment you enable bean called "fingerPrintService1" then exception will be thrown and there is an ambiguity on two beans exists of same type. In the below outcome if you see though we did not mention referenced beans explicitly container is able to identify based on the type of the beans..
One more thing to observe here is, "securityService" is defined as an "abstract" bean means we can not instantiate this bean (its exactly like java abstract classes) and child bean "fingerPrintService" is inheriting this bean and hence only setting "scannerMachineName" value while inheriting "typeOfSecurity" form parent bean.
Based on this discussion we do have following issues/limitations with auto wiring:
if we set any values in <property> or <constructor-arg> then they override auto wiring values. And we can not auto wire simple properties like primitives, Strings etc..
It is not as clear as explicit wiring. So to avoid ambiguity, avoid auto wiring for large projects.
If you do not want a particular bean to NOT to be auto wired then set "autowire-candidate" attribute to false for that bean.
Based on this discussion we do have following issues/limitations with auto wiring:
if we set any values in <property> or <constructor-arg> then they override auto wiring values. And we can not auto wire simple properties like primitives, Strings etc..
It is not as clear as explicit wiring. So to avoid ambiguity, avoid auto wiring for large projects.
If you do not want a particular bean to NOT to be auto wired then set "autowire-candidate" attribute to false for that bean.
Method Injection:
In most of the cases, spring container creates beans as singletons. In cases where a singleton bean has dependency on another singleton bean (or vice versa, a non singleton bean aka prototype bean has a dependency on another non singleton bean) then we can configure using <ref element. But the real problem is a singleton bean has a dependency on another non singleton bean. Say take an example, Bean A is a singleton and it has dependency on Bean B. So when A gets instantiated (at that point of time) B will set as its dependency. Further invocations of A will not give us latest/new bean called B (remember, B is a prototype bean so each time a new bean instance will be produced). In these situations how do we ensure every invocation of A will get us latest/new instance of Bean B. This leads us to method injection concept. One way to handle this issue is, implement Bean A as it implements ApplicationContextAware interface (so you get access to ApplicationContext) with that, every time you call getBean("B") you ask container to produce a new Bean. But issue, here we are coupling the code to spring (intrusiveness).
Alternative to write non intrusive code is using "Look up method injection". In this method container uses its ability to override methods on container managed beans, to return the lookup result for another bean in the container. Usually, lookup involves a prototype bean using CGLIB (to generate a dynamic subclass and override that method), As you know we cant override final methods, do not mark your method which will return prototype bean as final method.
then from the above code, we marked createBeanB() as abstract and the subclass (generated from CGLIB) will implement this method. But how does it know it need to create a bean of class BeanB? answer is below. Here we are just mentioned when you create MethodInjectionBean, we need to look up for a method called "createBeanB" and its implemention (provided by CGLIB) will give us a freshly brewed new bean called "b" every time you access.. Is nt it simple?
<!-- a stateful bean deployed as a prototype (non-singleton) --> <bean id="b" class="com.mastspring.lesson01" scope="prototype"><!-- inject dependencies here as required --> </bean> <bean id="MethodInjectionBean" class="com.mastspring.lesson01"> <lookup-method name="createBeanB" bean="b"/> </bean>
p-namespace and c-namespace:
p-namespace short for property name space, allows us to use <bean> element's attributes directly to set properties rather explicitly using child <property> elements..
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="me-classic" class="com.example.Person"> <property name="name" value="John Doe"/> <property name="spouse" ref="jane"/> </bean> <bean name="me-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> <bean name="jane" class="com.example.Person"> <property name="name" value="Jane Doe"/> </bean> </beans>
this example from reference documentation is using p namespace. If you see "spouse-ref" its indirectly saying spouse is a ref element (not a direct string property rather a reference to another bean), Imagine if your property name ends with -ref then those situations we cant use p name space.. The c name space short of constructor name space does the same thing to pass constructor arguments.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <-- 'traditional' declaration --> <bean id="foo" class="x.y.Foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> <constructor-arg value="foo@bar.com"/> </bean> <-- 'c-namespace' declaration --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"> </beans>
great job buddy thanks for this post,your post totally covered all the topics of java spring framework and i'm very delighted to read your post
ReplyDeleteBest Dot Net Training in Chennai
Best Software Testing Training Institute in Chennai
Java Training with Placement
Best PHP Training Institutes