One of the most important parts of the Spring framework is the Spring IoC Container. The container behaves as a factory of beans. We provide the configuration metadata to the container and the container provides us the instances of beans along with their dependencies. The configuration metadata can be provided by XML file or Java annotations, or Java code. The configuration metadata contains how to instantiate beans, where to inject dependencies etc.
XML-Based configuration
Most of the time, we will use annotation based configuration. But to show you how XML based confirmation, first create a few Java classes.
Suppose we have a Vehicle
class that depends on the Engine
class to start.
public interface Engine {
void start();
}
public class EngineImpl implements Engine {
public void start() {
System.out.println("Starting engine...");
}
}
public class Vehicle {
private Engine engine; // dependency
public void setEngine(Engine engine) {
this.engine = engine;
}
public void start() {
engine.start();
}
}
As Vehicle
class dependents on an implementation of Engine
interface, you have to inform Spring container via configuration that whenever you request a Vehicle instance, container must return that instance along with the engine field populated. In XML based configuration we provide that configuration using <bean>
elements.
We will create a file called spring-config.xml
under the src/main/resources
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="vehicle" class="com.kcs.service.Vehicle">
<property name="engine"><ref bean="engineBean"/></property>
</bean>
<bean id="engineBean" class="com.kcs.impl.EngineImpl" />
</beans>
As you can see, we have declared 2 beans with unique id. Also we have used the ref
attribute to assign a bean with id engineBean
to the engine
property of vehicle bean. Please note, we must have a setter method for the field engine. You can also specify constructor arguments, but let’s not go into detail. We already know how to configure constructor injection using annotation.
Java-based configuration
In the case of Java-based configuration, instead of an XML file, we create a configuration class that is annotated with @Configuration
annotation. Inside this class we create methods that are annotated with @Bean
annotation. From those methods, we construct and return bean instances. Consider @Bean
annotation equivalent to <bean>
element. Spring container will use method name as the bean name. When you request a bean, the container will call the appropriate method annotated with @Bean
and return the instance.
The equivalent Java configuration of the XML configuration is given below –
@Configuration
public class AppConfig {
@Bean
public Engine engineBean() {
return new EngineImpl();
}
@Bean
public Vehicle vehicle() {
Vehicle vehicle = new Vehicle();
vehicle.setEngine(engineBean());
return vehicle;
}
}
If we want to assign a different name to the bean rather than the method name, we can do that by passing the desired bean name to the @Bean annotation.
@Bean("engine")
public Engine engineBean() {
return new EngineImpl();
}
We can also mix XML configuration with Java configuration. For example, let’s assume you have kept the Vehicle and Engine bean definition in an XML file and you want to import that configuration in your configuration class. To achieve this, you can use @ImportResource
annotation.
@Configuration
@ImportResource(locations = "classpath:Spring-config.xml")
public class AppConfig {
}
Annotation-Based configuration
In case of annotation-based configuration, we annotate bean classes with the appropriate stereotype annotation like @Component
, @Service
etc. and use @Autowired
annotation on fields, setters and constructors to configure the dependency.
Also, we have to request Spring to scan our application to find the annotated classes. To do that, in our configuration class we can use @ComponentScan
annotation and specify the package name. Spring will scan for the annotated classes under the specified package and all of its sub-packages. If we use @ComponentScan
without specifying the package name, Spring will scan the current package in which the configuration class is preset and all of its sub-packages.
So, the annotation based configuration will look like below –
@Component
public class EngineImpl implements Engine {
public void start() {
System.out.println("Starting engine...");
}
}
@Service
public class Vehicle {
@Autowired
private Engine engine;
public void start() {
engine.start();
}
}
@ComponentScan(basePackages = {"com.kcs"})
@Configuration
public class AppConfig {
}
In case of annotation-based configuration, if we don’t specify any name, class names will be used as the name. Only the first letter will be downcasted. So the name of Vehicle bean would be vehicle. We are also allowed to explicitly specify the bean name as shown below.
@Service(“twoWheeler”)
public class Vehicle {
......
}
Instantiating a container
As our bean configuration is done, let’s instantiate a container. Spring Framework provides two types of Containers –
- Bean Factory
- Application Context
Bean Factory : The BeanFactory is the actual container that instantiates, injects dependencies and manages a number of beans. BeanFactory only supports XML based configuration. The most commonly used implementation of BeanFactory is the XmlBeanFactory
class.
Application Context : This interface is built on top of the BeanFactory interface to provide additional functionality like internationalization, event publication, AOP service etc. Always try to use ApplicationContext. The commonly used implementations of this interface are: AnnotationConfigApplicationContex, AnnotationConfigWebApplicationContext
etc.
To instantiate Spring IoC container using XmlBeanFactory you can do as following –
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("Spring-config.xml"));
Vehicle vehicle = beanFactory.getBean(Vehicle.class);
To instantiate Spring IoC container using AnnotationConfigApplicationContex you can do as following –
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Vehicle vehicle = ctx.getBean(Vehicle.class);
Differences between BeanFactory and ApplicationContext
Feature | BeanFactory | ApplicationContext |
---|---|---|
Implementation | XMLBeanFactory | AnnotationConfigWebApplicationContext, AnnotationConfigApplicationContext etc. |
Annotation Support | No | Yes |
Instantiation | BenaFactory instantiates beans when the getBean() method gets called. | ApplicationContext instainte bean at the time container starts. |
Event Publication | Bean factory does not have the ability to push events to the beans. | Application Context has the ability to push to push events to the beans. |
Internationalization | No | Yes |
That’s it for now. Hope you have enjoyed this tutorial. If you have any doubt, please ask in the comment section. I will try to answer that as soon as possible. Till then, bye bye.
Itís nearly impossible to find experienced people on this subject, but you sound like you know what youíre talking about! Thanks