Spring Boot is a framework that simplifies the development of Java applications by providing a convention-over-configuration approach and reducing boilerplate code. It is particularly useful for creating microservices and RESTful web services. In this introduction, we will cover some important annotations and concepts in Spring Boot, while also drawing comparisons to Angular.

Example Application

Here is a simple example of a Spring Boot application that implements a REST controller.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@RestController
class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }
}

1. How Does the Spring Container Work?

The Spring Container manages the lifecycle of beans, which are created through Dependency Injection (DI). It is responsible for instantiating, configuring, and managing objects called beans. The container uses configuration metadata to determine how beans are created and wired together.

2. What is ApplicationContext in Relation to the Spring Container?

ApplicationContext is an extension of the Spring Container that provides additional features such as event propagation, message source management, and support for internationalization. It serves as the central interface for the Spring IoC Container, allowing for the management of beans and their dependencies.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

@Component
class MyCommandLineRunner implements CommandLineRunner {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void run(String... args) throws Exception {
        // Fetching a bean from the application context
        MyService myService = applicationContext.getBean(MyService.class);
        myService.performAction();
    }
}

@Component
class MyService {
    public void performAction() {
        System.out.println("Service action performed!");
    }
}

Here’s a code example demonstrating how to use the ApplicationContext in a Spring Boot application:

Example Code
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

@Component
class MyCommandLineRunner implements CommandLineRunner {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void run(String... args) throws Exception {
        // Fetching a bean from the application context
        MyService myService = applicationContext.getBean(MyService.class);
        myService.performAction();
    }
}

@Component
class MyService {
    public void performAction() {
        System.out.println("Service action performed!");
    }
}
Explanation of the Code
  1. @SpringBootApplication: This annotation marks the main class of the Spring Boot application, enabling auto-configuration and component scanning.
  2. MyApplication: This is the main class that starts the Spring Boot application using SpringApplication.run().
  3. @Component: The MyCommandLineRunner class is annotated with @Component, making it a Spring-managed bean. It will be automatically detected and registered in the application context.
  4. CommandLineRunner: This interface allows you to run specific code after the Spring application context is loaded. The run method is overridden to define what should happen at startup.
  5. @Autowired: This annotation is used to inject the ApplicationContext into the MyCommandLineRunner bean. Spring will automatically provide the application context when this bean is created.
  6. ApplicationContext: This is the central interface to the Spring IoC (Inversion of Control) container. It holds references to all the beans in the application. In this example, it is used to retrieve a specific bean (MyService).
  7. getBean(MyService.class): This method is called on the ApplicationContext to fetch an instance of MyService. The class type is provided as an argument.
  8. MyService: This is another Spring-managed bean that contains a method performAction(). When called, it prints a message to the console.

When we run this application, the MyCommandLineRunner will execute at startup, fetching the MyService bean from the application context and calling its performAction() method. This demonstrates how to use the ApplicationContext to manage and access beans in a Spring Boot application.

3. What is BeanPostProcessor in Spring Boot? Is There a Similar Mechanism in Angular?

BeanPostProcessor is an interface that allows for custom logic to be applied before and after the initialization of a bean. In Angular, there isn’t a direct equivalent, but similar concepts can be achieved through lifecycle hooks like ngOnInit.

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public BeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

class MyService {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

@Component
class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            ((MyService) bean).setName("Initialized Service");
            System.out.println("Before Initialization: Setting name for MyService");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof MyService) {
            System.out.println("After Initialization: MyService is ready to use");
        }
        return bean;
    }
}

@Component
class MyCommandLineRunner implements CommandLineRunner {

    private final MyService myService;

    public MyCommandLineRunner(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Running MyService with name: " + myService.getName());
    }
}
Explanation of the Code
  1. @SpringBootApplication: This annotation marks the main class of the Spring Boot application, enabling auto-configuration and component scanning.
  2. MyApplication: The main class that starts the Spring Boot application using SpringApplication.run().
  3. @Bean: The myService method defines a bean of type MyService. This bean will be managed by the Spring container.
  4. MyService: A simple service class with a property name and corresponding getter and setter methods.
  5. MyBeanPostProcessor: This class implements the BeanPostProcessor interface, which allows you to modify beans before and after their initialization.
    • postProcessBeforeInitialization: This method is called before a bean’s initialization callback (like @PostConstruct). In this example, it checks if the bean is an instance of MyService and sets its name to “Initialized Service”. It also prints a message indicating that the name is being set.
    • postProcessAfterInitialization: This method is called after the bean’s initialization. It checks if the bean is an instance of MyService and prints a message indicating that the service is ready to use.
  6. MyCommandLineRunner: This component implements CommandLineRunner, allowing it to run specific code after the Spring application context is loaded.
    • It receives the MyService bean through constructor injection and prints its name when the application starts.

When you run this application, the MyBeanPostProcessor will modify the MyService bean during its lifecycle. The output will show the messages from both the postProcessBeforeInitialization and postProcessAfterInitialization methods, confirming that the name was set before initialization and that the service is ready to use afterward. This demonstrates how BeanPostProcessor can be used to customize bean initialization in a Spring Boot application.

4. Field Injection

Field Injection is a method of Dependency Injection where dependencies are directly injected into the fields of a class, typically using the @Autowired annotation.

@Component
public class MyService {
    @Autowired
    private MyRepository myRepository;
}

5. Scope (singleton, prototype, session, request)

  • Singleton: A single instance per Spring Container (default).
  • Prototype: A new instance for each request.
  • Session: An instance per HTTP session.
  • Request: An instance per HTTP request.

6. CommandLineRunner

CommandLineRunner is an interface that provides a method to be executed on application startup.

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

@Component
class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner is executed on application startup");
        // Hier können Sie Initialisierungslogik hinzufügen
    }
}
Explanation of the CommandLineRunner Code
  • CommandLineRunner: This interface provides a single method, run, which is called after the application context is loaded and right before the application starts. You can use this method to execute logic that needs to run at startup, such as initializing data or performing setup tasks.
  • @SpringBootApplication: This annotation marks the main class of a Spring Boot application. It combines several annotations, including @Configuration, @EnableAutoConfiguration, and @ComponentScan, which collectively set up the Spring application context.
  • @Component: This annotation indicates that the MyCommandLineRunner class is a Spring-managed bean. By marking it as a component, Spring will automatically detect and register it during the component scanning process.
  • run(String... args): This method takes a variable number of string arguments (typically command-line arguments) and contains the logic that will be executed when the application starts. In this example, it simply prints a message to the console.

When you run the application, the run method of MyCommandLineRunner is invoked, and you’ll see the message “CommandLineRunner is executed on application startup” printed in the console. This allows you to perform any necessary initialization or setup tasks right when your application starts.

7. HTTP Session in Java

An HTTP session stores data across multiple HTTP requests for a specific user. In Java, this is commonly handled using HttpSession

8. @ComponentScan

@ComponentScan instructs the Spring Container to look for beans in specified packages. It is often included in @SpringBootApplication.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.example.package")
public class AppConfig {
}

9. @SpringBootApplication

This annotation combines several others, including @Configuration, @EnableAutoConfiguration, and @ComponentScan. It serves as the entry point for a Spring Boot application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

10. @PostConstruct

The @PostConstruct annotation is used to mark a method that should be called after the bean’s construction. This is similar to ngOnInit in Angular, where initializations are performed after the component is created.

Example:
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;

@Component
public class MyBean {
    
    @PostConstruct
    public void init() {
        System.out.println("Bean is initialized");
    }
}

11. @Qualifier

The @Qualifier annotation is used to specify which bean to inject when multiple beans of the same type exist. This is useful for avoiding conflicts.

Example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    
    @Autowired
    @Qualifier("myRepository")
    private MyRepository myRepository;
}

12. @Configuration

The @Configuration annotation marks a class that contains bean definitions. These classes are processed by Spring when the application starts.

Example:
@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

The @Configuration annotation is commonly used to indicate that a class declares one or more @Bean methods. However, there are other annotations that can also be used for similar purposes:

  • You can use @Component to mark a class as a Spring-managed bean. While it doesn’t explicitly declare beans like @Configuration, if the class contains @Bean methods, Spring will treat it as a configuration class.
  • @ComponentScan: This annotation is used in conjunction with @Configuration or @SpringBootApplication to specify the packages to scan for Spring components, including configuration classes.
  • @EnableAutoConfiguration : Used in Spring Boot applications, this annotation automatically configures your application based on the dependencies present on the classpath. It can eliminate the need for many explicit @Configuration classes.
  • @Import:You can use this annotation to import other configuration classes into a configuration class. This allows you to modularize your configuration.
@Configuration
@Import(OtherConfig.class)
public class MyConfig {
    // Bean definitions
}

13. @TestConfiguration

The @TestConfiguration annotation is used to define test-specific beans. These beans are only available in the test context.

Example:
@TestConfiguration
public class TestConfig {
    @Bean
    public MyService myService() {
        return Mockito.mock(MyService.class);
    }
}

14. @Bean

The @Bean annotation is used to mark a method as a bean that should be managed by Spring.

Example:
@Bean
public MyRepository myRepository() {
    return new MyRepository();
}

15. @Profile

The @Profile annotation is used to activate beans only in specific profiles. This is useful for defining different configurations for development, testing, and production environments.

Example:
@Profile("dev")
@Bean
public MyService devService() {
    return new DevService();
}

@Profile("production")
@Bean
public MyService prodService() {
    return new ProdService();
}

16. @ActiveProfiles

The @ActiveProfiles annotation is used to specify active profiles for tests. This helps control the configuration during testing.

Example:
@ActiveProfiles("test")
@SpringBootTest
public class MyServiceTest {
    // Test methods
}

17. @Primary

The @Primary annotation is used to designate a bean as the primary bean when multiple beans of the same type exist. This indicates which bean should be used by default.

Example:
@Bean
@Primary
public MyService primaryService() {
    return new PrimaryService();
}

18. @SpringBootTest

The @SpringBootTest annotation is used for integration testing in a Spring Boot application. It loads the entire application context.

Example:
@SpringBootTest
public class ApplicationTests {
    @Test
    public void contextLoads() {
    }
}

19. Mockito

Mockito is a popular framework for creating mock objects in tests. It allows you to test components in isolation.

Example:
import static org.mockito.Mockito.*;

public class MyServiceTest {
    @Test
    public void testMyService() {
        LogService mockLogService = Mockito.mock(LogService.class);
        MyService myService = new MyService(mockLogService);

        // Test logic
    }
}

20. @ExtendWith

@ExtendWith is used in tests to register extensions that provide additional functionalities, such as Mockito or JUnit5-specific extensions.

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
    
    @Test
    public void testWithMockito() {
        // Test code using Mockito
    }
}

Conclusion

In this introduction, we covered the basics of Java Spring Boot and explained some important annotations and concepts. These concepts are essential for developing robust and maintainable applications in Spring Boot and offer many advantages that make development more efficient.

By Shabazz

Software Engineer, MCSD, Web developer & Angular specialist

Leave a Reply

Your email address will not be published. Required fields are marked *