The SpringBoot project specification compiled a year ago is afraid of being lost. After all, it was written with care at the time, and now it is posted on the blog.
1. Application Division Specifications
When developing an application system, the back-end service needs to consider dividing multiple SpringBoot modules according to the principle of module/microservice division, so as to facilitate future microservice reconstruction. The rules/principles of application division are as follows:
- Horizontal split : Split according to different business domains, such as order, marketing, risk control, credit resources, etc. Form independent business domain microservice clusters.
- Vertical split : Split different modules or components in a business function. For example, splitting public components into independent atomic services and sinking them to the bottom layer to form a relatively independent atomic service layer. In this way, the service division of the business can be realized.
In order to do a good job in the layering of microservices, it is necessary to sort out and extract core services and public applications, and sink them into the core and public capability layers as independent services, and gradually form a stable service center, so that front-end applications can respond more quickly to changing Market demand. Is the service split the smaller the better? Microservices are big and small. For example, in the early days, we split the transaction into a microservice, but with the increase of business volume, a transaction system may have gradually become large, and the concurrent traffic is not small. In order to support more transaction volume, The trading system will be divided into order services, bidding services, transfer services, etc. Therefore, the splitting of services needs to be combined with specific businesses. The general principle is high cohesion within services and low coupling between services.
2. Project Creation Specifications
In an application system, at least one SpringBoot project and multiple SpringBoot modules will be created according to the situation. The following rules are followed when creating a project:
GroupID
: com.{Company/BU}.Line of Business[.Sub-Line of Business].Description: {company/BU} For example: alibaba/taobao/tmall/aliexpress and other BU first-level; sub-business lines are optional.
Positive example: com.taobao.jstorm or com.alibaba.dubbo.register
ArtifactID
format: product line name - module name. The semantics are not repeated or omitted. First go to the central warehouse to check.Positive example: dubbo-client/fastjson-api/jstorm-tool
Version
formatSecond-party library version number naming method: major version number. minor version number. revision number
1) Major version number: Product direction changes, or large-scale API incompatibilities, or architecture incompatible upgrades.
2) Minor version number: maintain relative compatibility, add major functional features, and make API incompatibility modifications with minimal impact.
3) Revision number: maintain full compatibility, fix bugs, add minor features, etc.
Note: Note that the starting version number must be: 1.0.0, not 0.0.1.
2.1. Parent module creation specification
One or more Spring Boot projects will be created in an application system. During the creation process of each Spring Boot project ( New -> Project
), the following specifications are followed:
name | specification |
---|---|
project type | Spring Initializr |
Group | Follow the java package name specification to the company level |
Artifact | <Project/Business Center Abbreviation>-service, etc. |
Type | Maven Project |
Language | Java |
Packaging | POM |
Java Version | keep default |
Name | Project name, same as Artifact |
Package | <Group>.<Project/Business Center Abbreviation> |
Version | You can select the newer stable version at the current time, such as the release version |
Among them, the version number naming method: major version number. minor version number. revision number
- Major version number: Product direction changes, or large-scale API incompatibilities, or schema incompatible upgrades.
- Minor version number: maintain relative compatibility, add major features, and make API incompatible modifications with a minimal impact.
- Revision number: maintain full compatibility, fix bugs, add minor features, etc.
Note: The starting version number must be: 1.0.0, not 0.0.1.
3. POM specification
3.1. Parent module POM specification
Parent module (tl-service) POM file reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/>
</parent>
<groupId>com.df.tl</groupId>
<artifactId>tl-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tl-service</name>
<description>tl项目的父模块</description>
<!-- 属性-->
<properties>
<java.version>1.8</java.version>
<spring-parent.version>2.4.5</spring-parent.version>
<lombok.version>1.18.0</lombok.version>
<mybatis.version>1.3.2</mybatis.version>
<mysql.version>8.0.16</mysql.version>
<druid.version>1.1.13</druid.version>
</properties>
<!-- 子模块,申明-->
<modules>
<module>tl-api</module>
<module>tl-project-service</module>
<module>tl-task-service</module>
</modules>
<!-- 打包方式 pom-->
<packaging>pom</packaging>
<!-- dependencyManagement 管理-->
<dependencyManagement>
<dependencies>
<!-- spring web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-parent.version}</version>
</dependency>
<!-- spring test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>${spring-parent.version}</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- druid 数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!-- pluginManagement 管理-->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
The points to note are as follows:
- properties : In addition to
java.version
, you can customize properties (not mandatory), such as the version number of maven dependencies. - modules : All submodules need to be declared.
- packaging : The parent module uses
pom
. This tag has three attributes:pom/jar/war
, but the function of the parent module is usually only packaged, so use pom. - dependencyManagement : The parent module recommends using
dependencyManagement
manage dependencies, which is more flexible thandependencies
and will not cause unnecessary dependencies to be introduced by submodules. You can check the information yourself and compare the difference betweendependencyManagement
anddependencies
. - pluginManagement : The parent module recommends using
pluginManagement
manage the plugin, which is more flexible thanplugins
. You can check the information yourself and compare the difference betweenpluginManagement
andplugins
.
3.2. Submodule POM Specification
Submodule (tl-project-service) POM file reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.df.tl</groupId>
<artifactId>tl-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.df.tl</groupId>
<artifactId>tl-project-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tl-project-service</name>
<description>项目管理模块</description>
<!-- 打包方式 jar-->
<packaging>jar</packaging>
<dependencies>
<!-- spring web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The points to note are as follows:
- parent : Inherit the parent module.
- packaging : Submodules use
jar
. - dependencies : Whether the parent module uses
dependencyManagement
ordependencies
, the sub-modules all usedependencies
. If it is the former, it is necessary to declare the repeated dependencies, but the version number can be omitted; if it is the latter, there is no need to repeat the dependencies. - plugins : Whether the parent module uses
pluginManagement
orplugins
, the sub-modules all useplugins
. If it is the former, you need to declare repeated dependencies, but you can omit the details of the version number and configuration; if it is the latter, there is no need to repeat dependencies.
4. Hierarchical Specifications
- Open interface layer : It can directly encapsulate the Service method and expose it as an RPC interface; encapsulate it into an http interface through the Web; gateway control layer, etc.
- Terminal display layer : The layer where the templates on each side render and execute the display. Currently, it is mainly velocity rendering, JS rendering, JSP rendering, mobile display, etc.
- Web layer : Mainly for forwarding access control, checking various basic parameters, or simply processing non-multiplexed services.
- Service layer : Relatively specific business logic service layer.
Manager layer : General business processing layer, it has the following characteristics:
1) For the layer encapsulated by the third-party platform, preprocess the returned result and convert the exception information.2) The sinking of general capabilities of the Service layer, such as caching solutions and general processing of middleware.
3) Interact with the DAO layer and reuse the combination of multiple DAOs.
- DAO layer : Data access layer, which interacts with the underlying MySQL, Oracle, Hbase, OB, etc.
- external interface or third-party platform : Including RPC open interfaces of other departments, basic platforms, and HTTP interfaces of other companies.
Here is also an example of a hierarchical structure for a single project project:
.
├── java
│ └── com
│ └── df
│ └── learn
│ └── exampleapi
│ ├── ExampleApiApplication.java
│ ├── config
│ │ └── ThreadPoolConfig.java
│ ├── constant
│ │ └── ThreadConstant.java
│ ├── controller
│ │ └── DemoController.java
│ ├── manager
│ │ └── UserManager.java
│ ├── mapper
│ │ └── HrUserMapper.java
│ ├── pojo
│ │ ├── bo
│ │ │ └── EmailInfoBO.java
│ │ ├── dto
│ │ │ └── UserInfoDTO.java
│ │ └── po
│ │ └── HrUserPO.java
│ ├── service
│ │ ├── DemoService.java
│ │ └── impl
│ │ └── DemoServiceImpl.java
│ └── util
│ └── EmailUtil.java
└── resources
├── application-dev.yml
├── application-prod.yml
├── application-uat.yml
├── application.yml
├── ehcache.xml
├── logback-spring.xml
├── mapper
│ └── HrUserMapper.xml
├── static
└── templates
Now to explain these engineering structures:
controller
: Front-end control layer Controller.service
: Data service interface layer Service.manager
: General business processing layer Manager.service.impl
: Data service interface implementation layer Service Implements.config
: Configuration class directory.consts
: Constant class directory.util
: Tool class directory.mapper(dao)
: dao layer directory, if it is a MyBatis project, you can use mapper.pojo
: Contains directories such as PO/BO/VO/DTO.
POJO layering
- POJO (Plain Ordinary Java Object): It is the collective name of DO/DTO/BO/VO. POJO refers to simple classes with only setter/getter/toString, including DO/DTO/BO/VO, etc., but it is forbidden to be named xxxPOJO.
- PO (Persistant Object): One-to-one correspondence with the database table structure. There is also the use of DO (Data Object) instead.
- DTO (Data Transfer Object): The data transfer object, the object that the Service or Manager transfers to the outside, that is, the object encapsulated by the Request or Response in the Controller.
- BO (Business Object): business object. It can be understood that in the process of Java development, some POJOs that have nothing to do with table structure abstracted may contain one or more DOs.
- VO (View Object): Display object, its function is to encapsulate all the data of a specified page (or component). VO is not common, because it is too similar to DTO, and it is basically replaced by DTO. For example: male/female is stored as 0/1 in the database, 0/1 is displayed in DTO, and male/female should be displayed in VO. But there is no need to tangle, personal preference is to use DTO directly.
5. Multi-environment configuration specification
The YAML configuration file in multiple environments, the specification is as follows:
- application.yml -- main configuration file
- application-dev.yml -- development environment configuration file
- application-uat.yml -- test environment configuration file
- application-prod.yml -- the official environment configuration file
An example configuration file is as follows:
spring:
profiles:
active: prod
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test
username: root
password: root
A project generally has many sets of environments, development environment, test environment, UAT environment, production environment, and the parameters of each environment are different, so we need to configure the parameters of each environment into the corresponding yml file, which can be passed in the main The current configuration file is enabled in the configuration file, for example:
spring:
profiles:
active: prod
This line is configured in the application.yml file, which means that the currently valid configuration file is application-prod.yml.
6. Exception Handling Specifications
Exception handling requirements at each layer
- DAO layer : There are many types of exceptions, which cannot be caught with fine-grained exceptions, use the catch(Exception e) method, and throw new DAOException(e), no need to print the log, because the log must be in the Manager/Service layer. It needs to be captured and printed to the log file. If the same server logs again, it will waste performance and storage.
- Service layer : When an exception occurs in the Service layer, the error log must be recorded to the disk, and parameter information should be included as much as possible, which is equivalent to protecting the crime scene.
- Manager layer : The Manager layer and the Service are deployed on the same machine, and the log method is the same as that of the DAO layer. If it is deployed separately, the same processing method as the Service is adopted.
- Web layer : The Web layer should never continue to throw exceptions, because it is already at the top level. If you realize that this exception will cause the page to fail to render properly, you should jump directly to the friendly error page and try to add friendly errors prompt information. The open interface layer should process exceptions into error codes and return error messages.
Global exception handling ideas
As mentioned above, the Service
, Manager
and Controller
layers require exception handling. These exceptions that need to be handled can often be divided into several categories, and different types of exceptions are dealt with in a unified manner. For example: exceptions that need to be fed back to the user (such as account/password errors), exceptions handled by the program itself (such as database lock conflicts, automatic retry of optimistic lock CAS), server exceptions that are nothing but resolved (such as database downtime, network fluctuations, etc.)... .
For such exceptions that can be classified and processed uniformly, it is recommended to write a global exception handling method to implement the implementation. The specific implementation method has the following three steps:
- Custom exception class : Use a unified exception, you can also customize the exception class, such as "exception that needs to be fed back to the user", you can customize the business exception class, and manually throw a prompt.
- throws an exception : Because of unified processing, it is necessary to standardize throwing exceptions.
- Global exception handling : For exception handling, you cannot always try catch at each method, you can use the idea of aspect-oriented programming to do global exception handling. Common global exception handling methods are:
@ControllerAdvice
,AOP
,filter and
interceptor, etc. However, note that their execution order is (
ServletContextListener > Filter > Interception > AOP > Specific Execution Method > AOP > @ControllerAdvice > Interception > Filter > ServletContextListener ).
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。