☕ Beginner-friendly • IBM blue/white style • Interactive

How Spring puts your app together.

Think of a Spring app like a school robotics team. Different students build the wheels, camera, battery, and controller. A lightweight container helps assemble all those parts into one working robot.

App Assembly Machine

Spring Container
Controller
handles web requests
Service
does business work
Repository
talks to data
Config
settings outside code

Spring creates these objects, connects them, and gives each part what it needs.

The Big Idea

A Spring application is built from small Java objects. In Spring, many of these objects are called beans. The container is like a helpful coach that knows which objects need each other.

Instead of every object building all its own parts, Spring gives each object the parts it needs. This is called Inversion of Control, and the most common way Spring does it is Dependency Injection.

Lesson 1

Inversion of Control, or IoC

Inversion of Control means your object is not fully in charge of finding or creating everything it needs. The container is in charge of assembling the object graph.

Normal control: my class creates its helpers.
Inverted control: Spring creates helpers and gives them to my class.

// Without IoC: the class builds its own helper
class ReportController {
    private ReportService service = new ReportService();
}

// With IoC: Spring gives the helper to the class
@RestController
class ReportController {
    private final ReportService service;

    ReportController(ReportService service) {
        this.service = service;
    }
}

The second version is easier to test, change, and understand.

Lesson 2

Dependency Injection

A dependency is something a class needs to do its job. Injection means the dependency is handed to the class instead of the class hunting for it.

Best common pattern: constructor injection

The required helper is listed in the constructor. Spring sees it and provides the right bean.

@Service
class WeatherService {
    String forecast() {
        return "Sunny with a chance of learning!";
    }
}

@RestController
class WeatherController {
    private final WeatherService weatherService;

    WeatherController(WeatherService weatherService) {
        this.weatherService = weatherService;
    }

    @GetMapping("/weather")
    String getWeather() {
        return weatherService.forecast();
    }
}

Field injection: easy, but not the best teaching pattern

Field injection hides what the class needs. Constructor injection makes the needs obvious.

@RestController
class WeatherController {
    @Autowired
    private WeatherService weatherService;
}

Teacher note: show it exists, but recommend constructor injection for clean, testable code.

Separating configuration from use

The code uses a setting, but the actual value lives outside the class. That means you can change behavior without rewriting the class.

// application.yml
school:
  name: Blue Ridge Middle School

// Java class using the setting
@Component
class SchoolBanner {
    private final String schoolName;

    SchoolBanner(@Value("${school.name}") String schoolName) {
        this.schoolName = schoolName;
    }

    String message() {
        return "Welcome to " + schoolName;
    }
}

Lesson 3

Dependency Injection vs. Service Locator

Both patterns can connect an object to another object. The difference is who does the finding.

Dependency Injection

The dependency is handed to the class.

class GameController {
    private final ScoreService scoreService;

    GameController(ScoreService scoreService) {
        this.scoreService = scoreService;
    }
}
  • ✅ Easy to see what the class needs
  • ✅ Easier to test
  • ✅ Common Spring style

Service Locator

The class asks a locator to find the dependency.

class GameController {
    void play() {
        ScoreService scoreService =
            ServiceLocator.get(ScoreService.class);
    }
}
  • ⚠️ Hides what the class needs
  • ⚠️ Can make tests harder
  • ⚠️ Often less clear for beginners

Mini Spring Boot Project Map

This is a tiny web app structure. The controller uses the service. The service uses the repository. Configuration stays in application.yml.

Controller
/api/books
Service
business rules
Repository
data access
Config
application.yml
// pom.xml idea
// Use Java 21 and Spring Boot 3.5.13

@RestController
@RequestMapping("/api/books")
class BookController {
    private final BookService bookService;

    BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/favorite")
    String favoriteBook() {
        return bookService.favorite();
    }
}

@Service
class BookService {
    private final BookRepository bookRepository;

    BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    String favorite() {
        return bookRepository.findFavorite();
    }
}

@Repository
class BookRepository {
    String findFavorite() {
        return "The Java Adventure";
    }
}

Lesson 4

Lombok: Less Repeated Java Code

Lombok is a helper library that writes boring Java code for you during compilation. It can create getters, setters, constructors, builders, and loggers so your code is shorter and easier to read.

Before Lombok

public class StudentDto {
    private String name;
    private int grade;

    public StudentDto() {}

    public StudentDto(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getGrade() { return grade; }
    public void setGrade(int grade) { this.grade = grade; }
}

With Lombok

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class StudentDto {
    private String name;
    private int grade;
}
@Data
Creates getters, setters, toString, equals, and hashCode.
@Builder
Lets you create objects step by step using readable code.
@Slf4j
Adds a logger named log to your class.

Lesson 5

Spring Annotations: Labels That Tell Spring What To Do

An annotation is like a sticky note on your code. It tells Spring, Java, or a tool extra information about a class, method, or field.

AnnotationSimple MeaningCommon Place
@SpringBootApplicationStarts the Spring Boot app and turns on auto-configuration.Main class
@RestControllerCreates web API endpoints that return data.Controller class
@GetMappingHandles an HTTP GET request.Controller method
@ServiceMarks business logic code.Service class
@RepositoryMarks data access code.Repository class
@ConfigurationHolds bean and app setup rules.Config class
@BeanCreates an object managed by Spring.Config method
@ValueReads a setting from application.yml or properties.Constructor parameter or field
@SpringBootApplication
public class SchoolApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchoolApplication.class, args);
    }
}

@Configuration
class AppConfig {
    @Bean
    Clock appClock() {
        return Clock.systemUTC();
    }
}

Lesson 6

Spring Security: Locking the Doors

Security decides who can enter the app and what they are allowed to do. Authentication asks, Who are you? Authorization asks, What are you allowed to access?

Simple Security Configuration

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/index.html", "/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .build();
    }
}

Controller With Roles

@RestController
@RequestMapping("/api/grades")
class GradeController {

    @GetMapping("/mine")
    String myGrades() {
        return "Only a logged-in student can see this.";
    }

    @PreAuthorize("hasRole('TEACHER')")
    @PostMapping("/update")
    String updateGrade() {
        return "Only a teacher can update grades.";
    }
}

Important idea: separate security configuration from business code

The controller should focus on school grade actions. The security config should focus on login rules, roles, and access paths. This keeps the app easier to change and safer to review.

Lesson 7

Testing With JUnit and Mockito

A test is like a practice run. It checks whether your code does the right thing before real users depend on it. Mockito creates fake helpers so you can test one class at a time.

Service Test With Mockito

@ExtendWith(MockitoExtension.class)
class BookServiceTest {

    @Mock
    BookRepository bookRepository;

    @InjectMocks
    BookService bookService;

    @Test
    void favoriteReturnsBookFromRepository() {
        when(bookRepository.findFavorite())
            .thenReturn("The Java Adventure");

        String result = bookService.favorite();

        assertEquals("The Java Adventure", result);
        verify(bookRepository).findFavorite();
    }
}

Controller Test With MockMvc

@WebMvcTest(BookController.class)
class BookControllerTest {

    @Autowired
    MockMvc mockMvc;

    @MockBean
    BookService bookService;

    @Test
    void favoriteEndpointReturnsOk() throws Exception {
        when(bookService.favorite()).thenReturn("The Java Adventure");

        mockMvc.perform(get("/api/books/favorite"))
            .andExpect(status().isOk())
            .andExpect(content().string("The Java Adventure"));
    }
}
@Test
marks a test method
@Mock
creates a fake helper
verify()
checks a fake was used

Setup

Maven Dependencies Example

In a real Spring Boot project, these dependencies give you web APIs, validation, security, Lombok, and testing tools.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Check Your Understanding

Quick Quiz

Remember This

  • Container: creates and connects objects.
  • Bean: an object managed by Spring.
  • IoC: control of assembly moves from your class to the container.
  • DI: needed objects are handed in.
  • Config separation: settings live outside the class that uses them.
  • Lombok: reduces repeated Java boilerplate.
  • Security: authentication proves who you are; authorization controls what you can do.
  • Testing: JUnit checks results; Mockito creates fake dependencies.