The Spring Framework empowers developers to create Java applications and deliver on business focus quickly. The primary benefit of Spring is its inversion-of-control container approach to dependency injection, removing the need for hard-coded wiring as the framework can inject dependencies where they are needed.
Benefits
• Testability
• Maintainability
• Scalability
Testability
Because Spring decouples object contracts from their implementations and autowires them using Spring's Application Context, we can create units of work that are much easier to write tests for.
Maintainability
By using Spring's opinionated architecture, developers can quickly identify and familiarize themselves with an application's business focus. Most frameworks are popular because they operate on some fundamentals that are easy to grasp, which is one of Spring's strengths.
Scalability
Spring containers utilizing Spring Boot are able to deploy as standalone JARs and run on an included Tomcat server. Between Spring's @Profile
annotations and the Spring Application Context Configuration, there is a lot of flexibility to control the behavior of a Spring application in varying environments.
IoC/Dependency Injection in Spring
Understanding dependency injection is a fundamental component of understanding the Spring Framework. Spring Boot is the most popular project developers get started with and is an excellent sandbox for development ideas around dependency injection. Let's take a look, getting started with how we can store configurations in a Java class and tell Spring how to use it with the @Configuration
annotation.
ApplicationContextConfiguration
Using the @Configuration
annotation enables Java configuration of specific dependencies. In the example below, we will tell Spring what implements theUserDao
and what DataSource
to build. We are assuming the UserDao
uses constructor injection to determine its database connection dependency.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyApplicationContextConfiguration { // (1)
@Bean
public DataSource dataSource() { // (2)
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUser("root");
dataSource.setPassword("s3cr3t");
dataSource.setURL("jdbc:mysql://localhost:3306/myDatabase");
return dataSource;
}
@Bean
public UserDao userDao() { // (3)
return new UserDao(dataSource());
}
}
- The class name used with a
@Configuration
annotation will be used in configuring theApplicationContext
in Spring - A
DataSource
with the Spring@Bean
is created - A
UserDao
Spring@Bean
is created, calling thedataSource()
method on theDataSource @Bean
ApplicationContext
Spring uses the ApplicationContext
to determine what @Bean
s to instantiate and inject into dependencies.
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
public class MyApplication {
public static void main(String[] args) {
// (1)
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyApplicationContextConfiguration.class);
UserDao userDao = ctx.getBean(UserDao.class); // (2)
User user1 = userDao.findById(1);
User user2 = userDao.findById(2);
DataSource dataSource = ctx.getBean(DataSource.class); // (3)
// etc ...
}
}
- Construct an
ApplicationContext
by passing inMyApplicationContextConfiguration
class, which will create aUserDao
and aDataSource
- Get the fully configured
UserDao
, including its dependency on aDataSource
for JDBC connection - We can also get the exact same instance of the
DataSource
used inUserDao
from theApplicationContext
Using @ComponentScan to inject @Components
We don't need to tell Spring to look at our Application Context Configuration to figure out what @Bean
s exist in our application. Instead, we can tell Spring where it can look for other @Component
s in our application using the @ComponentScan
annotation on our main Application
class.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan // (1)
public class MyApplicationContextConfiguration {
@Bean
public DataSource dataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUser("root");
dataSource.setPassword("s3cr3t");
dataSource.setURL("jdbc:mysql://localhost:3306/myDatabase");
return dataSource;
}
// (2)
// no more UserDao @Bean method!
}
- Without any arguments, Spring will look for @Components in all Java classes in the same package
- Why don't we need the UserDao @Bean in the Application Context Configuration anymore?
import javax.sql.DataSource;
import org.springframework.stereotype.Component;
@Component // (1)
public class UserDao {
private DataSource dataSource;
private UserDao(DataSource dataSource) { // (2)
this.dataSource = dataSource;
}
}
- Spring now knows the
UserDao
is a dependency it should manage and inject where needed - How does Spring know what to provide to the
UserDao
for its DataSource dependency?
While not required in the latest versions of Spring (4.2 and later), the @Autowired
annotation can be used to explicitly mark the constructor injection method as dependent on the DataSource @Bean
Spring will create.
import javax.sql.DataSource;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
public class UserDao {
private DataSource dataSource;
private UserDao(@Autowired DataSource dataSource) {
this.dataSource = dataSource;
}
}
Injection Methods
• Constructor
• Setter
• Field
Sources
Code examples used in this blog were adapted from Marco Behler's What is Spring Framework?
Top comments (0)