Skip to main content

3 posts tagged with "spring-boot"

View All Tags

· 3 min read
Elbert Ribeiro

Design Patterns are solutions to common software development problems. They offer proven guidelines for designing code efficiently and in a reusable manner. Among these patterns, the Factory Pattern is widely used for creating objects in a flexible and decoupled way. In this article, we will explore how to apply the Factory Design Pattern in a Spring Boot project, providing a practical example to illustrate its usage.

The Factory Pattern

The Factory Pattern is a creational design pattern that focuses on object creation. It provides an interface for creating objects, allowing subclasses to decide which concrete class to instantiate. This promotes the principles of abstraction and decoupling.

There are two main variants of the Factory Pattern: the Factory Method and the Abstract Factory. However, we will focus on the Factory Method here, as it is the most commonly used and easiest to understand.

Implementing the Factory Method with Spring Boot

Let's consider a scenario where we have an order management system in a Spring Boot application. There are different types of orders, such as physical product orders, service orders, and subscription orders. Each type of order requires different creation logic.

To apply the Factory Method, we will start by creating an Order interface that defines the common operations for all types of orders:

public interface Order {
void process();
}

Now, we will create concrete implementations of this interface for each type of order:

public class PhysicalProductOrder implements Order {
@Override
public void process() {
// Logic to process a physical product order
}
}

public class ServiceOrder implements Order {
@Override
public void process() {
// Logic to process a service order
}
}

public class SubscriptionOrder implements Order {
@Override
public void process() {
// Logic to process a subscription order
}
}

Next, we will create the order factory that allows us to create concrete order instances:

public class OrderFactory {
public Order createOrder(OrderType type) {
return switch (type) {
case PHYSICAL_PRODUCT -> new PhysicalProductOrder();
case SERVICE -> new ServiceOrder();
case SUBSCRIPTION -> new SubscriptionOrder();
default -> throw new IllegalArgumentException("Unknown order type");
};
}
}

The OrderType enumeration is used to identify the type of order we want to create.

Now, we can use the factory to create orders in our Spring Boot application:

public class OrderService {
private OrderFactory orderFactory;

public OrderService(OrderFactory orderFactory) {
this.orderFactory = orderFactory;
}

public void processOrder(OrderType type) {
Order order = orderFactory.createOrder(type);
order.process();
}
}

The OrderService class injects the order factory and uses the Factory Method to create and process orders based on the specified type.

Finally, we can configure Spring Boot to inject the order factory into our application:

@Configuration
public class AppConfig {
@Bean
public OrderFactory orderFactory() {
return new OrderFactory();
}
}

Now, whenever we need to create a new type of order, we can simply add a new implementation of the Order interface and update the order factory to accommodate the new type, keeping our code flexible and extensible.

Conclusion

The Factory Design Pattern is a valuable tool for creating objects in a flexible and decoupled manner in a Spring Boot project. It promotes the principles of abstraction and makes code more reusable and extensible. By following the principles of the Factory Method, we can create an order management system that can easily accommodate new types of orders without modifying existing code. This is just one example of how the Factory Design Pattern can be applied in software development, and its applications are broad and varied.

· 4 min read
Elbert Ribeiro

When developing a Spring Boot application, one of the most critical decisions to make is regarding the project's structure. Traditionally, many projects are organized into layers, such as DTO, Entity, and Service, to facilitate the separation of responsibilities. However, an alternative approach, based on domain-driven design (DDD), has gained prominence in recent years. In this article, we will explore the reasons why domain-based separation (e.g., Person, Car, Payment) is often a superior choice compared to layered separation.

1. Clarity and Focus on Business Logic

The domain-driven design approach places business logic at the heart of the project. Each package or module is associated with a specific domain concept, such as Person, Car, or Payment. This makes the code clearer as the components are closely related to business needs. As a result, developers can concentrate on the specific rules and functionalities of the domain, rather than getting lost in abstract layers.

2. Ease of Maintenance and Evolution

The domain-based structure simplifies the maintenance of the application. When a change is required in a business rule, you know exactly where to look and make the necessary modifications. In contrast, in a layered structure, changes often involve modifying several parts of the code, making it more error-prone and harder to maintain.

3. Enhanced Code Reusability

With domain-based separation, it is easier to reuse components in different parts of the application or even in future projects. For example, if you develop a Payment feature in one project, you can easily reuse it in another project involving Payments, without the need to recreate the entire service and data access layer.

4. Improved Testability

The domain-based structure allows the straightforward creation of domain-specific unit tests. This is crucial for ensuring code quality and application stability. Tests can be written more directly, covering the key domain functionalities.

5. Scalability and Flexibility

As the application grows, the domain-based structure naturally adapts. New functionalities can be added within the context of the existing domain, as long as the domain is well defined. This flexibility makes it easier to scale the application as new requirements emerge.

Downsides of Layered Organization

To provide a comprehensive overview, it's essential to consider the downsides of a layered organization:

  1. Complex Communication: A rigid separation into layers can lead to complex communication between the layers, resulting in intricate code to transfer data between different layers, such as DTOs.

  2. Risk of Anemic Domain: In projects with a layered organization, the so-called "Anemic Domain" can occur, where entities (Entities) frequently lack behavior (methods), resulting in an excessively burdened service layer.

  3. Increased Boilerplate Code: With distinct layers, it often requires writing more boilerplate code to convert data between DTOs and Entities, increasing code complexity.

  4. Difficulty Maintaining Cohesion: Maintaining class and component cohesion can be challenging in projects with layered organization, as responsibilities are distributed across different parts of the code.

  5. Reduced Clarity of Business Rules: In a layered structure, business logic is often diluted, making it difficult to understand specific business rules.

Bibliographic References

To further your understanding of the domain-driven design approach in Spring Boot projects and the disadvantages of a layered organization, you may consider reading the following books:

  1. "Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans
  2. "Implementing Domain-Driven Design" by Vaughn Vernon
  3. "Patterns, Principles, and Practices of Domain-Driven Design" by Scott Millett and Nick Tune
  4. "Clean Code: A Handbook of Agile Software Craftsmanship" by Robert C. Martin
  5. "Refactoring: Improving the Design of Existing Code" by Martin Fowler

These references provide valuable insights into code organization and best practices for Spring Boot projects.

Conclusion

The domain-driven design approach offers numerous advantages over layered separation in Spring Boot projects, including greater clarity, ease of maintenance, code reusability, testability, and scalability. However, it's important to note that the choice between these approaches should be based on the specific project's needs and the development team's preferences. In some cases, a combination of both approaches may be the ideal solution, allowing you to leverage the best of each approach to effectively meet project requirements.

· 7 min read
Elbert Ribeiro

This article was born out of a day-to-day need, in short, at my workplace we are updating the infrastructure and some technologies (which is beside the point now), but the problem is; we have more than 200 applications in production, how to make all this run with spring-boot and in weblogic 12? (The idea here is to make the transition of technologies little by little).

Many of the materials I’ve found on the internet are either outdated or simply don’t work for spring-boot 2.7.12 and weblogic 12.2.1.3, or are simply too complicated for a novice developer to understand. The idea here is not to explain each point of the configuration, class or lib, how it is done and how it works. The idea is that any dev, inciting or not, can replicate the configuration, and have your application running with weblogic + spring-boot.

The structure I used in the project applies a concept of maven multi modules (if you are a beginner developer and don’t know what I’m talking about, talk to your senior dev or search the internet about the advantages and disadvantages. Maybe I’ll write an article about). Even using maven multi modules it is a simple structure, with 30 min studying the code you will understand. For this article I used Intellij Community, although it has the Ultimate version, I want to keep this article as generic as possible so that any dev can apply what was developed here in their reality.


Project Structure

About the structure of the project, I developed two modules, api and core.

spring-boot-projetc-struture


Main Module

Let’s start with the parent project’s pom.xml. The idea here is to group the default settings for every project. I’m using Java 8 and UTF-8 for the encoder, however, whether your project is legacy or not, it may have another encoder ( check before compiling, especially if your project is JSP).

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.elbertribeiro</groupId>
<artifactId>spring-boot-weblogic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-weblogic</name>
<modules>
<module>spring-boot-weblogic-core</module>
<module>spring-boot-weblogic-api</module>
</modules>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<spring.boot.version>2.7.12</spring.boot.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

Core Module

Now, going from bottom to top, in the spring-boot-weblogic-core module, we have the following structure:

core-module-structure

In spring-boot-weblogic-core’s pom.xml we will have:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.elbertribeiro</groupId>
<artifactId>spring-boot-weblogic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>spring-boot-weblogic-core</artifactId>
<dependencies>
<!--SPRING BOOT-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

Note that the pom.xml is simple, and the idea is that it contains the dependencies for the api module.

Inside the JAVA directory we have only one package (as the idea here is just to present a functional concept, this model is as simple as possible).

teste-service

In the test package we have the TesteService class, which would work as a Service layer for the api. In TesteService, we have the following code;

package com.elbertribeiro.teste;

import org.springframework.stereotype.Service;

@Service
public class TesteService {
public String retornoService() {
return "Teste Weblogic com multiModules e service e @Autowired";
}
}

Note that the added dependency in spring-boot-weblogic-core’s pom.xml allows us to use Annotations normally. The core module is simple for the purpose of this article, now let’s move on to the more interesting part.

API module

Now, let’s go to the spring-boot-weblogic-api module, we have the following structure:

spring-boot-project-structure

The first point to note is that the api module has more files, because it will contain the class that initializes the project in spring-boot and will also be implemented in weblogic.

In the spring-boot-weblogic-api pom.xml we will have:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.elbertribeiro</groupId>
<artifactId>spring-boot-weblogic</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>spring-boot-weblogic-api</artifactId>
<packaging>war</packaging>

<dependencies>
<!-- Dependencia dos modulos -->
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>${project.parent.artifactId}-core</artifactId>
<version>${project.parent.version}</version>
</dependency>

<!--SPRING BOOT-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${spring.boot.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring.boot.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<webResources>
<resource>
<directory>src/main/webapp</directory>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
</project>

If you paid attention to the parent module, you noticed that the spring-boot versions were defined globally and the modules only refer to the specified version.

The most important dependency here is:

core-module-structure

It will be responsible for allowing us to use the project with spring-boot even adding configurations to run in weblogic.

Also note that we have the core module of the project as a dependency, allowing access to any class, method or entity added in the core module:

module-core-dependency

We also have devtoos as a dependency, for those who don’t know it’s a lib that allows a browser update when a resource is changed at compile time, removing the need to restart your spring-boot service.

devtools-dependency

If you looked at the spring-boot-weblogic-api pom.xml you might have noticed two plugins:

plugin.png

The first allows you to run spring-boot commands like mvn spring-boot:run, while the second plugin is responsible for collecting and compiling all dependencies, classes and resources of the web application into a web application file, generating an artifact of type *.war.

I understand that I said I wouldn’t explain every lib configuration point and operation, but understanding how the dependencies work and when they will be used is important, this prevents your system from evolving by applying responsibilities where it shouldn’t.

Now let’s go to the “interesting part”, let’s add some configurations for the application to run in weblogic, however, I recommend that you research how each configuration works and why it exists. With that, I hope to partially fulfill the promise of not explaining how libs and configurations work (we can write an article explaining how they work soon).

About the resources directory, we only have an empty *.yml properties file. Already in the webapp directory, we have the files that allow you to add your application to weblogic, for the structure of the packages we have:

weblogic.png

In the weblogic.xml file we have;

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app
xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app
http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">

<wls:context-root>spring-boot-weblogic</wls:context-root>
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>org.slf4j.*</wls:package-name>
<wls:package-name>org.springframework.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
</wls:weblogic-web-app>

In the webapp directory we also have the file dispatcherServlet-servlet.xml;

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

And finally, we have the file structure of the JAVA directory:

dispatcherServlet-servlet.png

Where the ServletInitializer class has only one method:

package com.elbertribeiro.configuracao;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootWeblogicApplication.class);
}

}

The configure method is used to configure the spring-boot application to add to an external application server such as weblogic. It takes a SpringApplicationBuilder object as a parameter and returns an instance of it.

The configure method is being replaced to configure the SpringBootWeblogicApplication application as the spring-boot application source. This means that the SpringApplicationBuilder is being configured to load the configuration and components of that specific application when deploying to weblogic.

And we also have the class contains the main method, responsible for initializing our spring-boot application.

package com.elbertribeiro.configuracao;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.elbertribeiro")
public class SpringBootWeblogicApplication {

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

}

And as resources, we have only one endpoint that is present in the TesteController class;

package com.elbertribeiro.controller;

import com.elbertribeiro.teste.TesteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("teste")
public class TesteController {
@Autowired
private TesteService service;

@GetMapping
public String getTest() {
return service.retornoService();
}
}

I hope the article didn’t get too long, before finalizing it lacks proof that all this works 😂.


Running the application with spring-boot

To run this project with spring-boot run the command below in the spring-boot-weblogic-api module

mvn spring-boot:run

test-spring-boot.png

Running the application with Weblogic

Upload the artifact to weblogic and access the weblogic address with the path of your application.

test-weblogic.png

Conclusion

Well, it is true that using a multi-module maven project may not seem interesting at first, but it helps a lot, especially when we are talking about scalable software, if necessary, you can delete the core module, just pass the dependency to the module api move our classes to the api module as well.

The code for the developed project is here: https://github.com/ElbertRibeiro/spring-boot-weblogic/tree/artigo-medium

Below I will put my social networks, feel free to comment or discuss any topic addressed in this project.

References