- Java EE 8 and Angular
- Prashant Padmanabhan
- 893字
- 2021-07-02 19:22:40
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.
- Facebook Application Development with Graph API Cookbook
- Python入門很簡單
- C++面向對象程序設計(微課版)
- 微服務設計原理與架構
- Oracle Database 12c Security Cookbook
- Python數據可視化之Matplotlib與Pyecharts實戰
- 執劍而舞:用代碼創作藝術
- Test-Driven Development with Django
- Python趣味編程與精彩實例
- 深入解析Java編譯器:源碼剖析與實例詳解
- Python Programming for Arduino
- Visual Basic程序設計基礎
- Software Architecture with Python
- INSTANT LESS CSS Preprocessor How-to
- Python程序設計:基礎與實踐