一、SpringCloud概述
1.什么是微服务:
http://www.martinfowler.com/articles/microservices.html)
2.微服务具备的特征
A.每个微服务都可独立运行在自己的服务进程中;
B.一系列独立运行的微服务共同搭建起整个系统;
C.每个服务为独立的业务开发,一个微服务一般完成某个特定的功能,比如:订单管理,商品管理等;
D.微服务之间通过一些轻量的童鞋机制进行通信,例如:通过REST API或者RPC的方式进行调用。
3.优点
易于开发和维护;启动较快;局部修改容易部署;技术栈不受限;按需伸缩;DevOps
4.挑战
运维要求较高;分布式的复杂性;接口调用成本高;重复劳动
5.设计原则
单一职责原则,服务自治原则,轻量级通信原则,接口明确原则
二、创建服务注册中心
服务注册中心我需要使用组件上Spring Cloud Netflix的Eureka,eureka只用一个服务注册和发现模块。我们可以将自己定义的API接口注册到Spring Cloud Eureka上,Eureka服务服务的注册与发现。构成Eureka体系包括:服务注册中心、服务提供者、服务消费者。
上图描述了(图片来源于网络):
A.两天Eureka服务注册中构成的注册复制集群;
B.然后服务提供者想注册中心进行注册、续约、下线服务等;
C.服务消费者向Eureka注册中拉去服务列表并维护在本地;
D.然后服务消费者根据从Eureka服务注册中心获取的服务列表选取一个服务提供者进行消费服务。
1.创建一个web-app的maven工程。此处命名为:springcloud;
在该工程下创建module;快速创建一个名为eureka的springboot工程。
勾选Eureka Server。注意springboot版本,建议使用2.0以上版本
2.创建好之后,看下pom.xml是否导入了依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.在启动类中加入注解@EnableEurekaServer
package com.springcloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @EnableEurekaServer 启动一个服务注册中心提供给其他应用进行对话
* @EnadbleEuredaServe Import导入了EurekaMarkerConfiguration类,eurekaServerMarkerBean会往Spring容器中注入一个空类Marker;
* Marker类是一个开关标志,用了激活EurekaServerAutoConfiguration类。
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
4.将application.properties修改为application.yml,添加配置
server:
port: 8761
spring:
application:
name: eureka
eureka:
instance:
hostname: localhost
client:
register-with-eureka: true #false:即禁止自己注册自己
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #配置服务注册中心访问地址
访问:http://localhost:8761/
可以看到,此时注册中心注册了自己;一般我们都会禁止注册中心注册自己。修改application.yml中register-with-eureka: false即可
三、创建服务生产者
1.快速创建一个名为client的springboot工程
我这为了方便测试,加入了myql、mybatis和Web开发相关组件;pom.xml如下
<?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.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springcloud</groupId>
<artifactId>client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</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>
2.在启动类ClientApplication.java中加入注解@EnableEurekaClient
package com.springcloud.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @EnableEurekaClient 表明自己是一个生产者
*/
@SpringBootApplication
@EnableEurekaClient
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
3.application.yml配置
#配置服务注册中心地址
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: service-client
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/dny_website?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
server:
port: 8765
mybatis:
mapper-locations: classpath:mapping/*Mapper.xml
type-aliases-package: com.springcloud.client.entity
logging:
level:
com:
springcloud:
client:
Dao: debug
项目结构(springboot整合mybatis这里就不细说了,有兴趣的可以看下这篇博客:)
控制层代码:
package com.springcloud.client.Controller;
import com.springcloud.client.entity.Admin;
import com.springcloud.client.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin")
public class AdminController {
@Autowired
private AdminService adminService;
@RequestMapping("/list")
public List<Admin> home(Integer permissions){
return adminService.adminList(permissions);
}
}
4.启动测试
启动服务提供者项目后,查看注册中心
使用postman进行测试:
四、创建服务消费者
方式一:ribbon+RestTemplate
创建一个名为ribbon的springboot项目。
<?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.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springcloud</groupId>
<artifactId>ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ribbon</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</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.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</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>
2.application.yml配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8762
spring:
application:
name: service-ribbon
3.启动类加入注解@EnableDiscoveryClient
package com.springcloud.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
/**
* 加入restTemplate以消费相关的服务。
* @return
*/
@Bean
@LoadBalanced
RestTemplate restTemplate()
{
return new RestTemplate();
}
}
4.创建Service和Contoller
package com.springcloud.ribbon.service;
import com.springcloud.customer.entity.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.List;
@Service
public class RibbonService {
@Autowired
private RestTemplate restTemplate;
public String StringServcie(){
return restTemplate.getForObject("http://SERVICE-CLIENT/admin/string",String.class);
}
public List<Admin> ListService(Integer permissions){
/**
* 方法getForObject(url,?.class)中的url必须使用服务提供者的项目名称“CLIENT”,不能使用IP地址
* RestTemplate接收List集合数据时,必须用数组接收
*/
Admin[] admin=restTemplate.getForObject("http://SERVICE-CLIENT/admin/list?permissions="+permissions,Admin[].class);
for(Admin a:admin){
System.out.println(a.getAdmin_name());
}
List<Admin> list= Arrays.asList(admin);
return list;
}
}
package com.springcloud.ribbon.controller;
import com.springcloud.customer.entity.Admin;
import com.springcloud.customer.service.RibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/ribbon")
public class RibbonController {
@Autowired
private RibbonService testService;
@RequestMapping("/string")
public String findString(){
return testService.StringServcie();
}
@RequestMapping("/list")
public List<Admin> AdminList(Integer permissions){
return testService.ListService(permissions);
}
}
测试:
方式二:Feign
创建项目,导入依赖;pom.xml:
<?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.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springcloud</groupId>
<artifactId>customer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>customer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</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-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</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>
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8764
spring:
application:
name: service-feign
#feign的配置,连接超时及读取超时配置
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
主类CustomerApplication:
package com.springcloud.customer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @EnableDiscoveryClient 声明自己是一个服务消费者
* @EnableFeignClients 启用feign客户端
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class CustomerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerApplication.class, args);
}
}
创建Service和Controller:
package com.springcloud.customer.service;
import com.springcloud.customer.entity.Admin;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Spring Cloud集成了Ribbon和Eureka,
* 可在使用Feign时提供负载均衡的http客户端。
*/
@FeignClient(value = "service-client")
public interface FeignService {
@RequestMapping("/admin/string")
public String StringService();
@PostMapping("/admin/list")
public List<Admin> FeignList(@RequestParam("permissions")Integer permissions);
}
package com.springcloud.customer.controller;
import com.springcloud.customer.entity.Admin;
import com.springcloud.customer.service.FeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/feign")
public class FeignController {
@Autowired
private FeignService feignService;
@RequestMapping("/string")
public String FeignString(){
return feignService.StringService();
}
@RequestMapping("/list")
public List<Admin> FeignList(Integer permissions){
return feignService.FeignList(permissions);
}
}
测试:
SpringCloud搭建(下)------断路器(Netflix Hystrix)+网关(Netflix Zuul)+配置中心(Spring Cloud Config)