diff --git a/content/courses/spring-boot/_index.md b/content/courses/spring-boot/_index.md index 8a98741..584a3a5 100644 --- a/content/courses/spring-boot/_index.md +++ b/content/courses/spring-boot/_index.md @@ -5,61 +5,60 @@ weight: 3 # Prerequisites -* Solid understanding of Java -* Object-oriented programming -* Classes, methods and interfaces -* Basic understanding of databases -* Tables, primary keys, foreign keys, relationships, etc. -* Write basic SQL statements +Before diving in, make sure you're comfortable with the following: ---- +- **Java** — solid understanding of the language +- **Object-oriented programming** — classes, methods and interfaces +- **Databases** — tables, primary keys, foreign keys, relationships, etc. +- **SQL** — ability to write basic SQL statements + +--- # What is a Spring Framework? -**Spring** -- is a popular framework for building Java applications. It has a lot of modules, each designed to handle a specific task. They are combined into few different layers. +**Spring** is a popular framework for building Java applications. It has a lot of modules, each designed to handle a specific task. They are combined into a few different layers. -![Spring layers](assets/spring-layers.svg) -*Img. 1 -- Spring layers* +![Spring layers](assets/spring-layers.svg) +*Img. 1 — Spring layers* | **Layer** | **Purpose** | -| ------------- | -------------- | -| *Core* | Handling dependency injection, managing objects | -| *Web* | Building web applications | -| *Data* | Working with databases | -| *AOP* | Aspect oriented programming | -| *Test* | Testing spring components | +|-----------|-------------| +| *Core* | Handling dependency injection, managing objects | +| *Web* | Building web applications | +| *Data* | Working with databases | +| *AOP* | Aspect oriented programming | +| *Test* | Testing spring components | ---- +--- -While the spring framework is powerfull, using it often involves a lot of configuration. For example, if you want to build a web app you might need to setup a web server, configure routing and manage dependencies manually. That's when **Spring Boot** comes in. +While the Spring Framework is powerful, using it often involves a lot of configuration. For example, if you want to build a web app you might need to setup a web server, configure routing and manage dependencies manually. That's when **Spring Boot** comes in. -You can think of spring boot as a layer on top of the spring framework, that takes care of all of the setup. +> [!NOTE] +> You can think of Spring Boot as a layer on top of the Spring Framework that takes care of all of the setup. *Spring Boot* simplifies Spring development by providing sensible defaults and ready-to-use features. -*Sring Boot* siplifies Spring development by providing sensible defaults and ready-to-use features. +By the way, the Spring Framework is just one part of a larger family of projects in the **Spring ecosystem**. -By the way, the spring framework is just one part of a larger family of projects in the spring ecosystem. +![Spring ecosystem](assets/spring-ecosystem.svg) +*Img. 2 — Spring ecosystem* -![Spring ecosystem](assets/spring-ecosystem.svg) -*Img. 2 -- Spring ecosystem* +| **Module Name** | **Purpose** | +|------------------------|-------------| +| *Spring Data* | Simplifying database access | +| *Spring Security* | Adding authentication and authorization | +| *Spring Batch* | Batch processing | +| *Spring Cloud* | Building microservices and distributed systems | +| *Spring Integration* | Simplifying messaging and integration between systems | -| **Module Name** | **Purpose** | -| ------------- | -------------- | -| *Spring Data* | Simplifying database access | -| *Spring Security* | Adding authentication and authorization | -| *Spring Batch* | Batch processing | -| *Spring Cloud* | Building microservices and distributed systems | -| *Spring Integration* | Symplifying messaging and integration between systems | +--- ---- +# Initialize Spring Boot Project -# Initialize Spring Boot Project - -To initialize a new spring boot project you can go to [start.spring.io](https://start.spring.io/) and select options that suits you. +To initialize a new Spring Boot project, go to [start.spring.io](https://start.spring.io/) and select the options that suit you. ![Spring Options](assets/spring-project-init.png) -*Img. 3 -- Spring Boot options* +*Img. 3 — Spring Boot options* -After unpacking the `zip` arvhive we have this template project. +After unpacking the `zip` archive, you'll have this template project: ```bash . @@ -70,23 +69,23 @@ After unpacking the `zip` arvhive we have this template project. ├── src │ ├── main │ │ ├── java -│ │ │ └── us -│ │ │ └── fymio +│ │ │ └── tech +│ │ │ └── codejava │ │ │ └── store │ │ │ └── StoreApplication.java │ │ └── resources │ │ └── application.properties │ └── test │ └── java -│ └── us -│ └── fymio +│ └── tech +│ └── codejava │ └── store │ └── StoreApplicationTests.java └── target ├── classes │ ├── application.properties - │ └── us - │ └── fymio + │ └── tech + │ └── codejava │ └── store │ └── StoreApplication.class ├── generated-sources @@ -104,16 +103,16 @@ After unpacking the `zip` arvhive we have this template project. │ ├── createdFiles.lst │ └── inputFiles.lst ├── surefire-reports - │ ├── TEST-us.fymio.store.StoreApplicationTests.xml - │ └── us.fymio.store.StoreApplicationTests.txt + │ ├── TEST-tech.codejava.store.StoreApplicationTests.xml + │ └── tech.codejava.store.StoreApplicationTests.txt └── test-classes - └── us - └── fymio + └── tech + └── codejava └── store └── StoreApplicationTests.class ``` -The "heart" of our project is the file named `pom.xml`: +The "heart" of our project is `pom.xml`: ```xml @@ -122,85 +121,85 @@ The "heart" of our project is the file named `pom.xml`: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 4.0.2 - - - us.fymio - store - 0.0.1-SNAPSHOT - store - Store - - - - - - - - - - - - - - - 21 - - - - org.springframework.boot - spring-boot-starter - + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 4.0.2 + + + tech.codejava + store + 0.0.1-SNAPSHOT + store + Store + + + + + + + + + + + + + + + 21 + + + + org.springframework.boot + spring-boot-starter + - - org.springframework.boot - spring-boot-starter-test - test - - + + org.springframework.boot + spring-boot-starter-test + test + + - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + + + org.springframework.boot + spring-boot-maven-plugin + + + ``` Maven uses this file to download dependencies and build our project. -In the `source` folder we have the actual code for our project. +In the `src` folder we have the actual code: ```bash src ├── main │ ├── java -│ │ └── us -│ │ └── fymio +│ │ └── tech +│ │ └── codejava │ │ └── store │ │ └── StoreApplication.java │ └── resources │ └── application.properties └── test └── java - └── us - └── fymio + └── tech + └── codejava └── store └── StoreApplicationTests.java ``` -The `StoreApplication.java` file is the entry point to our application. +`StoreApplication.java` is the entry point to our application: ```java -package us.fymio.store; +package tech.codejava.store; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -208,20 +207,20 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class StoreApplication { - public static void main(String[] args) { - SpringApplication.run(StoreApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(StoreApplication.class, args); + } } ``` -In the `main` method we have a call to `SpringApplication.run` method. +In the `main` method we have a call to `SpringApplication.run`. -If we run `mvn clean install` from the root of our project we will get this result (the output is partially reduced): +Running `mvn clean install` from the root of our project gives us this result *(output partially reduced)*: ```bash ... -[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.542 s -- in us.fymio.store.StoreApplicationTests +[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.542 s -- in tech.codejava.store.StoreApplicationTests [INFO] [INFO] Results: [INFO] @@ -233,10 +232,6 @@ If we run `mvn clean install` from the root of our project we will get this resu [INFO] [INFO] --- spring-boot:4.0.2:repackage (repackage) @ store --- ... -... -[INFO] Installing /home/fymio/store/pom.xml to /home/fymio/.m2/repository/us/fymio/store/0.0.1-SNAPSHOT/store-0.0.1-SNAPSHOT.pom -[INFO] Installing /home/fymio/store/target/store-0.0.1-SNAPSHOT.jar to /home/fymio/.m2/repository/us/fymio/store/0.0.1-SNAPSHOT/store-0.0.1-SNAPSHOT.jar -[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 14.787 s @@ -244,18 +239,20 @@ If we run `mvn clean install` from the root of our project we will get this resu [INFO] ------------------------------------------------------------------------ ``` -So we can tell that our application was built without errors. +Our application built without errors. + +--- # Dependency Management -Dependencies are third-party libraries or frameworks we use in our application. For example to build a web application we need an embedded web server like *Tomcat*, we need libraries for handling web requests building APIs, processing JSON data, logging and so on. +Dependencies are third-party libraries or frameworks we use in our application. For example, to build a web application we need an embedded web server like *Tomcat*, libraries for handling web requests, building APIs, processing JSON data, logging and so on. -In spring boot applications instead of adding multiple individual libraries we can use a **starter dependency**. +In Spring Boot applications, instead of adding multiple individual libraries, we can use a **starter dependency**. -![Spring Boot Starter Web](assets/spring-boot-starter-web.svg) -*Img. 5 -- Spring Boot Starter Web* +![Spring Boot Starter Web](assets/spring-boot-starter-web.svg) +*Img. 5 — Spring Boot Starter Web* -To use this dependency we just need to copy the code below to our `pom.xml` file. +To use this dependency, copy the following into your `pom.xml`: ```xml @@ -265,53 +262,54 @@ To use this dependency we just need to copy the code below to our `pom.xml` file ``` -So the `dependencies` section would look like this +So the `dependencies` section would look like this: ```xml - - org.springframework.boot - spring-boot-starter - + + org.springframework.boot + spring-boot-starter + - - org.springframework.boot - spring-boot-starter-test - test - + + org.springframework.boot + spring-boot-starter-test + test + - - org.springframework.boot - spring-boot-starter-web - - - + + org.springframework.boot + spring-boot-starter-web + + + ``` -Notice, that I commented out the version of our dependency. That's because it's a better practice to let Spring Boot decide what version of the dependency to use. +> [!IMPORTANT] +> Notice that the version is commented out. It's a better practice to let Spring Boot decide what version of the dependency to use, as it ensures compatibility across your project. + +--- # Controllers -**Spring MVC** stands for *Model View Controller*. +**Spring MVC** stands for *Model View Controller*. -*Model* is where our application's data lives. It represents the business logic and is usually connected to a database or other data sources. In spring boot the model can be a simple java class. +- **Model** is where our application's data lives. It represents the business logic and is usually connected to a database or other data sources. In Spring Boot, the model can be a simple Java class. +- **View** is what the user sees. It's the HTML, CSS or JavaScript rendered in the browser. In Spring MVC, views can be static files or dynamically generated. +- **Controller** is like a traffic controller. It handles incoming requests from the user, interacts with the model to get data and then tells the view what to display. -*View* is what the user sees. It's the HTML, CSS or JavaScript that's rendered in the browser. In Spring MVC views can be static files or dynamically generated. - -*Controller* is like a traffic controller. It handles incoming requests from the user, interacts with the model to get data and then tells the view what to display. - -Let's add a new java class called `HomeController`. It will be located at `src/main/java/us/fymio/store/HomeController.java`. +Let's add a new Java class called `HomeController` at `src/main/java/tech/codejava/store/HomeController.java`: ```java -package us.fymio.store; +package tech.codejava.store; public class HomeController {} ``` -To make this a controller we have to decorate it with the controller annotation. And import the `Controller` from `org.springframework.stereotype` package. +To make this a controller, decorate it with the `@Controller` annotation: ```java -package us.fymio.store; +package tech.codejava.store; import org.springframework.stereotype.Controller; @@ -319,10 +317,10 @@ import org.springframework.stereotype.Controller; public class HomeController {} ``` -Let's now add an `index` method. When we send a request to the root of our website we want this method to be called. Also we need to add another special annotation to this method. +Now let's add an `index` method. When we send a request to the root of our website, we want this method to be called: ```java -package us.fymio.store; +package tech.codejava.store; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -337,7 +335,7 @@ public class HomeController { } ``` -Now we need to create this view. We add the `index.html` at `src/main/resources/static/index.html`. For now let's just print "Hello world!". +Now we need to create the view. Add `index.html` at `src/main/resources/static/index.html`: ```html @@ -353,33 +351,31 @@ Now we need to create this view. We add the `index.html` at `src/main/resources/ ``` -Now let's build our application using `mvn spring-boot:run`. - -As we can see from the logs: +Let's build and run our application using `mvn spring-boot:run`. From the logs: ```bash -2026-02-19T14:55:23.948+03:00 INFO 36752 --- [store] [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2026-02-19T14:55:23.948+03:00 INFO 36752 --- [store] [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) ``` -It means that our app is up and running at [localhost:8080](http://localhost:8080/). +Our app is up and running at [localhost:8080](http://localhost:8080/). -![Hello world!](assets/hello-world.png) -*Img. 7 -- Our app is up and running!* +![Hello world!](assets/hello-world.png) +*Img. 7 — Our app is up and running!* + +--- # Configuring Application Properties -Let's take a look at our `application.properties` file located at `src/main/resources/application.properties`. +Let's take a look at `src/main/resources/application.properties`: ```properties spring.application.name=store ``` -To use this property in our code we can use the `@Value` annotation. - -Let's change our `HomeController` class so it prints the name of our application. +To use this property in our code, we can use the `@Value` annotation. Let's update `HomeController` to print the application name: ```java -package us.fymio.store; +package tech.codejava.store; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; @@ -399,19 +395,276 @@ public class HomeController { } ``` -And as we can see after running our application there is a `store` printed out in the terminal. +After running the application, we can see `store` printed in the terminal: ```bash ... -2026-02-19T15:32:37.507+03:00 INFO 41536 --- [store] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' -2026-02-19T15:32:37.509+03:00 INFO 41536 --- [store] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms +2026-02-19T15:32:37.507+03:00 INFO 41536 --- [store] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' +2026-02-19T15:32:37.509+03:00 INFO 41536 --- [store] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms application name = store ... ``` -# Dependency injection +--- -Imagine we are building an E-Commerce application that handles placing orders. When the order is placed, the customer's payment needs to be processed so order service depends on a payment service like stripe payment service. In this case we can say that order service is *dependent* or *coupled to* stripe payment service. +# Dependency Injection -![Depends on/Coupled to relation](assets/depends-on-coupled-to.svg) -*Img. 8 -- Depends On/Coupled To relation.* +Imagine we're building an E-Commerce application that handles placing orders. When an order is placed, the customer's payment needs to be processed — so `OrderService` depends on a payment service like `StripePaymentService`. We can say that `OrderService` is *dependent on* (or *coupled to*) `StripePaymentService`. + +![Depends on/Coupled to relation](assets/depends-on-coupled-to.svg) +*Img. 8 — Depends On/Coupled To relation* + +Let's talk about the issues that arise when one class is **tightly coupled** to another. + +1. **Inflexibility** — `OrderService` can only use `StripePaymentService`. If tomorrow we decide to switch to a different payment provider like PayPal, we would have to modify `OrderService`. Once we change it, it has to be recompiled and retested, which could impact other classes that depend on it. +2. **Untestability** — We cannot test `OrderService` in isolation, because `OrderService` is tightly coupled with `StripePaymentService` and we can't test its logic separately from it. + +> [!NOTE] +> The problem here isn't that `OrderService` *depends* on `StripePaymentService` — dependencies are normal in any application. The issue is about *how* the dependency is created and managed. + +**Analogy:** Think of a restaurant. A restaurant needs a chef — that's a perfectly normal dependency. If the current chef becomes unavailable, the restaurant can hire another one. + +![Restaurant — Chef dependency](assets/restaurant-chef-dependency.svg) +*Img. X — Restaurant — Chef dependency (Normal)* + +Now what if we replace "chef" with a specific person: John? Our restaurant is now dependent on *John specifically*. If John becomes unavailable, we can't replace him — the restaurant is in trouble. This is an example of **tight** or **bad coupling**. + +![Restaurant — John dependency](assets/restaurant-john-dependency.svg) +*Img. X — Restaurant — John dependency (Bad coupling)* + +We don't want `OrderService` to be tightly coupled to a specific payment service like Stripe. Instead, we want it to depend on a `PaymentService` *interface*, which could be Stripe, PayPal, or any other provider. To achieve this we can use the *interface* to decouple `OrderService` from `StripePaymentService`. + +![Payment Service as `interface`](assets/payment-service-as-interface.svg) +*Img. X — `PaymentService` as `interface`* + +If `OrderService` depends on a `PaymentService` interface, it doesn't know anything about Stripe, PayPal, or any other payment provider. As long as these providers implement `PaymentService`, they can be used to handle payments — and `OrderService` won't care which one is being used. + +**Benefits:** + +1. If we replace `StripePaymentService` with `PayPalPaymentService`, the `OrderService` class is not affected. +2. We don't need to modify or recompile `OrderService`. +3. We can test `OrderService` in isolation, without relying on the specific payment provider like Stripe. + +With this setup, we simply give `OrderService` a particular implementation of `PaymentService`. This is called **dependency injection** — we *inject* the dependency into a class. + +![Dependency Injection example](assets/dependency-injection.svg) +*Img. X — Dependency Injection example* + +Let's see how it works in our project. Create `OrderService` at `src/main/java/tech/codejava/store/OrderService.java`: + +```java +package tech.codejava.store; + +public class OrderService { + + public void placeOrder() {} +} +``` + +> [!NOTE] +> In a real project we would need to provide something like `Order order` to this method, but for teaching purposes we won't do that. + +Now create `StripePaymentService` in the same directory: + +```java +package tech.codejava.store; + +public class StripePaymentService { + + public void processPayment(double amount) { + System.out.println("=== STRIPE ==="); + System.out.println("amount: " + amount); + } +} +``` + +Let's implement `placeOrder` in `OrderService` using `StripePaymentService`: + +```java +package tech.codejava.store; + +public class OrderService { + + public void placeOrder() { + var paymentService = new StripePaymentService(); + paymentService.processPayment(10); + } +} +``` + +> [!IMPORTANT] +> This is our *before* setup — before we introduced the interface. In this implementation, `OrderService` is **tightly coupled** to `StripePaymentService`. We cannot test `OrderService` in isolation, and switching to another payment provider would require modifying `OrderService`. + +Let's fix this. Create a `PaymentService` interface in the same directory: + +```java +package tech.codejava.store; + +public interface PaymentService { + void processPayment(double amount); +} +``` + +Modify `StripePaymentService` to implement `PaymentService`: + +```java +package tech.codejava.store; + +public class StripePaymentService implements PaymentService { + + @Override + public void processPayment(double amount) { + System.out.println("=== STRIPE ==="); + System.out.println("amount: " + amount); + } +} +``` + +The recommended way to inject a dependency into a class is via its **constructor**. Let's define one in `OrderService`: + +```java +package tech.codejava.store; + +public class OrderService { + + private PaymentService paymentService; + + public OrderService(PaymentService paymentService) { + this.paymentService = paymentService; + } + + public void placeOrder() { + paymentService.processPayment(10); + } +} +``` + +Now let's see this in action. Modify `StoreApplication`: + +```java +package tech.codejava.store; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StoreApplication { + + public static void main(String[] args) { + // SpringApplication.run(StoreApplication.class, args); + + var orderService = new OrderService(new StripePaymentService()); + orderService.placeOrder(); + } +} +``` + +Running the application *(output intentionally reduced)*: + +```bash +... +=== STRIPE === +amount: 10.0 +... +``` + +Now let's create a `PayPalPaymentService` in the same directory: + +```java +package tech.codejava.store; + +public class PayPalPaymentService implements PaymentService { + + @Override + public void processPayment(double amount) { + System.out.println("=== PayPal ==="); + System.out.println("amount: " + amount); + } +} +``` + +Now we can switch from `StripePaymentService` to `PayPalPaymentService` in `StoreApplication` — without touching `OrderService` at all: + +```java +package tech.codejava.store; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StoreApplication { + + public static void main(String[] args) { + // SpringApplication.run(StoreApplication.class, args); + + // var orderService = new OrderService(new StripePaymentService()); + var orderService = new OrderService(new PayPalPaymentService()); + orderService.placeOrder(); + } +} +``` + +```bash +... +=== PayPal === +amount: 10.0 +... +``` + +Notice that we didn't change `OrderService`. In *object-oriented programming* this is known as the **Open/Closed Principle**: + +> A class should be open for extension and closed for modification. + +In other words: we should be able to add new functionality to a class without changing its existing code. This reduces the risk of introducing bugs and breaking other parts of the application. + +--- + +## Setter Injection + +Another way to inject a dependency is via a **setter**. In `OrderService`, let's define one: + +```java +package tech.codejava.store; + +public class OrderService { + + private PaymentService paymentService; + + public void setPaymentService(PaymentService paymentService) { + this.paymentService = paymentService; + } + + public OrderService(PaymentService paymentService) { + this.paymentService = paymentService; + } + + public void placeOrder() { + paymentService.processPayment(10); + } +} +``` + +We can use it like this in `StoreApplication`: + +```java +package tech.codejava.store; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StoreApplication { + + public static void main(String[] args) { + // SpringApplication.run(StoreApplication.class, args); + + // var orderService = new OrderService(new StripePaymentService()); + var orderService = new OrderService(new PayPalPaymentService()); + orderService.setPaymentService(new PayPalPaymentService()); + orderService.placeOrder(); + } +} +``` + +> [!IMPORTANT] +> If you remove the constructor from `OrderService` and forget to call the setter, the application will crash with a `NullPointerException`. Use setter injection only for **optional** dependencies — ones that `OrderService` can function without. diff --git a/content/courses/spring-boot/assets/dependency-injection.svg b/content/courses/spring-boot/assets/dependency-injection.svg new file mode 100644 index 0000000..a4e6341 --- /dev/null +++ b/content/courses/spring-boot/assets/dependency-injection.svg @@ -0,0 +1,4 @@ + + + +
OrderService
PaymentService
<<interface>>
Stripe
PayPal
<<class>>
<<class>>
Dependency Injection
\ No newline at end of file diff --git a/content/courses/spring-boot/assets/payment-service-as-interface.svg b/content/courses/spring-boot/assets/payment-service-as-interface.svg new file mode 100644 index 0000000..c70e4ff --- /dev/null +++ b/content/courses/spring-boot/assets/payment-service-as-interface.svg @@ -0,0 +1,4 @@ + + + +
OrderService
PaymentService
<<interface>>
Stripe
PayPal
<<class>>
<<class>>
\ No newline at end of file diff --git a/content/courses/spring-boot/assets/restaurant-chef-dependency.svg b/content/courses/spring-boot/assets/restaurant-chef-dependency.svg new file mode 100644 index 0000000..f9e814f --- /dev/null +++ b/content/courses/spring-boot/assets/restaurant-chef-dependency.svg @@ -0,0 +1,4 @@ + + + +
Restaurant
Chef
Normal
\ No newline at end of file diff --git a/content/courses/spring-boot/assets/restaurant-john-dependency.svg b/content/courses/spring-boot/assets/restaurant-john-dependency.svg new file mode 100644 index 0000000..1451100 --- /dev/null +++ b/content/courses/spring-boot/assets/restaurant-john-dependency.svg @@ -0,0 +1,4 @@ + + + +
Restaurant
John
Bad coupling
\ No newline at end of file diff --git a/public/courses/spring-boot/assets/dependency-injection.svg b/public/courses/spring-boot/assets/dependency-injection.svg new file mode 100644 index 0000000..a4e6341 --- /dev/null +++ b/public/courses/spring-boot/assets/dependency-injection.svg @@ -0,0 +1,4 @@ + + + +
OrderService
PaymentService
<<interface>>
Stripe
PayPal
<<class>>
<<class>>
Dependency Injection
\ No newline at end of file diff --git a/public/courses/spring-boot/assets/payment-service-as-interface.svg b/public/courses/spring-boot/assets/payment-service-as-interface.svg new file mode 100644 index 0000000..c70e4ff --- /dev/null +++ b/public/courses/spring-boot/assets/payment-service-as-interface.svg @@ -0,0 +1,4 @@ + + + +
OrderService
PaymentService
<<interface>>
Stripe
PayPal
<<class>>
<<class>>
\ No newline at end of file diff --git a/public/courses/spring-boot/assets/restaurant-chef-dependency.svg b/public/courses/spring-boot/assets/restaurant-chef-dependency.svg new file mode 100644 index 0000000..f9e814f --- /dev/null +++ b/public/courses/spring-boot/assets/restaurant-chef-dependency.svg @@ -0,0 +1,4 @@ + + + +
Restaurant
Chef
Normal
\ No newline at end of file diff --git a/public/courses/spring-boot/assets/restaurant-john-dependency.svg b/public/courses/spring-boot/assets/restaurant-john-dependency.svg new file mode 100644 index 0000000..1451100 --- /dev/null +++ b/public/courses/spring-boot/assets/restaurant-john-dependency.svg @@ -0,0 +1,4 @@ + + + +
Restaurant
John
Bad coupling
\ No newline at end of file diff --git a/public/courses/spring-boot/index.html b/public/courses/spring-boot/index.html index 898204c..3bb24e9 100644 --- a/public/courses/spring-boot/index.html +++ b/public/courses/spring-boot/index.html @@ -9,9 +9,8 @@ CodeJava - + - - + + - + @@ -169,7 +166,13 @@ Layer Purpose Core Handling dependency injection, managing objects Web Building >Spring Boot - +