创建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
通过网关路由,在浏览器网址中访问网关项目的域名+端口号+路由规则,即可访问到不同域名+端口号下的各个微服务了。