- Overview
- Inversion of Control in Spring
- Inversion of Control with XML Configuration
- Inversion of Control with Java Annotations
Inversion of Control (IoC) is the approach of outsourcing the construction and management of objects. And the outsourceing will be handled by an object factory.
// [FILE] MyApp.java
package com.luv2code.springdemo;
public class MyApp {
public static void main(String[] args) {
// create the object
Coach theCoach = new TrackCoach();
// use the object
System.out.println(theCoach.getDailyWorkout());
}
}
// [File] Coach.java
package com.luv2code.springdemo;
public interface Coach {
public String getDailyWorkout();
}
// [File] BaseballCoach.java
package com.luv2code.springdemo;
public class BaseballCoach implements Coach {
@Override
public String getDailyWorkout() {
return "Spend 30 minutes on batting practice";
}
}
// [File] TrackCoach.java
package com.luv2code.springdemo;
public class TrackCoach implements Coach {
@Override
public String getDailyWorkout() {
return "Run a hard 5k";
}
}
Let's see the blurb from the Spring Reference Manual:
In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
- Whenever we see Spring Bean, just think it as Java Objects.
- When Java objects are created by the Spring Container, then Spring refers to them as Spring Beans.
- Spring Beans are created from normal Java classes just like Java objects.
The primary functions of Spring Container are:
- Create and manage objects (Inversion of Control, IoC)
- Inject object's dependencies (Dependency Injection, DI)
There're three ways of configuring the Spring Container:
- XML Configuration file (legacy, but most legacy applications still use this)
- Java Annotations (modern)
- The special lables/markers added to Java classes.
- Provide meta-data about the class.
- Processed at compile time or run-time for special processing.
- Spring will scan the Java classes for special annotations and register the beans in the Spring Container automatically.
- Java Source Code (modern)
The development process of Spring IoC can be summaried as steps below:
- Configure the Spring Beans.
- Create a Spring Container.
- In the Spring world, a Spring Container is generically known as
ApplicationContext
. - e.g.
ClassPathXmlApplicationContext
,AnnotationConfigApplicationContext
,GenericWebApplicationContext
, others...
- In the Spring world, a Spring Container is generically known as
- Retrieve Beans from Spring Container.
The development process of Spring IoC can be summaried as steps below:
- Enable Component Scanning in Spring Config File.
- Add the
@Component
Annotation to the Java Classes. - Retrieve Beans from Spring Container.
The development process of Spring IoC can be summaried as steps below:
- Create Java Class and Annotate as
@Configuration
. - Add Component Scanning Support with
@ComponentScan
(optional). - Read Spring Java Configuration Class.
- Retrieve Bean from Spring Container.
First, add the applicationContext.xml
to the src
folder:
<?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">
<!-- Define your beans here -->
<bean id="myCoach"
class="com.luv2code.springdemo.TrackCoach">
</bean>
</beans>
- The
id
is like an alias. - The
class
should be the fully qualified class name of implementation class.
Now, load the spring configuration file and retrieve bean from the spring container:
package com.luv2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloSpringApp {
public static void main(String[] args) {
// load the spring configuration file
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// retrieve bean from spring container
Coach theCoach = context.getBean("myCoach", Coach.class);
// call methods on the bean
System.out.println(theCoach.getDailyWorkout());
// close the context
context.close();
}
}
- The first parameter in
context.getBean()
should be the bean id. - The second parameter in
context.getBean()
should be the interface. - When we pass the interface to the method, Spring will cast the object for us behind the scenes.
Add applicationContext.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">
<!-- add entry to enable component scanning -->
<context:component-scan base-package="com.luv2code.springdemo" />
</beans>
- The
base-package
should be the name of the package.
Create a package named com.luv2code.springdemo
and interface Coach.java
:
package com.luv2code.springdemo;
public interface Coach {
public String getDailyWorkout();
}
Then create the class TennisCoach.java
implementing interface Coach
and add the @Component
annotation:
package com.luv2code.springdemo;
import org.springframework.stereotype.Component;
@Component("thatSillyCoach")
public class TennisCoach implements Coach {
@Override
public String getDailyWorkout() {
return "Practice your backhand volley";
}
}
- The
"thatSillyCoach"
would be the bean id. - If we don't give the bean id, the default bean id would be the class name but making first letter lower-case. Special case when BOTH the first and second characters of the class name are upper case, then the name is NOT converted.
- e.g. The default bean id of class
TennisCoach
would betennisCoach
. - e.g. The default bean id of class
RESTFortuneService
would beRESTFortuneService
.
- e.g. The default bean id of class
package com.luv2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnotationDemoApp {
public static void main(String[] args) {
// read spring config file
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// get the bean from spring container
Coach theCoach = context.getBean("thatSillyCoach", Coach.class);
// call a method on the bean
System.out.println(theCoach.getDailyWorkout());
// close the context
context.close();
}
}