Spring by Durgesh
Spring by Durgesh
Dependency injection is a pattern we can use to implement IoC, where the control being
inverted is setting an object's dependencies.
Connecting objects with other objects, or “injecting” objects into other objects, is done by an
assembler rather than by the objects themselves.
Here Geeta object is dependent on Ramu object. So we don't required to create Geeta object.
We give control to spring to create object of Geeta and spring inject Geeta object into Ramu
Object. This process called Inversion of Control (IOC).
What Is Inversion of Control?
Inversion of Control is a principle in software engineering which transfers
the control of objects or portions of a program to a container or framework.
We most often use it in the context of object-oriented programming.
We used to create DAO layer in jdbc to connect with database where we create every object
with new keyword. In DAO layer we create methods with database queries and in
Business/service layer we write logical code and create DAO object in business layer with new
keyword which is tight coupling . If we change DAO layer then we have to change all in business
layer. So we don't recommend to create object with new keyword, that's why we used spring to
create automatic object. Which inject one object into another object by xml file or by
annotation.
Overview of Spring Framework Modules | Spring
Core | Spring Data Integration | Spring Web
Application context:
It is an interface represents spring IOC container.
It extends beanFactory.
It has its own properties and beanFactory properties.
We can access all values of object present in spring container with the
help of Application Context. But it is an interface so we have to make
a class which implements Application Context interface.
So we have three classes for access data which implement Application
Context interface.
1. ClassPathXmlApplicationContext – this class search xml
configuration in java class path.
2. FileSystemXmlApplicationContext – this class search xml
configuration from file.
3. AnnotationConfigApplicationContext – this class search those
beans on which we used annotation.
The ApplicationContext Interface
One of the main features of the Spring framework is the IoC (Inversion of
Control) container. The Spring IoC container is responsible for managing the
objects of an application. It uses dependency injection to achieve inversion
of control.
The interfaces BeanFactory and ApplicationContext represent the Spring IoC
container. Here, BeanFactory is the root interface for accessing the Spring
container. It provides basic functionalities for managing beans.
On the other hand, the ApplicationContext is a sub-interface of
the BeanFactory. Therefore, it offers all the functionalities of BeanFactory.
Furthermore, it provides more enterprise-specific functionalities. The
important features of ApplicationContext are resolving messages, supporting
internationalization, publishing events, and application-layer specific
contexts. This is why we use it as the default Spring container.
For setter-based DI, the container will call setter methods of our
class after invoking a no-argument constructor or no-argument static factory
method to instantiate the bean. Let's create this configuration using
annotations:
Constructor-Based Dependency Injection
In the case of constructor-based dependency injection, the container will
invoke a constructor with arguments each representing a dependency we want to
set.
package com.spring.MavenProjectSpring.beans;
public Student() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Student [id=" + studentId + ", name=" + studentName + ", address=" + studentAddress + "]";
}
}
Spring.config.xml file:
<property name="studentNmae">
<value>Lalit</value>
</property>
<property name="studentAddress">
<value>Panipat</value>
</property>
</bean>
</beans>
package com.spring.MavenProjectSpring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.MavenProjectSpring.Student;
Spring.config.xml file:
</bean>
</beans>
package com.spring.MavenProjectSpring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.MavenProjectSpring.Student;
</beans>
<property name="addresses">
<set>
<value>Panipat</value>
<value>Delhi</value>
<value>Mumbai</value>
</set>
</property>
<property name="courses">
<map>
<entry key="java" value="2 months"/>
<entry key="python" value="6 months"/>
<entry key="Spring" value="3months"/>
</map>
</property>
</bean>
</beans>
import java.util.List;
import java.util.Map;
import java.util.Set;
public Employee(String name, List<String> phones, Set<String> addresses, Map<String, String> courses) {
super();
this.name = name;
this.phones = phones;
this.addresses = addresses;
this.courses = courses;
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
System.out.println(emp1.getName());
System.out.println(emp1.getPhones());
System.out.println(emp1.getAddresses());
System.out.println(emp1.getCourses());
}
}
</bean>
</bean> -->
</beans>
A bean/pojo file:
package com.spring.core.reference;
public class A {
private int x;
private B b;
public A(int x, B b) {
super();
this.x = x;
this.b = b;
}
public A() {
super();
// TODO Auto-generated constructor stub
}
public B getB() {
return b;
}
@Override
public String toString() {
return "A [x=" + x + ", b=" + b + "]";
}
public class B {
private int y;
public B(int y) {
super();
this.y = y;
}
public B() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "B [y=" + y + "]";
}
package com.spring.core.reference;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
}
Constructor Injection:
Constructor.config.xml 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"
xmlns:context="
https://www.springframework.org/schema/context"
xmlns:p="https://www.springframework.org/schema/p"
xmlns:c="https://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<constructor-arg>
<value>"111"</value>
</constructor-arg>
<constructor-arg>
<value>"Lalit"</value>
</constructor-arg>
</bean> -->
</beans>
@Override
public String toString() {
return this.name + ":" + this.id + ":" + this.certificate;
}
}
Certificate bean/pojo file:
package com.spring.constructor.injection;
@Override
public String toString() {
return " " + this.certificate;
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
}
Ambiguity Problem and its Solution with Constructor
Injection
In <constructor-args> tag every property treated as String. If in
corresponding class has String arguments constructor that constructor
called by spring. If not String arguments constructor then 1st top
contstructor will be called by spring.
If we want a specific constructor will call by spring then we have to
put 'type' attribute in <constructor-args> tag.
Configuration.xml file:
</bean>
</beans>
Bean/pojo class:
package com.springCore.lifeCycle;
public Samosa() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return " " + price;
}
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
}
}
Bean/pojo class:
package com.springCore.lifeCycle;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public Pepsi() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Pepsi [price=" + price + "]";
}
Config.xml 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"
xmlns:context="
https://www.springframework.org/schema/context"
xmlns:p="https://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean class="com.springCore.lifeCycle.Pepsi" name="pepsi">
<property name="price" value="90" />
</bean>
</beans>
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
}
}
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public Example() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Example [example=" + example + "]";
}
@PostConstruct
public void start() {
System.out.println("this method works as init() method");
}
@PreDestroy
public void end() {
System.out.println("this method works as destroy() method");
}
}
Config.xml 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"
xmlns:context="
https://www.springframework.org/schema/context"
xmlns:p="https://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
</beans>
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
}
}
Bean/pojo class:
Employee class:
package com.spring.core.autowire;
public Employee() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Employee [address=" + address + "]";
}
Address class:
package com.spring.core.autowire;
@Override
public String toString() {
return "Address [street=" + street + ", address=" + address + "]";
}
configuration 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"
xmlns:context="
https://www.springframework.org/schema/context"
xmlns:p="https://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
byType:
Constructor:
package com.spring.core.autowire;
public Employee() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Employee [address1=" + address1 + ", address2=" + address2 + "]";
}
}
@Autowired Annotation for Autowiring
We have to enable @Autowire annotation in configuration file.
Annotation-Based Configuration
<context:annotation-config/>
Bean class:
package com.spring.core.autowire.annotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@Autowired
@Qualifier("address2")
private Address1 address;
public Employee1() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Employee [address=" + address + "]";
}
Xml 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
Bean/pojo class:
package com.standalone.application;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@Override
public String toString() {
return "Person [friends=" + friends + ", feeStr=" + feeStr + ", properties=" + properties + "]";
}
Xml 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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<property name="feeStr">
<ref bean="fees"/>
</property>
<property name="properties">
<ref bean="dbconfig"/>
</property>
</bean>
</beans>
package com.standalone.application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
System.out.println(p1.getFriends().getClass().getName());
We can change our bean name with the help of @Component("Our own
bean name"). otherwise @Component annotation will take Class name
in camel case.
In other words, without having to write any explicit code, Spring will:
Scan our application for classes annotated with @Component
Instantiate them and inject any specified dependencies into them
Inject them wherever needed
They all act the same because they are all composed annotations
with @Component as a meta-annotation for each of them. They are
like @Component aliases with specialized uses and meaning outside of
Spring auto-detection or dependency injection.
However, there are other areas of Spring that look specifically for
Spring's specialized annotations to provide additional automation
benefits. So, we should probably just stick with using the established
specializations most of the time.
Bean/pojo class:
package com.spring.core.stereotype;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("student1")
public class Student {
@Value("Lalit")
private String name;
@Value("panipat")
private String city;
@Override
public String toString() {
return "Student [name=" + name + ", city=" + city + "]";
}
}
Xml file:
<context:component-scan base-package="com.spring.core.stereotype"/>
</beans>
package com.spring.core.stereotype;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new
ClassPathXmlApplicationContext("com/spring/core/stereotype/stereo.conf
ig.xml");
Student s1 = context.getBean("student", Student.class);
System.out.println(s1);
}
<context:component-scan base-package="com.spring.core.stereotype"/>
</util:list>
</beans>
package com.spring.core.stereotype;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("student1")
public class Student {
@Value("Lalit")
private String name;
@Value("panipat")
private String city;
@Value("#{list}")
private List<String> country;
@Override
public String toString() {
return "Student [name=" + name + ", city=" + city + ", country=" +
country + "]";
}
}
Removing Complete XML for Spring Configuration |
@Configuration | @ComponentScan | @Bean Annotation
@ComponentScan
Before we rely completely on @Component, we must understand that it's
only a plain annotation. The annotation serves the purpose of
differentiating beans from other objects, such as domain objects.
However, Spring uses the @ComponentScan annotation to actually gather
them all into its ApplicationContext.
Pojo/bean class:
package com.spring.core.javaconfig;
import org.springframework.stereotype.Component;
@Component("firstStudent")
public class Student {
}
Our own configuration file:
package com.spring.core.javaconfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.spring.core.javaconfig")
public class JavaConfig {
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
}
}
@Bean:
1. We can use @Bean annotation for declaring bean in our own
configuration file.
2. We want to get object of our pojo/class then we have to create a
method which return same object in our configuration file and use
@Bean annotation on that method.
3. From our pojo class we remove @Component annotation and from our
configuration file we remove @ComponentScan annotation.
4. Our bean name will be same as our method name.
5. But we can change our bean name by using @Bean(name= "bean_name")
Bean/pojo class:
package com.spring.core.javaconfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@Value("Lalit")
private String firstName;
@Value("Bizlain")
private String lastName;
@Autowired
public Address address;
@Override
public String toString() {
return "Student [firstName=" + firstName + ", lastName=" + lastName + ", address=" +
address + "]";
}
package com.spring.core.javaconfig;
import org.springframework.beans.factory.annotation.Value;
@Override
public String toString() {
return "Address [add=" + add + "]";
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfig {
@Bean
public Address getAddress() {
return new Address();
}
@Bean(name ="student")
public Student getStudent() {
return new Student();
}
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
}
}