1.File->new Projectt->Spring Initializr->勾选web,lombok(需要安装插件使用File->Settings->Plugins->Browse repositories)
2.编写controller
@RestController
public class HelloWorld {
@RequestMapping("/")
String helloWorld(){
return "Hello World";
}
}
3.启动
@SpringBootApplication
public class YyApplication {
public static void main(String[] args) {
SpringApplication.run(YyApplication.class, args);
}
}
4.启动成功
2017-09-13 13:49:14.233 INFO 2380 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-09-13 13:49:14.236 INFO 2380 --- [ main] com.wacmx.yy.YyApplication : Started YyApplication in 2.471 seconds (JVM running for 4.397)
5.Eureka Service(服务注册中心)
右键工程->NEW->Module->spring initialir->勾选eureka server
启动服务注册中心@EnableEurekaServer
@EnableEurekaServer
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
application.yml(两个false表示是eureka server)
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
点击启动类访问 http://localhost:8761/
此刻Application显示 No instances available
6.Eureka Client(服务提供者)
当client向server注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka server 从每个client实例接收心跳消息。 如果心跳超时,则通常将该实例从注册server中删除。
创建过程与server类似,勾选eureka discovery进入
启动类添加注解
@EnableEurekaClient
@SpringBootApplication
@RestController
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
@Value("${server.port}")
String port;
@RequestMapping("/hi")
public String home(String name){
return "hi"+name+"i'm from port:"+port;
}
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8762
spring:
application:
name: service-hi
启动后访问 http://localhost:8761/
此时Apllicaion则为 SERVICE-HI,端口为8762
访问http://localhost:8762/hi?name=wacmx
显示:
hiwacmxi'm from port:8762
7.ribbon+restTemplate(服务消费者Ⅰ)
简介:
在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于httprestful的。Spring cloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。
ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。Feign默认集成了ribbon。
项目前准备:
启动eureka-server 工程;启动service-hi工程,它的端口为8762;将service-hi的配置文件的端口改为8763,并启动,这时你会发现:service-hi在eureka-server注册了2个实例,这就相当于一个小的集群。如下图:
创建新的boot项目,勾选Web,Eureka Discovery,Ribbon,项目命名service-ribbon
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8764
spring:
application:
name: service-ribbon
启动类:
@SpringBootApplication
@EnableDiscoveryClient//向服务中心注册
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
@Bean//向程序的ioc注入一个bean:restTemplate
@LoadBalanced//注解表明这个restRemplate开启负载均衡的功能
RestTemplate restTemplate() {
return new RestTemplate();
}
}
测试类
HelloService:
@Service
public class HelloService {
@Autowired
private RestTemplate restTemplate;
public String hiService(String name){
/**直接用的程序名替代了具体的url地址
在ribbon中它会根据服务名来选择具体的服务实例
根据服务实例在请求的时候会用具体的url替换掉服务名*/
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
}
HelloController:
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@RequestMapping("/hi")
publicString hi(String name){
return helloService.hiService(name);
}
}
访问http://localhost:8764/hi?name=wacmx,交替显示
(idea启动类配置的EditConfiguration中有一个Single instance only在service-hi那个服务中取消选中;
否则你启动第二遍的时候,系统会自动把之前的服务给关闭了)
hiwacmxi'm from port:8762
hiwacmxi'm from port:8763
说明当我们通过调用restTemplate.getForObject(“http://SERVICE-HI/hi?name=“+name,String.class)方法时,已经做了负载均衡,访问了不同的端口的服务实例。
此时的架构图:
一个服务注册中心,eureka server,端口为8761
service-hi工程跑了两个实例,端口分别为8762,8763,分别向服务注册中心注册
sercvice-ribbon端口为8764,向服务注册中心注册
当sercvice-ribbon通过restTemplate调用service-hi的hi接口时,因为用ribbon进行了负载均衡,会轮流的调用service-hi:8762和8763两个端口的hi接口;
8.Feign(服务消费者Ⅱ)
简介:
Feign 采用的是基于接口的注解
Feign 整合了ribbon
创建项目:
勾选Web,Eureka Discovery,Feign,命名为service-feign
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8765
spring:
application:
name: service-feign
启动类:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}
Feign接口,通过@FeignClient("服务名")指定具体服务,和具体的接口:
@FeignClient(value = "service-hi")
public interface SchedualServiceHi {
@GetMapping( "/hi")
String sayHiFromClientOne(@RequestParam(value="name") String name);
}
HiController 暴露/hi接口,供SchedualServiceHi消费服务:
@RestController
public class HiController {
@Autowired
private SchedualServiceHi schedualServiceHi;
@GetMapping("/hi")
public String sayHi(@RequestParam String name){
return schedualServiceHi.sayHiFromClientOne(name);
}
}
启动后,多次访问http://localhost:8765/hi?name=wacmx,接替显示
hiwacmx,i'm from port:8762
hiwacmx,i'm from port:8763
9.Hystrix(断路器)
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC),在Spring Cloud可以用RestTemplate+Ribbon和Feign来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。为了解决这个问题,业界提出了断路器模型。
Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。在微服务架构中,一个请求需要调用多个服务是非常常见的
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric是5秒20次) 断路器将会被打开。
断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值。
启动eureka-service(port:8761),eureka-hi(port:8762)
①基于service-ribbon工程
pom.xml添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
启动类添加@EnableHystrix:
@SpringBootApplication
@EnableDiscoveryClient//向服务中心注册
@EnableHystrix//开启断路器
public class RibbonApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
@Bean//向程序的ioc注入一个bean:restTemplate
@LoadBalanced//注解表明这个restRemplate开启负载均衡的功能
RestTemplaterestTemplate() {
return new RestTemplate();
}
}
改造HelloService类:
@Service
public class HelloService {
@Autowired
private RestTemplate restTemplate;
/**该注解对该方法创建了熔断器的功能,并指定了fallbackMethod熔断方法*/
@HystrixCommand(fallbackMethod = "hiError")
public String hiService(String name){
/**直接用的程序名替代了具体的url地址
在ribbon中它会根据服务名来选择具体的服务实例
根据服务实例在请求的时候会用具体的url替换掉服务名*/
returnrestTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
//熔断方法
public String hiError(String name){
return "hi\t"+name+",sorry,error";
}
}
启动:service-ribbon 工程,当我们访问http://localhost:8764/hi?name=wacmx
hiwacmxi'm from port:8762
关闭service-hi工程后,执行熔断方法:
hi wacmx,sorry,error
这就说明当 service-hi 工程不可用的时候,service-ribbon调用 service-hi的API接口时,会执行快速失败,直接返回一组字符串,而不是等待响应超时,这很好的控制了容器的线程阻塞。
②基于service-feign工程:
feign自带断路器,application.yml添加如下配置:
feign:
hystrix:
enabled: true
SchedualServiceHiHystrix熔断类,继承SchedualService接口:
@Component//注入到IOC容器
public class SchedualServiceHiHystriximplements SchedualServiceHi{
@Override
public String sayHiFromClientOne(String name) {
return "sorry\t"+name;
}
}
SchedualService @FeignClient接口中添加fallback,指定熔断类
@FeignClient(value = "service-hi",fallback= SchedualServiceHiHystrix.class)
public interface SchedualServiceHi {
@GetMapping( "/hi")
String sayHiFromClientOne(@RequestParam(value="name") Stringname);
}
启动服务:
此时service-hi未开启,访问http://localhost:8765/hi?name=wacmx
sorry wacmx
开启service-hi服务:
hiwacmxi'm from port:8762
③Hystrix Dashboard(断路器,hystrix仪表盘,ribbon与feign相同处理)
pom.xml添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
启动类添加@EnableHystrixDashboard
访问 http://localhost:8765/hystrix (以feign为例),会有熊出没
点击Monitor Stream 会进入对应的监控页面.
10.zuul(路由网关)
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简单的微服务系统:
使用场景:
在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服。,服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理(下一篇文章讲述),配置服务的配置文件放在git仓库,方便开发人员随时改配置。
Zuul简介:
Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
创建项目:
勾选Web,Eureka Discovery,Zuul,项目命名为service-zuul
启动类:
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ZuulApplication {
publicstatic void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
application.yml:
首先指定服务注册中心的地址为http://localhost:8761/eureka/,服务的端口为8769,服务名为service-zuul;以/api-a/ 开头的请求都转发给service-ribbon服务;以/api-b/开头的请求都转发给service-feign服务;
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8769
spring:
application:
name: service-zuul
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-ribbon
api-b:
path: /api-b/**
serviceId: service-feign
依次运行这五个工程;打开浏览器访问:http://localhost:8769/api-a/hi?name=wacmx ;浏览器显示:
hi wacmx,i am from port:8762
打开浏览器访问:http://localhost:8769/api-b/hi?name=wacmx ;浏览器显示:
hi wacmx,i am from port:8762
这说明zuul起到了路由的作用
zuul的服务过滤作用,可以用作安全验证:
@Componet
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
/**
*返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型
* pre:路由之前
* routing:路由之时
* post: 路由之后
* error:发送错误调用
* filterOrder:过滤的顺序
* shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
* run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
*/
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
publicObject run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s>>>%s",request.getMethod(),request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if (accessToken == null){
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
log.info("ok");
return null;
}
}
启动后,访问http://localhost:8769/api-a/hi?name=wacmx
token is empty
访问http://localhost:8769/api-a/hi?name=wacmx&token=520
hiwacmxi'm from port:8762
以上,zuul完成了路由代理,与安全过滤的功能.
11.spring cloud config(分布式配置中心)
简介:
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。
①创建config-server项目:
勾选Config Server,Eureka Server,命名为config-server
启动类添加注解@EnableConfigServer:
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigApplication {
publicstatic void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
application.properties
spring.application.name=config-server
server.port=8888
#git仓库地址
spring.cloud.config.server.git.uri=https://github.com/forezp/SpringcloudConfig/
#仓库路径
spring.cloud.config.server.git.searchPaths=respo
#仓库的分支
spring.cloud.config.label=master
#git仓库的用户名
#spring.cloud.config.server.git.username=yourusername
#git仓库的用户密码
#spring.cloud.config.server.git.password=yourpassword
远程仓库https://github.com/forezp/SpringcloudConfig/ 中有个文件config-client-dev.properties文件中有一个属性:
foo = foo version 3
启动程序:访问http://localhost:8888/foo/dev
{
name: "foo",
profiles: [
"dev"
],
label: null,
version:"a68876a6211369bae723348d5f8c3defe4a55e04",
state: null,
propertySources: [ ]
}
证明配置服务中心可以从远程程序获取配置信息。
http请求地址和资源文件映射如下:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
②创建config-client项目:
勾选Web,Config Client,命名为config-client
application.properties:
spring.application.name=config-client
#远程仓库的分支
spring.cloud.config.label=master
#dev开发环境配置文件 test测试环境 pro正式环境
spring.cloud.config.profile=dev
#配置服务中心的网址
spring.cloud.config.uri=http://localhost:8888/
server.port=8881
启动类:
@SpringBootApplication
@RestController
@EnableEurekaClient
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
@Value("${foo}")
String foo;
@RequestMapping("/hi")
public String sayhi() {
return foo;
}
}
启动后访问:http://localhost:8881/hi
foo version 2
这就说明,config-client从config-server获取了foo的属性,而config-server是从git仓库读取的12. spring cloud config高可用的配置服务中心
当服务实例很多时,都从配置中心读取文件,这时可以考虑将配置中心做成一个微服务,将其集群化,从而达到高可用
①有一个Eureka-server(port:8889)
②改造Config-server
application.properties指定服务注册地址:
spring.application.name=config-server
server.port=8888
#git仓库地址
spring.cloud.config.server.git.uri=https://github.com/forezp/SpringcloudConfig/
#仓库路径
spring.cloud.config.server.git.searchPaths=respo
#仓库的分支
spring.cloud.config.label=master
#git仓库的用户名
#spring.cloud.config.server.git.username=yourusername
#git仓库的用户密码
#spring.cloud.config.server.git.password=yourpassword
#指定服务注册地址
eureka.client.serviceUrl.defaultZone=http://localhost:8889/eureka/
启动类添加@EnableEurekaServer注解
③改造config-client
pom.xml添加eureka依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
application.properties加上服务注册地址:
spring.application.name=config-client
#远程仓库的分支
spring.cloud.config.label=master
#dev开发环境配置文件 test测试环境 pro正式环境
spring.cloud.config.profile=dev
#配置服务中心的网址
spring.cloud.config.uri=http://localhost:8888/
#指定服务注册地址
eureka.client.serviceUrl.defaultZone=http://localhost:8889/eureka/
#从配置中心读取文件
spring.cloud.config.discovery.enabled=true
#配置中心的servieId,即服务名
spring.cloud.config.discovery.serviceId=config-server
server.port=8881
在读取配置文件不再写ip地址,而是服务名,这时如果配置服务部署多份,通过负载均衡,从而高可用
依次启动eureka-servr,config-server,config-client
访问网址:http://localhost:8889/
application中包含configserver 和 config client
访问http://localhost:8881/hi,浏览器显示:
foo version 2
12.消息总线
Spring Cloud Bus 将分布式的节点用轻量的消息代理连接起来。它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控。本文要讲述的是用Spring Cloud Bus实现通知微服务架构的配置文件的更改。
下载rebbitmq: http://www.rabbitmq.com/
config-client添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
application.properties中加上RabbitMq的配置:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
# spring.rabbitmq.username=
# spring.rabbitmq.password=
依次启动eureka-server、confg-cserver,启动两个config-client,端口为:8881、8882。
访问http://localhost:8881/hi 或者http://localhost:8882/hi 浏览器显示:
foo version 2
这时我们去代码仓库将foo的值改为“foo version 4”,即改变配置文件foo的值。如果是传统的做法,需要重启服务,才能达到配置文件的更新。此时,我们只需要发送post请求:http://localhost:8881/bus/refresh,你会发现config-client会重新读取配置文件
再访问http://localhost:8881/hi 或者http://localhost:8882/hi 浏览器显示:
foo version 4
/bus/refresh接口可以指定服务,即使用”destination”参数,比如 “/bus/refresh?destination=customers:**”即刷新服务名为customers的所有服务,不管ip。
当git文件更改的时候,通过pc端用post 向端口为8882的config-client发送请求/bus/refresh/;此时8882端口会发送一个消息,由消息总线向其他服务传递,从而使整个微服务集群都达到更新配置文件。
13.spring cloud sleuth服务链接追踪
作用:在分布式系统中提供追踪解决方案,并且兼容支持了 zipkin
http://blog.youkuaiyun.com/forezp/article/details/70162074
14.高可用服务注册中心
http://blog.youkuaiyun.com/forezp/article/details/70183572
特别鸣谢方志朋的博客