This project serves as an illustrative example in the Spring Boot framework, demonstrating the distinctions between constructor injection and field injection.
Now include AssertJ, Mapper, API Versioning, Logging via Slf4j and Model documentation and validation as well
- IOC
- In traditional programming, objects are responsible for creating and managing their dependencies. This can lead to tightly coupled code and make it challenging to change or replace dependencies. Inversion of Control addresses this by inverting the control of creating and managing dependencies to an external container or framework. (Create the @component and @Autowired it when we use it instead of using new SomeGoodNamingObject())
- How IOC works in Spring
- Configuration Metadata: In Spring Boot, the configuration metadata is typically provided using annotations such as @Component, @Service, @Repository, and @Controller. These annotations mark the classes as Spring-managed components and indicate their role and purpose within the application.
- Spring will do component scan in all the same package or sub-package as the @SpringBootApplication
- Bean Creation: The container scans the application's classpath and identifies the classes annotated with the appropriate annotations. It then creates instances of these classes, known as beans, and registers them within the container. (Which will scan all class in the package and sub-package)
- Dependency Resolution: When creating beans, the container analyzes the dependencies declared by each bean and resolves them by looking for other beans in the container that can satisfy those dependencies. This process is known as autowiring. Note: In some cases that you did not specify the bean spring will do AutoConfiguration such as ObjectMapper
- Scope? probably will not include it in this example
- Benefit of IOC
- Loose Coupling: IOC promotes loose coupling between components by allowing dependencies to be resolved dynamically. This makes it easier to replace or modify dependencies without affecting other parts of the application.
- Testability: By delegating the responsibility of object creation to the container, it becomes easier to write unit tests for individual components. Dependencies can be mocked or stubbed during testing, enabling isolated testing of specific components.
- Modular and Maintainable Code: IOC encourages the development of modular and maintainable code by separating the construction and configuration of objects from their usage. This leads to code that is more focused on business logic and easier to understand and maintain.
- Constructor vs field injection (See the code)
- Benefit of using Constructor injection
- Testability
- Faster Because we don't need to create Spring context at all
- Cyclic Dependency detection
- Spring does not support cyclic dependencies with constructor injection.
- Cleaner Code
- Seriously, If you have more than 3,4 parameters in your constructor, your class probably doesn't follow a "Single responsibility" principal
- Testability
- Benefit of using Constructor injection
- AssertJ
- It provides a more expressive and fluent API for writing assertions compared to the more traditional assertion methods provided by JUnit. AssertJ's fluent syntax allows you to write assertions in a more readable and natural language style, making your tests easier to understand and maintain.
- It provides a wider range of assertion features beyond basic assertion
- It can do chain assertion in case you need to do "assertThat(42).isEven().isGreaterThan(20).isLessThan(55);" for some reason
- Custom assertion: For example, you want to check that user have full name you expect you can do assertThat(user) .haveFullName("Big Bigger");
- Mapper
- show example
- talk about ofNullable
- Api Versioning
- Make sure to have the API version in front of your API in case we need to update the version ( Breaking change, remove some field ), we can just create new endpoint with a new version
- Logging using @Slf4j rather than create your own logger or System.out.println()
- Standard Logging such as logging context information, stack traces, and exception handling. This can be invaluable for troubleshooting and debugging purposes, allowing you to capture relevant information when an issue occurs.
- Easy to config log level
- The logging levels used are ERROR, WARN, INFO, DEBUG and TRACE.
- SLF4J provides a very useful interface for working with parameters: logger.debug("Very important message: {}", message);
- Never use "System.out.println()" because it is blocking (not async)
- Data Model documentation
- It will tell the user what that field is
- The example will be used as an example in swagger
- Data Model Validation
- This is really clear!