Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。本文主要介绍Spring Cloud的基本使用,文中使用到的软件版本:Spring Boot 2.2.5.RELEASE、Spring Cloud Hoxton.SR3、Java 1.8.0_191。
1、项目结构
使用maven来管理工程,工程里包含多个模块:注册中心(scdemo-eureka)、服务提供者(scdemo-server)、服务调用者(scdemo-client)、网关(scdemo-gateway),差不多下面的样子:
2、根工程(scdemo)
跟功能只有一个pom文件,用于定义Spring Boot、Spring Cloud及其他一些框架的版本信息。
scdemo/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>com.inspur</groupId> <artifactId>scdemo</artifactId> <version>1.0</version> <modules> <module>scdemo-eureka</module> <module>scdemo-srever</module> <module>scdemo-client</module> <module>scdemo-gateway</module> </modules> <packaging>pom</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath /> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
3、注册中心(scdemo-eureka)
3.1、scdemo/scdemo-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>scdemo</artifactId> <groupId>com.inspur</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>scdemo-eureka</artifactId> <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> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3.2、application.yml
spring:
application:
name: scdemo-eureka
server:
port: 9000
eureka:
instance:
prefer-ip-address: true
#hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:${server.port}/eureka
server:
enable-self-preservation: false
3.3、启动类
package com.inspur.scdemo.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }
3.4、控制台地址
启动后,控制台地址为:http://localhost:9000/
4、服务提供者(scdemo-server)
4.1、scdemo/scdemo-server/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>scdemo</artifactId> <groupId>com.inspur</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>scdemo-srever</artifactId> <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> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
4.2、application.yml
spring:
application:
name: scdemo-server
cloud:
loadbalancer:
ribbon:
enabled: false
server:
port: 9001
servlet:
context-path: /
eureka:
instance:
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:9000/eureka/
4.3、启动类
package com.inspur.scdemo.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); } }
4.4、编写Controller
package com.inspur.scdemo.server.controller; import com.inspur.scdemo.server.entity.CallResult; import com.inspur.scdemo.server.entity.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { private Logger logger = LoggerFactory.getLogger(UserController.class); @RequestMapping("/addUser") public CallResult<User> addUser(@RequestBody User user) { logger.info(user.toString()); //TODO: insert to db user.setId(1000L); user.setName("server-" + user.getName()); CallResult<User> result = new CallResult<>(); result.setResult(user); return result; } @RequestMapping("/getUser") public CallResult<User> getUser(long id) { logger.info(id + ""); //TODO: select from db User user = new User(); user.setId(id); user.setName("server-马云"); user.setAddress("杭州"); CallResult<User> result = new CallResult<User>(); result.setResult(user); return result; } }
5、服务调用者(scdemo-client)
5.1、scdemo/scdemo-client/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>scdemo</artifactId> <groupId>com.inspur</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>scdemo-client</artifactId> <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> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
5.2、application.yml
spring:
application:
name: scdemo-client
cloud:
loadbalancer:
ribbon:
enabled: false
server:
port: 9002
servlet:
context-path: /
eureka:
instance:
prefer-ip-address: true
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:9000/eureka
feign:
hystrix:
enabled: true
5.3、启动类
package com.inspur.scdemo.client; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class ClientApplication { public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); } }
5.4、编写Feign接口调用服务端
package com.inspur.scdemo.client.feign; import com.inspur.scdemo.client.entity.CallResult; import com.inspur.scdemo.client.entity.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "scdemo-server") public interface IUserFeign { @PostMapping("/user/addUser") CallResult<User> addUser(@RequestBody User user); @PostMapping("/user/getUser") CallResult<User> getUser(@RequestParam("id") long id); }
5.5、编写Controller
package com.inspur.scdemo.client.controller; import com.inspur.scdemo.client.entity.CallResult; import com.inspur.scdemo.client.entity.User; import com.inspur.scdemo.client.feign.IUserFeign; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { private Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired private IUserFeign userFeign; @RequestMapping("/addUser") public CallResult<User> addUser(String name, String address) { logger.info("name={},address={}", name, address); CallResult<User> result = new CallResult<>(); try { User user = new User(); user.setName(name); user.setAddress(address); CallResult<User> resultServer = userFeign.addUser(user); logger.info("server返回结果:{}" + resultServer); User user2 = resultServer.getResult(); user2.setName("client-" + user2.getName()); result.setResult(user2); } catch (Exception e) { result = new CallResult<User>(-1, "发生异常"); e.printStackTrace(); } return result; } @RequestMapping("/getUser") public CallResult<User> getUser(long id) { logger.info(id + ""); CallResult<User> result = null; try { result = userFeign.getUser(id); } catch (Exception e) { result = new CallResult<User>(-1, "发生异常"); e.printStackTrace(); } return result; } }
6、网关(scdemo-gateway)
6.1、scdemo/scdemo-gateway/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>scdemo</artifactId> <groupId>com.inspur</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>scdemo-gateway</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> </project>
6.2、application.yml
spring:
application:
name: scdemo-gateway
cloud:
loadbalancer:
ribbon:
enabled: false
gateway:
discovery:
locator:
enabled: false #是否开启服务注册和发现功能;将为每一个服务创建一个router,这个router把以服务名开头的请求路径转发到对应的服务上
lower-case-service-id: true #将请求路径上的服务名转为小写
routes:
- id: client
uri: lb://scdemo-client
predicates:
- Path=/scdemo-client/**
filters:
- StripPrefix=1 #路由时会去除/scdemo-client
server:
port: 9006
servlet:
context-path: /
eureka:
instance:
prefer-ip-address: true
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://localhost:9000/eureka/
6.3、启动类
package com.inspur.scdemo.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
7、测试
分别启动各个模块。
7.1、查看注册的服务
打开http://localhost:9000/,可以看到注册的服务:
7.2、访问服务调用者的Controller
打开http://localhost:9002/user/addUser?name=a&address=b
可以看到服务调用者的后台日志,成功调用了服务提供者:
页面也返回正确结果:
7.3、通过网关访问服务调用者的Controller
打开http://localhost:9006/scdemo-client/user/addUser?name=a&address=b,页面也返回正确结果: