官术网_书友最值得收藏!

Building our services

Let's start building parts of our Issue Management System (IMS), which is going to be a one-stop-destination for collaboration among teams. As the name implies, this system will be used for managing issues that are raised as tickets and get assigned to users for resolution. To begin the project, we will identify our microservice candidates based on the business model of IMS. Here, let's define three functional services, which will be hosted in their own independent Git repositories:

  • ims-micro-users
  • ims-micro-tasks
  • ims-micro-notify

You might wonder, why these three and why separate repositories? We could create much more fine-grained services and perhaps it wouldn't be wrong to do so. The answer lies in understanding the following points:

  • Isolating what varies: We need to be able to independently develop and deploy each unit. Changes to one business capability or domain shouldn't require changes in other services more often than desired.
  • Organisation or Team structure: If you define teams by business capability, then they can work independent of others and release features with greater agility. The tasks team should be able to evolve independent of the teams that are handling users or notifications. The functional boundaries should allow independent version and release cycle management.
  • Transactional boundaries for consistency: Distributed transactions are not easy, thus creating services for related features that are too fine grained, and lead to more complexity than desired. You would need to become familiar with concepts like eventual consistency, but these are not easy to achieve in practice.
  • Source repository per service: Setting up a single repository that hosts all the services is ideal when it's the same team that works on these services and the project is relatively small. But we are building our fictional IMS, which is a large complex system with many moving parts. Separate teams would get tightly coupled by sharing a repository. Moreover, versioning and tagging of releases will be yet another problem to solve.

The projects are created as standard Java EE projects, which are Skinny WARs, that will be deployed using the Payara Micro server. Payara Micro allows us to delay the decision of using a Fat JAR or Skinny WAR. This gives us flexibility in picking the deployment choice at a later stage.

As Maven is a widely adopted build tool among developers, we will use the same to create our example projects, using the following steps:

mvn archetype:generate -DgroupId=org.jee8ng -DartifactId=ims-micro-users -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

mvn archetype:generate -DgroupId=org.jee8ng -DartifactId=ims-micro-tasks -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

mvn archetype:generate -DgroupId=org.jee8ng -DartifactId=ims-micro-notify -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Once the structure is generated, update the properties and dependencies section of pom.xml with the following contents, for all three projects:

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

</dependencies>

Next, create a beans.xml file under WEB-INF folder for all three projects:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="all">
</beans>

You can delete the index.jsp and web.xml files, as we won't be needing them.

The following is the project structure of ims-micro-users. The same structure will be used for ims-micro-tasks and ims-micro-notify:

└── ims-micro-users
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── jee8ng
│ │ └── ims
│ │ └── users
│ │ ├── JaxrsActivator.java
│ │ ├── boundary
│ │ ├── control
│ │ └── entity
│ ├── resources
│ └── webapp
│ └── WEB-INF
│ └── beans.xml
└── test
└── java

The package name for users, tasks, and notify service will be as shown as the following:

  • org.jee8ng.ims.users (inside ims-micro-users)
  • org.jee8ng.ims.tasks (inside ims-micro-tasks)
  • org.jee8ng.ims.notify (inside ims-micro-notify)

Each of the above will in turn have sub-packages called boundary, control, and entity. The structure follows the Boundary-Control-Entity (BCE)/Entity-Control-Boundary (ECB) pattern.

The JaxrsActivator shown as follows is required to enable the JAX-RS API and thus needs to be placed in each of the projects:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("resources")
public class JaxrsActivator extends Application {}

All three projects will have REST endpoints that we can invoke over HTTP. When doing RESTful API design, a popular convention is to use plural names for resources, especially if the resource could represent a collection. For example:

  • /users
  • /tasks

The resource class names in the projects use the plural form, as it's consistent with the resource URL naming used. This avoids confusions such as a resource URL being called a users resource, while the class is named UserResource. Given that this is an opinionated approach, feel free to use singular class names if desired.

Here's the relevant code for ims-micro-users, ims-micro-tasks, and ims-micro-notify projects respectively.

Under ims-micro-users, define the UsersResource endpoint:

package org.jee8ng.ims.users.boundary;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("users")
public class UsersResource {

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response get() {
return Response.ok("user works").build();
}
}

Under ims-micro-tasks, define the TasksResource endpoint:

package org.jee8ng.ims.tasks.boundary;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("tasks")
public class TasksResource {

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response get() {
return Response.ok("task works").build();
}
}

Under ims-micro-notify, define the NotificationsResource endpoint:

package org.jee8ng.ims.notify.boundary;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("notifications")
public class NotificationsResource {

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response get() {
return Response.ok("notification works").build();
}
}

Once you build all three projects using mvn clean install, you will get your Skinny WAR files generated in the target directory, which can be deployed on the Payara Micro server.

主站蜘蛛池模板: 道真| 泌阳县| 长治县| 盐津县| 遵化市| 永修县| 扬中市| 邻水| 邵阳县| 板桥市| 南昌市| 上栗县| 宣武区| 承德县| 缙云县| 夹江县| 高青县| 苏州市| 盐池县| 澄城县| 秭归县| 扶风县| 赤峰市| 肇庆市| 门头沟区| 涟源市| 巴马| 嵊泗县| 衡南县| 甘孜县| 基隆市| 河东区| 宁蒗| 拜泉县| 宁海县| 萍乡市| 元江| 新余市| 九江市| 龙岩市| 南丰县|