Eureka 服务注册与发现
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- Spring Cloud End -->
- @EnableEurekaServer:启动一个服务注册中心
- 配置:application.yml
spring:
application:
name: itoken-eureka
boot:
admin:
client:
url: http://localhost:8084
zipkin:
base-url: http://localhost:9411
server:
port: 8761
eureka:
instance:
hostname: host
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health,info
服务提供者
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- Spring Cloud End -->
- @EnableEurekaClient 表明自己是一个 Eureka Client
- 配置application.yml
spring:
application:
name: hello-spring-cloud-service-admin
server:
port: 8762
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
服务消费者(Feign)
<!-- Spring Cloud Begin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Spring Cloud End -->
- @EnableDiscoveryClient :注解注册到服务中心
- @EnableFeignClients: 注解开启 Feign 功能
- 配置application.yml
设置程序端口号为:8765
spring:
application:
name: hello-spring-cloud-web-admin-feign
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 8765
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- @FeignClient("服务名"): 注解来指定调用哪个服务
@FeignClient(value = "hello-spring-cloud-service-admin")
熔断器防止服务雪崩hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 在 Service 中增加 fallback 指定类
package com.funtl.hello.spring.cloud.web.admin.feign.service;
import com.funtl.hello.spring.cloud.web.admin.feign.service.hystrix.AdminServiceHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "hello-spring-cloud-service-admin", fallback = AdminServiceHystrix.class)
public interface AdminService {
@RequestMapping(value = "hi", method = RequestMethod.GET)
public String sayHi(@RequestParam(value = "message") String message);
}
package com.funtl.hello.spring.cloud.web.admin.feign.service.hystrix;
import com.funtl.hello.spring.cloud.web.admin.feign.service.AdminService;
import org.springframework.stereotype.Component;
@Component
public class AdminServiceHystrix implements AdminService {
@Override
public String sayHi(String message) {
return "Hi,your message is :\"" + message + "\" but request error.";
}
}
熔断器仪表盘监控HystrixDashboard
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableHystrixDashboard
public class WebAdminRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(WebAdminRibbonApplication.class, args);
}
}
- 创建 hystrix.stream 的 Servlet 配置
Spring Boot 2.x 版本开启 Hystrix Dashboard 与 Spring Boot 1.x 的方式略有不同,需要增加一个 HystrixMetricsStreamServlet 的配置,代码如下:
package com.funtl.hello.spring.cloud.web.admin.ribbon.config;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HystrixDashboardConfiguration {
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
路由网关统一访问接口Zuul
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
- @EnableZuulProxy: 注解开启 Zuul 功能
- application.yml
spring:
application:
name: hello-spring-cloud-zuul
server:
port: 8769
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
api-a:
path: /api/a/**
serviceId: hello-spring-cloud-web-admin-ribbon
api-b:
path: /api/b/**
serviceId: hello-spring-cloud-web-admin-feign
package com.funtl.hello.spring.cloud.zuul.fallback;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* 路由 hello-spring-cloud-web-admin-feign 失败时的回调
* <p>Title: WebAdminFeignFallbackProvider</p>
* <p>Description: </p>
*
* @author Lusifer
* @version 1.0.0
* @date 2018/7/27 6:55
*/
@Component
public class WebAdminFeignFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
// ServiceId,如果需要所有调用都支持回退,则 return "*" 或 return null
return "hello-spring-cloud-web-admin-feign";
}
/**
* 如果请求服务失败,则返回指定的信息给调用者
* @param route
* @param cause
* @return
*/
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
/**
* 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的,
* 不应该把 api 的 404,500 等问题抛给客户端
* 网关和 api 服务集群对于客户端来说是黑盒
* @return
* @throws IOException
*/
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return HttpStatus.OK.value();
}
@Override
public String getStatusText() throws IOException {
return HttpStatus.OK.getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = new HashMap<>();
map.put("status", 200);
map.put("message", "无法连接,请检查您的网络");
return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
// 和 getBody 中的内容编码一致
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return headers;
}
};
}
}
路由网关的服务过滤功能
- 继承 ZuulFilter 类并在类上增加 @Component 注解就可以使用服务过滤功能了,非常简单方便
package com.funtl.hello.spring.cloud.zuul.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* Zuul 的服务过滤演示
* <p>Title: LoginFilter</p>
* <p>Description: </p>
*
* @author Lusifer
* @version 1.0.0
* @date 2018/5/29 22:02
*/
@Component
public class LoginFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(LoginFilter.class);
/**
* 配置过滤类型,有四种不同生命周期的过滤器类型
* 1. pre:路由之前
* 2. routing:路由之时
* 3. post:路由之后
* 4. error:发送错误调用
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 配置过滤的顺序
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 配置是否需要过滤:true/需要,false/不需要
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体业务代码
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
logger.info("{} >>> {}", request.getMethod(), request.getRequestURL().toString());
String token = request.getParameter("token");
if (token == null) {
logger.warn("Token is empty");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
context.getResponse().getWriter().write("Token is empty");
} catch (IOException e) {
}
} else {
logger.info("OK");
}
return null;
}
}
filterType
返回一个字符串代表过滤器的类型,在 Zuul 中定义了四种不同生命周期的过滤器类型
- pre:路由之前
- routing:路由之时
- post: 路由之后
- error:发送错误调用
filterOrder
过滤的顺序
shouldFilter
是否需要过滤,这里是 true,需要过滤
run
过滤器的具体业务代码
分布式配置中心服务端config-server
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
- @EnableConfigServer:开启配置服务器功能
- application.yml
spring:
application:
name: itoken-config
boot:
admin:
client:
url: http://localhost:8084
cloud:
config:
label: master
server:
git:
uri: https://github.com/faramita-itoken/itoken-config.git
search-paths: respo
username: bsab123
password: xjx397556048
zipkin:
base-url: http://localhost:9411
server:
port: 8888
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health,info
respo文件
spring:
application:
name: itoken-web-admin
boot:
admin:
client:
url: http://localhost:8084
zipkin:
base-url: http://localhost:9411
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 8601
feign:
hystrix:
enabled: true
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health,info
metrics:
web:
server:
auto-time-requests: false
itoken-web-admin-prod
spring:
application:
name: itoken-web-admin
boot:
admin:
client:
url: http://139.224.117.172:8084
zipkin:
base-url: http://139.224.117.172:9411
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server:
port: 8601
feign:
hystrix:
enabled: true
eureka:
client:
serviceUrl:
defaultZone: http://139.224.117.172:9411:8761/eureka/,http://139.224.117.172:9411:8861/eureka/,http://139.224.117.172:9411:8961/eureka/
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health,info
metrics:
web:
server:
auto-time-requests: false
分布式配置中心客户端config
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
spring:
cloud:
config:
uri: http://localhost:8888
name: itoken-eureka
label: master
profile: dev
ZipKin 服务链路追踪
<!-- ZipKin Begin -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>${zipkin.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>${zipkin.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>${zipkin.version}</version>
</dependency>
<!-- ZipKin End -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
- @EnableZipkinServer: 注解开启 Zipkin Server 功能
- application.yml
设置端口号为:9411,该端口号为 Zipkin Server 的默认端口号
spring:
application:
name: hello-spring-cloud-zipkin
server:
port: 9411
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
metrics:
web:
server:
auto-time-requests: false
- 所有需要被追踪的项目(就当前教程而言,除了 dependencies 项目外都需要被追踪,包括 Eureka Server) 中增加 spring-cloud-starter-zipkin 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
- 在这些项目的 application.yml 配置文件中增加 Zipkin Server 的地址即可
spring:
zipkin:
base-url: http://localhost:9411
Spring Boot Admin 服务端
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
- @EnableAdminServer: 注解开启 Admin 功能
- application.yml
spring:
application:
name: itoken-admin
zipkin:
base-url: http://localhost:9411
server:
port: 8084
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health,info
Spring Boot Admin 客户端
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
设置端口号为:8085,并设置 Spring Boot Admin 的服务端地址
spring:
application:
name: hello-spring-cloud-admin-client
boot:
admin:
client:
url: http://localhost:8084
zipkin:
base-url: http://localhost:9411
server:
port: 8085
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
- 主要增加了 Spring Boot Admin Client 相关配置
spring:
boot:
admin:
client:
url: http://localhost:8084