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
@Configurationannotation will be used in configuring theApplicationContextin Spring - A
DataSourcewith the Spring@Beanis created - A
UserDaoSpring@Beanis created, calling thedataSource()method on theDataSource @Bean
ApplicationContext
Spring uses the ApplicationContext to determine what @Beans 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
ApplicationContextby passing inMyApplicationContextConfigurationclass, which will create aUserDaoand aDataSource - Get the fully configured
UserDao, including its dependency on aDataSourcefor JDBC connection - We can also get the exact same instance of the
DataSourceused inUserDaofrom theApplicationContext
Using @ComponentScan to inject @Components
We don't need to tell Spring to look at our Application Context Configuration to figure out what @Beans exist in our application. Instead, we can tell Spring where it can look for other @Components 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
UserDaois a dependency it should manage and inject where needed - How does Spring know what to provide to the
UserDaofor 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)