Spring Boot实战(十二)分布式系统开发 12.3 Spring Cloud实战

12.3实战

实战部分主要由6个微服务组成:
config:配置服务器,本例为person-service和some-service提供外部配置。
discovery:Eureka Server为微服务提供注册
person:为UI模块提供保存person的REST服务
some:为UI模块返回一段字符串
UI:作为应用网关,提供外部访问的唯一入口。使用Feign消费person服务、Ribbon消费some服务,且都提供断路器功能
monitor:监控UI模块中的断路器。

12.3.1 项目构建
新建模块化的maven本项目ch12,基pom.xml文件的主要部分如下。

(1)使用标签来实现模块化:

    <modules>
        <module>config</module>
        <module>discovery</module>
        <module>ui</module>
        <module>person</module>
		<module>some</module>
        <module>monitor</module>
    </modules>

(2)使用spring-cloud-starter-parent替代 spring-boot-starter-parent,其具备spring-boot-starter-parent的同样功能并附加了Spring Cloud的依赖,此处使用Edgware.RELEASE:

    <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-parent</artifactId>
        <version>Edgware.RELEASE</version>
        <relativePath/>
    </parent>

(3)在些pom.xml文件里添加的dependency对所有的子模块都是有效的,即在子模块不用再额外添加这些依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

12.3.2 服务发现–Discovery(Eureka Server)

1.依赖

服务发现依赖于Eureka Server,所以本模块加上如下依赖即可:

        <dependency>
        	<groupId>org.springframework.cloud</groupId>
        	<artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
        	<groupId>org.springframework.cloud</groupId>
        	<artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>

2.关键代码

package com.wisely.discovery;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer //一个常规的Spring Boot项目,我们只需要使用@EnableEurekaServer注解开启对EurakaServer的支持即可。
public class DiscoveryApplication {

	  public static void main(String[] args) {
	        SpringApplication.run(DiscoveryApplication.class, args);
	    }

}

3.配置

在云计算环境下,习惯使用YAML配置,此处我们也受用YAML配置。
application.yml

server:
  port: 8761   #当前Eureka Server服务的端口号为8761

eureka:
  instance:
    hostname: localhost     #当前EurekaServer的hostname为localhost
  client:
    register-with-eureka: false           #当前服务不需要到Eureka Server上注册。
    fetch-registry: false
    

12.3.3 配置–Config(Config Server)

1.依赖

Spring Cloud为我们提供了作为配置服务的依赖spring-cloud-config-server,以及作为eureka客户端的依赖spring-cloud-starter-eureka:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

2.关键代码

package com.wisely.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableConfigServer //使用@EnableConfigServer开启配置服务器的支持
@EnableEurekaClient //使用@EnableEurekaClient开启作为Eureka Server的客户端支持。
public class ConfigApplication {
	
	 public static void main(String[] args) {
	        SpringApplication.run(ConfigApplication.class, args);
	    }

}

3.配置

bootstrap.yml

spring:
  application:
    name: config #在Erueka Server注册的服务名为config
  profiles:
    active: native #配置服务器使用本地配置(默认为git配置)
    
eureka:
  instance:
    non-secure-port: ${server.port:8888} #非SSL端口,若环境变量中server.port有值,则使用环境变量的值,没有则使用8080.
    metadata-map:
      instanceId: ${spring.application.name}:${random.value} #配置在Eureka Server的实例ID
  client:
    service-url:
      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ #Eureka客户端设置Eureka Server的地址


代码解释:
这里对bootstrap.yml做一下解释,Spring Cloud应用提供使用bootstrap.yml负责从外部资源加载配置属性。

application.yml

spring:
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/config 

server:
  port: 8888

配置期货应用所需的配置文件的位置位于类路径下的config目录下,如图
在这里插入图片描述
配置文件的规则为:应用名+profile.yml。

12.3.4 服务模块——Person服务

1.依赖

本模块需要做数据库操作,故添加spring-boot-starter-data-jpa依赖(在开发环境下使用hsqldb,在Dockers生产环境下使用PostgreSQL);本模块还需要使用Config Server的配置,故添加spring-cloud-config-client依赖。

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        	<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
		</dependency>
		<dependency>
			<groupId>postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>9.1-901-1.jdbc4</version>
		</dependency>
    </dependencies>

2.关键代码

本模块没有特别值得关注的代码,主要是实现数据库的一个保存操作,并将保存操作暴露给UI模块调用。

package com.wisely.person.controller;


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.wisely.person.dao.PersonRepository;
import com.wisely.person.domain.Person;

@RestController
public class PersonController {
    @Autowired
    PersonRepository personRepository;

    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public List<Person> savePerson(@RequestBody String  personName) {
    	Person p = new Person(personName);
    	personRepository.save(p);
    	List<Person> people = personRepository.findAll(new PageRequest(0, 10)).getContent();
        return people;
    }



}

3.配置

bootstrap.yml:

spring:
  application:
    name: person
  cloud:
    config:
      enabled: true
      discovery:
        enabled: true
        service-id: CONFIG #指定ConfigServer的服务名,将会通过Eureka Server发现Config Server
eureka:
  instance:
    non-secure-port: ${server.port:8082}
  client:
    service-url:
      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/

在开发环境下使用hsqldb:(Config Server下的person.yml):

spring:
  jpa:
    database: HSQL 

在Docker生产环境下使用PostgreSQL(Config Server下的person-docker.yml):

spring:
  jpa:
    database: POSTGRESQL
  datasource:
    platform: postgres
    url: jdbc:postgresql://postgres:5432/postgres
    username: postgres
    password: postgres
    driver-class-name: org.postgresql.Driver

application.yml

server:
  port: 8082
 

spring:
  jpa:
    hibernate:
      ddl-auto: update


12.3.5 服务模块——Some服务

1.依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
    </dependencies>

2.关键代码

package com.wisely.some;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class SomeApplication {
	 @Value("${my.message}") //此处通过@value注入的值来处于Config Server
	 private String message; 
	
	 @RequestMapping(value = "/getsome")
	 public String getsome(){
		 return message;
	 }
	public static void main(String[] args) {
		SpringApplication.run(SomeApplication.class, args);
	}

}

在开发环境下(Config Server下的some.yml)。

my:
  message: Message from Development

在Docker生产环境下(Config Server下的some-docker.yml):

my:
  message: Message from Production

3.配置

bootstrap.yml:

spring:
  application:
    name: some
  cloud:
    config:
      enabled: true
      discovery:
        enabled: true
        service-id: CONFIG
eureka:
  instance:
    non-secure-port: ${server.port:8083}
  client:
    service-url:
      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/

application.yml:

server:
  port: 8083

12.3.6 界面模块——UI(Ribbon,Feign)

1.依赖

本模块会使用ribbon、feign、zuul以及CircuitBreaker,所以需添加相关依赖。本模块是一个具有界面的模块,所以通过webjar加载了一些常用的脚本框架:

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
        <dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zuul</artifactId>
		</dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</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-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
      
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>angularjs</artifactId>
            <version>1.3.15</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>angular-ui-router</artifactId>
            <version>0.2.13</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
        </dependency>
    </dependencies>

2.关键代码

(1)入口:
package com.wisely.ui;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启feign客户端支持
@EnableCircuitBreaker //开启CircuitBreaker的支持
@EnableZuulProxy //开启网关代理的支持
public class UiApplication {
	public static void main(String[] args) {
        SpringApplication.run(UiApplication.class, args);
    }
	
	@Bean
	@LoadBalanced  //注册一个restTemplate,并开启负载均衡以支持Robbin
	public RestTemplate restTemplate(RestTemplateBuilder builder) {
	    return builder.build();
	}
}

(2)使用feign调用Person Service:
package com.wisely.ui.service;

import java.util.List;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.wisely.ui.domain.Person;

@FeignClient("person")
public interface PersonService {
	 @RequestMapping(method = RequestMethod.POST, value = "/save",
	            produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
	    @ResponseBody List<Person> save(@RequestBody String  name);
}

代码解释,我们只需通过简单的在接口中声明方法即可调用Person服务的REST服务。

(3)调用Person Service的断路器:
package com.wisely.ui.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.wisely.ui.domain.Person;

@Service
public class PersonHystrixService {

	@Autowired
	PersonService personService; 

	@HystrixCommand(fallbackMethod = "fallbackSave") //当本方法调用失败时,调用后备方法fallbackSave。
	public List<Person> save(String name) {
		return personService.save(name);
	}
	
	public List<Person> fallbackSave(String name){ 
		List<Person> list = new ArrayList<>();
		Person p = new Person(name+"没有保存成功,Person Service 故障");
		list.add(p);
		return list;
	}
}

(4)使用ribbon调用Some Service,并使用断路器:
package com.wisely.ui.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@Service
public class SomeHystrixService {

	@Autowired
	RestTemplate restTemplate; //注入即可直接使用Ribbon,Spring Boot为我们自动做的配置

	@HystrixCommand(fallbackMethod = "fallbackSome") //当本方法调用失败时调用后备方法
	public String getSome() {
		return restTemplate.getForObject("http://some/getsome", String.class);
	}
	
	public String fallbackSome(){ 
		return "some service模块故障";
	}
}

3.配置

bootstrap.yml:

spring:
  application:
    name: ui

eureka:
  instance:
    non-secure-port: ${server.port:80}
  client:
    service-url:
      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/

application.yml

server:
  port: 80

12.3.7 断路器监控——Monitor(DashBoard)

1.依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-turbine</artifactId>
        </dependency>
    </dependencies>

2.主要代码

package com.wisely.monitor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.turbine.EnableTurbine;

@SpringBootApplication
@EnableEurekaClient
@EnableHystrixDashboard
@EnableTurbine
public class MonitorApplication {

    public static void main(String[] args) {
        SpringApplication.run(MonitorApplication.class, args);
    }
}

3.配置

bootstrap.yml

spring:
  application:
    name: monitor

eureka:
  instance:
    nonSecurePort: ${server.port:8989}
  client:
    serviceUrl:
      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/

application.yml

server:
  port: 8989

12.3.8 运行

我们依次启动DiscoveryApplication、ConfigApplication,后面所有的微服务启动不分顺序,最后启动MonitorApplication。此时访问http://localhost:8761,查看Eureka Server,如图
在这里插入图片描述

1.访问UI服务

UI服务既是我们的页面,也是我们的网关代理。在实际生产环境中,服务器防火墙只需将此端口暴露给外网即可,访问http://localhost,如图
在这里插入图片描述

(1)调用Person Service,如图

在这里插入图片描述

(2)调用Some service,如图

在这里插入图片描述

3.断路器监控

访问 http://localhost:8989/hystrix.stream,如图
在这里插入图片描述
输入http://localhost/hystrix.stream,如图
在这里插入图片描述
监控界面如图
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值