在上一篇博文中,Zuul将请求转发给了一个Web项目进行处理,如果处理的请求不是一个Web项目,而是整个微服务集群,那么Zuul将成为整个集群的网关。在加入Zuul前,Spring Cloud集群的结构如下图所示
为微服务集群加入Zuul的网关后,结构如下图所示
接下来我们就来实现在Spring Cloud中加入Zuul网关。
1.搭建集群
我们本例要实现一个书本销售的业务,在销售模块中需要调用书本模块的服务来查找书本。建立一下的项目
》 eurekaserver: Eureka服务器,应用端口为8761。
》 bookservice: 书本模块,属于服务的提供者,提供/book/{bookId}的服务,用于查找图书,最后返回的是JSON字符串,应用的端口是9000。
》saleservice: 销售模块,属于服务调用者,在该服务中会使用Feign框架来调用bookservice发布的查找图书的服务,其自身也会对外发布/salebook/{bookId}的销售服务。
1.1 eureka服务器
创建名为eurekaserver的maven项目,并编写代码实现相应的功能。项目的目录结构如下
在pom.xml文件中引入对应的依赖
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.triheart</groupId> <artifactId>eurekaserver</artifactId> <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies> </project>
在application.yml配置文件中配置应用端口以及eureka客户端以及服务端的相关属性
application.yml
server:
port: 8761
eureka:
client:
registerWithEureka: false
fetchRegistry: false
server:
enable-self-preservation: false
编写启动类,加入@EnableEurekaServer注解以及@SpringBootApplication注解
ServerApp.java
package com.triheart.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @author 阿遠 * Date: 2018/9/3 * Time: 10:25 */ @SpringBootApplication @EnableEurekaServer public class ServerApp { public static void main(String[] args){ SpringApplication.run(ServerApp.class, args); } }
Eureka服务器项目搭建完毕。
1.2 服务提供者
新建一个名为bookservice的maven项目,并编写代码实现相应的功能,项目的目录结构如下
在pom.xml中引入相关的依赖,代码请但如下
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.triheart</groupId> <artifactId>bookservice</artifactId> <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies> </project>
在application.yml中配置应用名称以及Eureka的客户端实例的名称和该实例所注册的服务器的地址
application.yml
spring:
application:
name: bookservice
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://localhost:8761/eureka/
编写应用启动类,加入@EnableEurekaClient注解以及@SpringBootApplication注解
BookService.java
package com.triheart.bookservice; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * @author 阿遠 * Date: 2018/9/3 * Time: 10:33 */ @SpringBootApplication @EnableEurekaClient public class BookServiceApp { public static void main(String[] args){ new SpringApplicationBuilder(BookServiceApp.class).properties( "server.port=9000").run(args); } }
编写Controller类,发布Web服务,代码清单如下
Book.java
package com.triheart.bookservice.web; /** * @author 阿遠 * Date: 2018/9/3 * Time: 10:37 */ public class Book { private Integer id; private String name; private String author; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
BookController.java
package com.triheart.bookservice.web; import org.springframework.http.MediaType; 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; /** * @author 阿遠 * Date: 2018/9/3 * Time: 10:38 */ @RestController public class BookController { @RequestMapping(value = "/book/{bookId}", method = RequestMethod.GET,produces = MediaType.APPLICATION_JSON_VALUE) public Book findBook(@PathVariable("bookId") Integer bookId) { Book book = new Book(); book.setId(bookId); book.setName("Spring Cloud"); book.setAuthor("ayuan"); return book; } }
bookservice服务提供者项目搭建完毕。
1.3 服务调用者
新建一个名为saleservice的maven项目,编写代码实现相应的功能,目录结构如下
在pom.xml文件中引入相应的依赖
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.triheart</groupId> <artifactId>salesservice</artifactId> <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> </dependencies> </project>
编写配置文件application.yml,配置应用的启动端口、应用的名称以及注册到eureka对应的名称和注册的eureka服务器的地址
server:
port: 9100
spring:
application:
name: saleservice
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
编写应用启动类,加入@EnableEurekaClient注解以及@SpringBootApplication注解,由于该模块需要用到Feign客户端框架来调用bookservice发布的服务,故需要在启动类中加入@EnableFeignClients的注解
SaleServiceApp.java
package com.triheart.salesservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; /** * @author 阿遠 * Date: 2018/9/3 * Time: 12:43 */ @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class SalesServiceApp { public static void main(String[] args){ SpringApplication.run(SalesServiceApp.class, args); } }
编写Feign框架对应的BookService接口,以调用bookservice项目发布的服务,代码清单如下
Book.java
package com.triheart.salesservice.feign; /** * @author 阿遠 * Date: 2018/9/3 * Time: 12:48 */ public class Book { private Integer id; private String name; private String author; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
BookService.java
package com.triheart.salesservice.feign; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * @author 阿遠 * Date: 2018/9/3 * Time: 12:49 */ @FeignClient("bookservice") public interface BookService { /** * 调用书本服务接口,获取一个Book的实例 */ @RequestMapping(value = "/book/{bookId}", method = RequestMethod.GET) Book getBook(@PathVariable("bookId") Integer bookId); }
编写SaleController控制器,发布图书销售的Web服务
SaleController.java
package com.triheart.salesservice.web; import com.triheart.salesservice.feign.Book; import com.triheart.salesservice.feign.BookService; import org.springframework.beans.factory.annotation.Autowired; 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; /** * @author 阿遠 * Date: 2018/9/3 * Time: 12:47 */ @RestController public class SaleController { @Autowired private BookService bookService; /** * 进行图书销售 */ @RequestMapping(value = "/salebook/{bookId}", method = RequestMethod.GET) public String saleBook(@PathVariable Integer bookId) { // 利用book服务查找相应的book Book book = bookService.getBook(bookId); // 控制台输出,模拟图书的销售 System.out.println("要销售的图书为id:"+ book.getId()+", 图书的名称为:"+book.getName()); return "success"; } }
saleservice服务调用项目搭建完毕。至此,我们已经将Eureka微服务集群搭建完成。接下来我们将搭建Zuul网关项目来实现Zuul在微服务集群中的使用。
2.路由到集群服务
新建一个名为zuulgetaway的maven项目,编写代码实现相应的功能,项目的目录结构如下
编写pom.xml文件,引入相关的依赖
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.triheart</groupId> <artifactId>zuulgateway</artifactId> <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> </dependencies> </project>
编写配置文件application.yml
application.yml
spring:
application:
name: zuulgateway
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
sale:
path: /sale/**
serviceId: saleservice
在配置文件中,我们配置了应用的名称,由于网关项目需要加入到集群中,我们需要在配置文件中进行配置让其注册到Eureka服务器中,最后我们配置了Zuul,在配置Zuul时声明了所有的/sale/**的请求都会被转发到Id为saleservice的服务进行处理,一般情况下,配置了serviceId后,在处理请求的routing阶段,将会使用一个名称为RibbonRoutingFilter的过滤器,该过滤器会调用Ribbon的API来思想负载均衡。
编写应用启动类
ZuulGatewayApp.java
package com.triheart.zuulgateway; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * @author 阿遠 * Date: 2018/9/3 * Time: 16:36 */ @SpringBootApplication @EnableZuulProxy public class ZuulGatewayApp { public static void main(String[] args){ new SpringApplicationBuilder(ZuulGatewayApp.class).properties("server.port=8080").run(args); } }
在应用的启动类中,我们需要添加@EnableZuulProxy注解来使用Zuul。
3.启动项目
我们按照以下顺序启动集群
》 启动eurekaserver
》启动bookservice
》启动saleservice
》启动zuulgeteway
在浏览器中访问http://localhost:8080/sale/salebook/1,可以看到在浏览器中返回如下
销售模块的控制台返回如下
根据输出可知,销售模块和图书模块均被调用。