How it works...

Let's understand how things work for each stage of the process.

The monolith application couldn't be simpler—it's just a project with two services using two beans to manage two entities. If you want to understand what is happening there regarding JAX-RS, Jakarta CDI, and/or Jakarta Persistence (formerly, JPA), check the relevant recipes earlier in this book.

So, we split the monolith into three projects (microservices)—the user service, the user address service, and the gateway service.

The user service classes remained unchanged after the migration from the monolith version. So, there's nothing to comment on.

The UserAddress class had to be changed to become a microservice. The first change was made on the entity.

Here is the monolith version:

@Entity
public class UserAddress implements Serializable {
...
@Column
@ManyToOne
private User user;

public UserAddress(User user, String street, String number,
String city, String zip) {
this.user = user;
...
}
...
}

Here is the microservice version:

@Entity
public class UserAddress implements Serializable {
...
@Column
private Long idUser;

public UserAddress(Long user, String street, String number,
String city, String zip) {
this.idUser = user;
...
}
...
}

Note that, in the monolith version, user was an instance of the User entity:

private User user;

In the microservice version, it became a number:

private Long idUser;

This happened for two main reasons:

  • In the monolith, we have the two tables in the same database (User and UserAddress), and they both have physical and logical relationships (foreign key). So, it makes sense to also keep the relationship between both the objects.
  • The microservice should have its database, completely independent of the other services. So, we choose to keep only the user ID, as it is enough to load the address properly anytime the client needs it.

This change also resulted in a change in the constructor.

Here is the monolith version:

public UserAddress(User user, String street, String number, 
String city, String zip)

Here is the microservice version:

public UserAddress(Long user, String street, String number, 
String city, String zip)

This could have lead to a change of contract with the client regarding the change of the constructor signature. But thanks to the way it was built, it wasn't necessary.

Here is the monolith version:

public Response add(UserAddress address)

Here is the microservice version:

public Response add(UserAddress address)

Even if the method is changed, it could easily be solved with @Path annotation, or if we really need to change the client, it would be only the method name and not the parameters (which used to be more painful).

Finally, we have the gateway service, which is our implementation of the API gateway design pattern. Basically, it is the one single point to access the other services.

The nice thing about it is that your client doesn't need to care about whether the other services changed the URL or the signature or even whether they are available. The gateway will take care of them.

The bad part is that it is also on a single point of failure. Or, in other words, without the gateway, all services are unreachable. But you can deal with it by using a cluster, for example.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.150.89