Skills101

Advanced Java & Spring Boot · Lesson 4 of 16 · Updated ·

Spring Boot Basics — Auto-configuration, Starters, application.properties and Profiles

Plain Spring needs a lot of setup: configure a web server, a database connection pool, JSON conversion, transactions… Spring Boot does all of that for you with sensible defaults, so you write only your own code.

1. What Spring Boot gives you

  • Starters — one dependency brings a whole feature with compatible versions (lesson 1).
  • Auto-configuration — Boot looks at your classpath and properties and creates the beans you'd otherwise write by hand. H2 on the classpath? A DataSource is configured. spring-boot-starter-webmvc? Tomcat and JSON are set up.
  • Embedded server — your app contains Tomcat; you run it with java -jar, no separate server install.
  • Production features — health checks, metrics and externalised configuration.

You can always override a default by defining your own bean or setting a property.

Layers of a Spring Boot REST API: client, @RestController, @Service, repository, database, with JSON DTOs at the top and SQL entities at the bottom

We'll build the Course API in these layers: controllers handle HTTP, services hold business rules, repositories talk to the database.

2. application.properties

All settings live in src/main/resources/application.properties. Here is our Course API's file:

# File: course-api/src/main/resources/application.properties
spring.application.name=course-api
server.port=8081
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

# H2 in-memory database (swap for MySQL/PostgreSQL in production)
spring.datasource.url=jdbc:h2:mem:courses
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.open-in-view=false

# JWT signing secret (base64, at least 32 bytes). In production read it from an environment variable.
app.jwt.secret=c2tpbGxzMTAxLWRlbW8tc2VjcmV0LWtleS0zMi1ieXRlcy1sb25nIQ==
app.jwt.ttl-minutes=60

management.endpoints.web.exposure.include=health,info
PropertyMeaning
server.portHTTP port (default 8080)
spring.datasource.urlwhich database to connect to
spring.jpa.hibernate.ddl-autocreate tables from entities (create-drop for learning; validate or none with real migrations in production)
spring.jpa.open-in-view=falseclose the database session when the service layer finishes (avoids hidden slow queries)
app.jwt.*our own settings, read with @Value("${app.jwt.ttl-minutes}")
management.endpoints…which Actuator endpoints are exposed

You can also use application.yml (same keys, YAML format) — pick one.

Never commit real secrets. Any property can be overridden by an environment variable: APP_JWT_SECRET=… overrides app.jwt.secret (dots become underscores, upper-case).

3. Profiles

Different settings per environment: create application-dev.properties and application-prod.properties, then start with --spring.profiles.active=prod (or SPRING_PROFILES_ACTIVE=prod). Profile files override the main file. A bean can be limited to a profile with @Profile("dev").

4. Running code at startup

CommandLineRunner beans run once the app has started — handy for sample data:

// File: course-api/src/main/java/com/skills101/courses/DataSeeder.java
package com.skills101.courses;

import com.skills101.courses.course.Course;
import com.skills101.courses.course.CourseRepository;
import com.skills101.courses.student.Student;
import com.skills101.courses.student.StudentRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

// Puts sample data in the in-memory database when the app starts
@Component
public class DataSeeder implements CommandLineRunner {

    private final CourseRepository courses;
    private final StudentRepository students;

    public DataSeeder(CourseRepository courses, StudentRepository students) {
        this.courses = courses;
        this.students = students;
    }

    @Override
    public void run(String... args) {
        if (courses.count() > 0) {
            return;
        }
        courses.save(new Course("Java Full Stack", 4999, 30));
        courses.save(new Course("DSA in Python", 2999, 1));
        students.save(new Student("Asha Verma", "asha@skills101.in"));
        students.save(new Student("Ravi Kumar", "ravi@skills101.in"));
    }
}

(For real databases use a migration tool such as Flyway or Liquibase instead — versioned SQL scripts that run once.)

5. Actuator: is the app healthy?

With spring-boot-starter-actuator, GET /actuator/health returns the app's status — load balancers and Kubernetes call it to decide whether to send traffic. When we ran the built jar:

$ curl http://localhost:8081/actuator/health
{"groups":["liveness","readiness"],"status":"UP"}

Expose only what you need (health, info); endpoints like env or heapdump can leak secrets.

Common mistakes

  • Two apps on the same port → "Port 8081 was already in use". Change server.port or stop the other app.
  • ddl-auto=create-drop on a real database — it deletes your tables on shutdown.
  • Hard-coding passwords and API keys in application.properties that gets committed to Git.

Quick recap

  • Spring Boot = Spring + starters + auto-configuration + embedded server.
  • Configure with application.properties (or .yml); override with environment variables and profiles.
  • CommandLineRunner runs code at startup; use Flyway/Liquibase for real schema changes.
  • Actuator's /actuator/health reports whether the app is up.

Practice what you learned

📝 Quiz: Spring Boot Basics5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →