Configuring and Integrating Spring, Spring MVC, and MyBatis for Java Web Applications
Integrating Spring, Spring MVC, and MyBatis requires a layered configuration approach where the root application context manages bussiness logic and persistence, while the child web context handles HTTP routing and controller execution. This annotation-driven architecture eliminates legacy XML descriptors and centralizes dependency management.
Root Application Context Setup
The foundational configuration class orchestrates component discovery, external property resolution, and module imports. It serves as the parent container for service and repository layers.
package com.example.app.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan(basePackages = {"com.example.app.service"})
@PropertySource(value = "classpath:db-connection.properties", ignoreResourceNotFound = true)
@Import({DataSourceConfiguration.class, PersistenceConfiguration.class})
@EnableTransactionManagement
public class AppContextConfiguration {
// Parent container responsible for business beans and transaction management
}
Web Layer Configuration
The presentation context operates independently, focusing strictly on request mapping, view resolution, and HTTP serialization.
package com.example.app.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.example.app.controller"})
public class WebMvcConfiguration {
// Child container dedicated to Spring MVC components
}
Servlet Container Initialization
Replacing traditional web.xml deployments, an initializer binds the root and web contexts to the servlet engine. It also registers request-level filters for character encoding normalization.
package com.example.app.config;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{AppContextConfiguration.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMvcConfiguration.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter utfFilter = new CharacterEncodingFilter();
utfFilter.setEncoding("UTF-8");
utfFilter.setForceEncoding(true);
return new Filter[]{utfFilter};
}
}
Data Source and Persistence Configuration
Externalized connection parameters are injected into a pooled datasource. MyBatis is subsequently wired to consume this pool and auto-discover repository interfaces.
db-connection.properties
db.jdbc.driver=com.mysql.cj.jdbc.Driver
db.jdbc.url=jdbc:mysql://127.0.0.1:3306/project_db?useSSL=false&serverTimezone=UTC
db.jdbc.username=admin_user
db.jdbc.password=secure_credentials
DataSourceConfiguration.java
package com.example.app.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
public class DataSourceConfiguration {
@Value("${db.jdbc.driver}")
private String jdbcDriver;
@Value("${db.jdbc.url}")
private String connectionEndpoint;
@Value("${db.jdbc.username}")
private String credentialUser;
@Value("${db.jdbc.password}")
private String credentialPass;
@Bean
public DataSource initializePool() {
DruidDataSource connectionPool = new DruidDataSource();
connectionPool.setDriverClassName(jdbcDriver);
connectionPool.setUrl(connectionEndpoint);
connectionPool.setUsername(credentialUser);
connectionPool.setPassword(credentialPass);
return connectionPool;
}
@Bean
public PlatformTransactionManager configureTransactions(DataSource targetSource) {
return new DataSourceTransactionManager(targetSource);
}
}
PersistenceConfiguration.java
package com.example.app.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class PersistenceConfiguration {
@Bean
public SqlSessionFactoryBean buildSessionFactory(DataSource connectionSource) {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(connectionSource);
factory.setTypeAliasesPackage("com.example.app.model");
return factory;
}
@Bean
public MapperScannerConfigurer scanRepositoryInterfaces() {
MapperScannerConfigurer interfaceScanner = new MapperScannerConfigurer();
interfaceScanner.setBasePackage("com.example.app.repository");
return interfaceScanner;
}
}
Dependency Management
The following Maven coordinates establish the required runtime enviroment, handling framework integration, database drivers, and serialization utilities.
<dependencies>
<!-- Core Framework Modules -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.25</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.25</version>
</dependency>
<!-- ORM & Integration Layer -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.14</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.1.1</version>
</dependency>
<!-- Connectivity & Pooling -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.18</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
<!-- Web & Serialization -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Request Processing Flow
During container startup, WebInitializer registers the DispatcherServlet and attaches it to the root path. The servlet loads WebMvcConfiguration, triggering component scans for @Controller classes and mapping HTTP endpoints. Simultaneously, the parent context instantiates service beans, transaction managers, and the MyBatis SqlSessionFactory. When an HTTP request arrives, it traverses the UTF-8 encoding filter, enters the DispatcherServlet, matches a handler mapping, and routes to the corresponding controller method. The controller delegates to service-layer components, which invoke auto-registered MyBatis mapper interfaces to execute parameterized SQL. Operations marked with @Transactional are intercepted by the DataSourceTransactionManager, ensuring atomic execution against the Druid connection pool before the serialized payload is returned to the client.