Skip to content
Home
Spring Boot Guide: Java Enterprise Web Development

Spring Boot Guide: Java Enterprise Web Development

Backend Web Frameworks Backend Web Frameworks 7 min read 1470 words Beginner ExcellentWiki Editorial Team

Spring Boot is the standard framework for building Java web applications. It simplifies Spring configuration with auto-configuration, embedded servers, and production-ready features. Spring Boot eliminates the boilerplate XML configuration that made traditional Spring difficult to set up.

This guide covers auto-configuration, Spring MVC, Spring Data JPA, security, and production deployment.

Auto-Configuration

Spring Boot’s auto-configuration is its most powerful feature. It uses @Conditional annotations to decide which beans to configure based on classpath contents, property values, and existing bean definitions. When spring-boot-starter-web is on the classpath, Spring Boot automatically configures DispatcherServlet, Jackson, and an embedded Tomcat server:

@SpringBootApplication  // Includes @EnableAutoConfiguration
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
---

Custom Auto-Configuration

Create custom auto-configuration for reusable infrastructure components:

@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MyCustomAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "my.feature.enabled", havingValue = "true")
    public MyService myService() {
        return new MyServiceImpl();
    }
---

The spring.factories file (or org.springframework.boot.autoconfigure.AutoConfiguration.imports) registers auto-configuration classes so Spring Boot discovers them.

Spring MVC

Spring MVC provides the controller layer for handling HTTP requests:

@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductService service;

    public ProductController(ProductService service) {
        this.service = service;
    }

    @GetMapping
    public List<Product> getAll() {
        return service.findAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<Product> getById(@PathVariable Long id) {
        return service.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Product create(@Valid @RequestBody Product product) {
        return service.save(product);
    }
---

Exception Handling

Use @ControllerAdvice for centralized exception handling:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(e -> e.getField() + ": " + e.getDefaultMessage())
            .toList();
        return ResponseEntity.badRequest()
            .body(new ErrorResponse("VALIDATION_FAILED", errors));
    }
---

Spring Data JPA

Spring Data JPA eliminates the need for boilerplate data access code:

@Entity
public class Product {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private BigDecimal price;

    @ManyToOne(fetch = FetchType.LAZY)
    private Category category;
---

public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findByCategoryId(Long categoryId);
    List<Product> findByNameContainingIgnoreCase(String name);
    Page<Product> findByPriceBetween(BigDecimal min, BigDecimal max, Pageable pageable);
---

Spring Data derives queries from method names — findByCategoryId generates SELECT * FROM product WHERE category_id = ?. Use @Query for custom queries and @Modifying for update/delete operations.

Security with Spring Security

Spring Security provides comprehensive authentication and authorization:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
            .sessionManagement(session -> 
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        return http.build();
    }
---

Actuator and Production Features

Spring Boot Actuator provides production endpoints for health checks, metrics, and monitoring:

# application.properties
management.endpoints.web.exposure.include=health,metrics,info,prometheus
management.endpoint.health.show-details=when-authorized

Prometheus metrics are available via the micrometer-registry-prometheus dependency. Health indicators report database connectivity, disk space, and custom checks.

Database Migrations

Spring Boot integrates Flyway and Liquibase automatically. Add the dependency and place migration scripts in db/migration/. The DataSource is auto-configured from application.properties with HikariCP as the default connection pool:

spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=myuser
spring.datasource.password=mypassword
spring.jpa.hibernate.ddl-auto=validate

Summary

Spring Boot simplifies Java web development with auto-configuration, embedded servers, and production-ready features. Use Spring MVC for REST APIs, Spring Data JPA for database access, Spring Security for authentication, and Actuator for monitoring.

FAQ

What is the difference between Spring and Spring Boot? Spring is the core framework with DI, AOP, and MVC. Spring Boot adds auto-configuration, embedded servers, starter dependencies, and production features. Spring Boot is the recommended way to build new Spring applications.

How do I handle database migrations in Spring Boot? Use Flyway or Liquibase — Spring Boot auto-configures them when the dependency is on the classpath. Place migration scripts in db/migration/ and Spring Boot runs them automatically on startup.

What is the best way to configure properties? Use application.yml or application.properties. Profile-specific files (application-dev.yml, application-prod.yml) override defaults. Use @ConfigurationProperties for typed property binding.

How do I secure a Spring Boot REST API? Use Spring Security with JWT authentication. Stateless sessions, CORS configuration, and method-level security with @PreAuthorize provide comprehensive protection.

Dependency Injection in Spring

Spring’s dependency injection is at the core of the framework. Understanding the available injection methods and their use cases is essential:

Field Injection (Not Recommended)

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
---

Field injection is concise but has significant drawbacks: it makes testing harder (cannot inject mocks without reflection), hides dependencies from the constructor signature, and prevents immutable fields (cannot use final).

Constructor Injection (Recommended)

@Service
public class UserService {
    private final UserRepository userRepository;
    private final EmailService emailService;

    public UserService(UserRepository userRepository, EmailService emailService) {
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
---

Constructor injection enables immutable fields, makes dependencies explicit, simplifies testing (construct with mocks), and works with Spring’s auto-detection. Spring Boot 2.x+ recommends constructor injection as the primary approach.

Setter Injection

@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
---

Use setter injection only when the dependency is optional or when circular dependencies cannot be resolved through constructor injection (though circular dependencies should be eliminated through better design).

Bean Scopes and Lifecycle

Spring beans have configurable scopes that determine their lifecycle:

  • Singleton (default) — One instance per Spring container. Stateless services. Thread-safe.
  • Prototype — New instance each time it is requested. Stateful beans. Not managed beyond creation.
  • Request — Instance per HTTP request. Web application context only.
  • Session — Instance per HTTP session. Web application context only.
  • Application — Instance per ServletContext. Web application context only.

Use @PostConstruct and @PreDestroy for lifecycle callbacks. For async initialization, implement InitializingBean or use @EventListener(ApplicationReadyEvent.class).

Spring Boot Auto-Configuration

Spring Boot’s auto-configuration automatically configures beans based on classpath dependencies, property settings, and existing beans. Enable debugging with --debug to see auto-configuration decisions. Exclude specific auto-configurations with @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) when you need manual control.

Spring Data JPA

Spring Data JPA eliminates boilerplate data access code. Define an interface and Spring generates the implementation:

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
    List<User> findByActiveTrue();
    @Query("SELECT u FROM User u WHERE u.lastLogin < :date")
    List<User> findInactiveUsersSince(@Param("date") LocalDateTime date);
---

Method names following Spring Data’s convention (findBy, countBy, deleteBy, existsBy) are automatically parsed and implemented. Complex queries use @Query with JPQL or native SQL. For dynamic queries, use Specification or QueryDSL.

Spring Security

Spring Security provides comprehensive authentication and authorization. The modern approach uses SecurityFilterChain:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(authz -> authz
            .requestMatchers("/api/public/**").permitAll()
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        )
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
        .sessionManagement(session -> session.sessionCreationPolicy(STATELESS));
    return http.build();
---

For JWT authentication, Spring Security validates the token signature, extracts claims, and populates the SecurityContext. Method-level security with @PreAuthorize provides fine-grained access control on individual endpoints or service methods.

Spring Boot Testing

Spring Boot provides comprehensive testing support at multiple levels:

Unit tests test individual classes in isolation using JUnit 5 and Mockito:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository userRepository;
    @InjectMocks
    private UserService userService;

    @Test
    void shouldFindUserByEmail() {
        when(userRepository.findByEmail("test@test.com"))
            .thenReturn(Optional.of(new User("test@test.com")));
        var result = userService.findByEmail("test@test.com");
        assertTrue(result.isPresent());
    }
---

Integration tests test the application context with a running server:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void shouldReturnUser() {
        var response = restTemplate.getForEntity("/api/users/1", User.class);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }
---

Slice tests load only specific layers: @WebMvcTest for controllers, @DataJpaTest for repositories, @JsonTest for serialization. Slice tests are faster than full context tests and focus testing on specific concerns.

Spring Boot Actuator

Actuator provides production-ready endpoints for monitoring and management:

  • /actuator/health — Application health (database, disk space, external services)
  • /actuator/metrics — JVM metrics, request metrics, custom metrics
  • /actuator/info — Custom application information
  • /actuator/env — Environment properties (protect in production)
  • /actuator/loggers — View and change log levels at runtime

Enable only the endpoints you need in production. Use Spring Security to protect sensitive endpoints.

Reactive Programming with Spring WebFlux

Spring WebFlux provides reactive (non-blocking) programming support for high-concurrency applications:

@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping
    public Flux<User> getAllUsers() {
        return userRepository.findAll();  // Reactive repository
    }

    @GetMapping("/{id}")
    public Mono<User> getUser(@PathVariable String id) {
        return userRepository.findById(id);
    }
---

WebFlux uses Project Reactor’s Mono (0-1 item) and Flux (0-N items) types. Reactive streams allow a single thread to handle many concurrent requests, significantly reducing resource usage under high concurrency. WebFlux pairs well with:

  • Reactive MongoDBspring-boot-starter-data-mongodb-reactive
  • Reactive Cassandraspring-boot-starter-data-cassandra-reactive
  • Reactive Kafkaspring-kafka with reactive consumer
  • R2DBC — Reactive relational database connectivity

Spring Cloud Ecosystem

Spring Cloud extends Boot for distributed systems:

  • Spring Cloud Config — External configuration management
  • Spring Cloud GatewayAPI gateway built on WebFlux
  • Spring Cloud Netflix — Service discovery (Eureka), circuit breaker (Hystrix)
  • Spring Cloud Sleuth — Distributed tracing with OpenTelemetry
  • Spring Cloud Stream — Event-driven microservices with message brokers

Batch Processing with Spring Batch

Spring Batch provides robust batch processing capabilities:

  • Chunk-oriented processing (read, process, write)
  • Job restart and skip capabilities
  • Transaction management
  • Parallel processing with partitioning
  • Item readers/writers for databases, files, and messaging systems

Use Spring Batch for ETL jobs, data migration, report generation, and any large-scale data processing tasks.


Related: ASP.NET Core Guide | REST API Frameworks

Section: Backend Web Frameworks 1470 words 7 min read Beginner 756 articles in section Report inaccuracy Back to top