创建maven聚合项目
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cloud-test</groupId>
<artifactId>cloud-test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>父工程</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
<mybatis.starter.version>1.3.2</mybatis.starter.version>
<mapper.starter.version>2.0.2</mapper.starter.version>
<druid.starter.version>1.1.9</druid.starter.version>
<mysql.version>5.1.32</mysql.version>
<pageHelper.starter.version>1.2.3</pageHelper.starter.version>
<leyou.latest.version>1.0.0-SNAPSHOT</leyou.latest.version>
<fastDFS.client.version>1.26.1-RELEASE</fastDFS.client.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mybatis启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.starter.version}</version>
</dependency>
<!-- 通用Mapper启动器 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.starter.version}</version>
</dependency>
<!-- 分页助手启动器 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pageHelper.starter.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--FastDFS客户端-->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>${fastDFS.client.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建Eureka服务注册模块
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-test</artifactId>
<groupId>cloud-test</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>eureka注册中心</name>
<artifactId>eureka-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
application.yml配置
server:
port: 8761
eureka:
instance:
hostname: localhost # 设置当前实例的主机名称
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动类配置
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class);
}
}
效果测试
成功但是还没有实例注册到eureka
创建生产者微服务
pom.xml配置文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
application.yml配置文件
server:
port: 1000
spring:
application:
name: provider-1000
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
启动类配置
@SpringBootApplication
@EnableDiscoveryClient
public class Provider1000 {
public static void main(String[] args) {
SpringApplication.run(Provider1000.class);
}
}
测试效果
生产者微服务成功注册进了Eureka服务中
Ribbon 负载均衡
创建消费者微服务
pom.xml配置文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
application.yml配置文件
server:
port: 2000
spring:
application:
name: consumer-ribbon-2000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
启动类配置
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class);
}
@Bean
@LoadBalanced /*添加负载均衡,默认会轮询调用提供者*/
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
消费者微服务 Controller 层
@RestController
public class ConsumerController {
@Resource
RestTemplate restTemplate;
@RequestMapping("/helloRibbon")
public Map helloRibbon() {
return restTemplate.getForObject("http://PROVIDER/hello", Map.class);
}
}
两个生产者微服务application.yml配置文件
为了测试负载均衡将生产者的服务名改成相同的。
spring:
application:
name: provider
效果如下:
两个生产者微服务的 Controller 层
@RestController
public class ProviderController {
@RequestMapping("/hello")
public Map<String, Object> hello() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "provider-1001");
return map;
}
}
@RestController
public class ProviderController {
@RequestMapping("/hello")
public Map<String, Object> hello() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "provider-1002");
return map;
}
}
测试效果
默认以轮询的方式访问生产者。
Feign 负载均衡
创建消费者微服务
pom.xml配置文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
</dependencies>
application.yml配置文件
server:
port: 2000
spring:
application:
name: consumer-ribbon-2000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
启动类配置
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class);
}
}
Controller
@RestController
public class ConsumerController {
@Resource
IService iService;
@GetMapping("/helloFeign")
public Map helloFeign() {
return iService.helloFeign();
}
}
接口
@FeignClient(value = "PROVIDER")/**通过value绑定微服务的名字来指定调用哪个服务*/
public interface IService {
@GetMapping("/hello")/**调用PROVIDER微服务的@GetMapping("/toProvider/hello")*/
public Map<String,Object> hello();
}
测试效果
和Ribbon 一样以轮询的方式实现了负载均衡。
Hystrix 熔断器
Netflix 熔断器是安装在服务消费者上的。所以我们需要做的就是在服务消费者上开启熔断器并配置。
Ribbon + Hystrix
pom.xml配置文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
application.yml配置文件
server:
port: 2000
spring:
application:
name: consumer-ribbon-2000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class);
}
控制层
//断路器配置,当无法调用如下方法时,就会调用自定义的errorMethod方法
@HystrixCommand(fallbackMethod = "errorMethod")
@RequestMapping("/toRibbonHystrix/hello")
public Map helloRibbonHystrix() {
// 故意写错访问路径
return restTemplate.getForObject("http://PROVIDER1/hello", Map.class);
}
public Map<String, Object> errorMethod() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("ribon", "ribon出错啦");
return map;
}
测试效果
Feign + Hystrix
pom.xml配置文件
Feign中已经引入了Hystrix 所以不需要依赖了。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
</dependencies>
application.yml配置文件
server:
port: 2000
spring:
application:
name: consumer-ribbon-2000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
feign:
hystrix:
enabled: true # 开启hystrix熔断器
控制层
@Resource
IServiceHystrix iServiceHystrix;
@GetMapping("/toFeignHystrix/hello")
public Map helloFeignHystrix() {
return iServiceHystrix.helloFeignHystrix();
}
接口
/**故意写错访问路径*/
@FeignClient(value = "PROVIDER1",fallback = IServiceHystrixImpl.class)
public interface IServiceHystrix {
@GetMapping("/hello")/**调用PROVIDER微服务的@GetMapping("/toProvider/hello")*/
public Map<String,Object> helloFeignHystrix();
}
实现类
@Service
public class IServiceHystrixImpl implements IServiceHystrix {
@Override
public Map<String, Object> helloFeignHystrix() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("feign", "feign出错啦");
return map;
}
}
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceFeignApplication .class);
}
}
测试效果
zuul路由网关配置
pom.xml配置文件
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
application.yml配置文件
server:
port: 6001
#服务的名称
spring:
application:
name: zuul-gateway
#指定注册中心地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
启动类
@EnableZuulProxy //开启网关路由
@EnableDiscoveryClient //Eureka客户端
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
首先在消费者微服务(端口号2000)中添加一个接口:
@GetMapping("/login")
public String login(){
return "hello zuul";
}
启动网关微服务(端口号6001)
访问 http://localhost:6001/consumer-ribbon-2000/login
注意: 默认路由规则 = 域名 + 端口 + 对应服务名(spring.application.name) + 接口地址
访问成功,证明网关微服务已启动成功。
自定义路由规则
#自定义路由映射
zuul:
routes:
my-route: # 标识 代表一组 路由名称 随便起一个就好了 没有任何意义,如果没有配置 和service-id是一样的
service-id: consumer-ribbon-2000 # 微服务的名字 要被路由的微服务
path: /zuuls/** # url地址
访问自定义路由规则路径:http://localhost:6001/zuuls/login
通过网关路由,在浏览器网址中访问网关项目的域名+端口号+路由规则,即可访问到不同域名+端口号下的各个微服务了。