微服务的核心思想:
服务组件化:小而美,独立又关联,同时,又不是不可替代。
去中心化:扁平化服务,没有单点瓶颈。
容错设计:状态监控,故障处理。
SpringCloud实现微服务的核心设计思想,而SpringCloud基于Springboot实现。
以前,曾基于SpringBoot1.*实现了一个微服务架构,后来,SpringBoot2正式发布后,我也更新了技术框架,只是一直没有发布到github。
旧版请参考:基于SpringBoot1.*的实现,请参考https://github.com/banat020/sc-frame
新版——
基于Springboot2实现的微服务,架构如下:
概述:服务注册到注册中心,客户端请求服务时,必须经过gateway(服务网关),由服务网关代理发起服务请求。服务网关发起请求时,先从注册中心获取服务列表,再请求服务。同时设计Tracker(日志收集服务)和Moniter(状态监控服务)对整个服务进行监控。
基于Springboot2技术,整合了Eureka实现的注册中心、zuul微服务网关、zipkin收集链路调用日志、ES保存链路日志,服务调用、ribbon与Feign负载均衡、hystrix、swagger生成API文档、Admin监控等。
Github上源码:https://github.com/banat020/sc2-frame
一、注册中心:
参考sc2-register工程源码。
注册中心注册相关系统的服务,使通过注册中心,实现微服务的无中心化。
Eureka技术实现注册中心:
1.1)引入相关资源包:
<?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.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.banling</groupId>
<artifactId>sc2-register</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sc2-register</name>
<description>springcloud framework v2, Eureka is as register center</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR4</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2)SpringBoot启动入口:
package com.banling.sc2.register;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class Sc2RegisterApplication {
public static void main(String[] args) {
SpringApplication.run(Sc2RegisterApplication.class, args);
}
}
只加了一行有效代码“@EnableEurekaServer”即可。
1.3)配置:
server.port=9100
spring.application.name=sc2-register
## eureka
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.server.enable-self-preservation=false
eureka.server.eviction-interval-timer-in-ms=30000
eureka.instance.hostname=m0
## 先在本机hosts中设置别名,否则单机没法启用多个注册中心
#127.0.0.1 localhost
#127.0.0.1 m0
#127.0.0.1 m1
#127.0.0.1 m2
##
eureka.client.serviceUrl.defaultZone=http://m1:9101/eureka/
如果想在单机环境中启用多个注册中心(单机集群),必须在hosts中为当前当机设置别名。在单机Docker环境中也一样。如,我本机(Windows)的设置如下,共设置了4个主机名:
127.0.0.1 localhost
127.0.0.1 m0
127.0.0.1 m1
127.0.0.1 m2
单机集群做法如下:
A注册中心:端口是9100,注册到另一个注册中心(B注册中心) http://m1:9101/eureka/
B注册中心:端口是9101,注册到A注册中心http://m0:9100/eureka/
1.4)测试
分别启动A注册中心与B注册中心即可。
效果如图:
二、设计并实现服务:
参考sc2-service工程源码。
注册到注册中心,同时,发布http服务。
2.1)设计http服务,并通过swagger发布API文档:
package com.banling.sc2.service.web;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.banling.sc2.module.User;
import org.slf4j.Logger;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping(value = "/hello")
public class HelloController {
private final Logger logger=LoggerFactory.getLogger(getClass());
@ApiOperation(value="获取消息", notes="根据传入参数获取响应消息")
@ApiImplicitParam(name = "msg", value = "入参", required = true, dataType = "String",paramType =