org.springframework.cloud
spring-cloud-starter-eureka-server
@EnableEurekaServer
server.port=1111
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false //是否将自己注册到eureka,由于自己已经是eureka负责,所以false
eureka.client.fetch-registry=false //是否从eureka获取注册信息,由于是单点服务,所以为false
//eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ //注册到其他Eureka的地址
org.springframework.cloud
spring-cloud-starter-eureka
@EnableDiscoveryClient //服务注册的通用注解,可以注册Eureka、Consul、Zookeeper,spring-cloud-commons提供
@EnableEurekaClient //当确定使用Eureka时,可以替代@EnableDiscoveryClient,spring-cloud-netflix提供
spring.application.name=hello-service //注册到eureka的服务名
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
eureka.instance.prefer-ip-addresss=true //是否将自己的ip注册到eureka,默认未false表示注册hostname
eureka.client.serviceUrl.defaultZone=http://ip:port/eureka/ //把自己注册到其他Eureka
eureka.client.serviceUrl.defaultZone=http://ip1:port/eureka/,http://ip2:port/eureka/
org.springframework.cloud
spring-cloud-starter-security
security.basic.enabled=true
security.user.name=tuyou
security.user.password=123456
eureka.client.serviceUrl.defaultZone=http://tuyou:123456@localhost:1111/eureka/
eureka.instance.metadata-map.mykey=myvalue //自定义元数据
@Autowired
private DiscoveryClient client;
client.getInstances()
eureka提供了一些接口,方便其他非jvm的服务接入进来,并且eureka的client也是调用的这些接口
//禁用自我保护模式,当eureka认为出现网络分区的时候,会启动自我保护,也就是不会删除已注册的微服务
eureka.server.enable-self-preservation=false
//客户端启用健康检查,如果想实现更细腻度的健康检查,可以实现检查接口
eureka.client.healthcheck=true
org.springframework.cloud
spring-cloud-starter-ribbon
@EnableDiscoveryClient //必须加上
@SpringBootApplication
public class RibbonApplication {
@Bean
@LoadBalanced //ribbon负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
@Autowired
LoadBalancerClient loadBalancerClient;
@RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
public String helloConsumer() {
ServiceInstance instance = loadBalancerClient.choose("HELLO-SERVICE");
logger.info("serviceId:{},host:{},port:{}", instance.getServiceId(), instance.getHost(), instance.getPort());
return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();
}
ribbon的默认配置类是RibbonClientConfiguration
前提:SpringCloud Netflix版本要高于1.2.0
HELLO-SERVICE.ribbon.listOfServers=localhost:8081,localhost:8082
org.springframework.cloud
spring-cloud-starter-feign
//name对应要调用服务的spring.application.name
//如果FeignClient不想使用Eureka,可以直接指定ribbon.listOfServers
//或者指定url,@FeignClient(name="服务名称", url="http://localhost:8080/")
@FeignClient(name = "hello-service")
public interface HelloService {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String index();
}
@EnableFeignClients
//如果要使用Eureka,则要启用注册发现客户端
@EnableDiscoveryClient
@Configuration
public class FeignConfiguration {
@Bean
public Contract modifyDefaultFeignContract(){
return new feign.Contract.Default();
}
}
@FeignClient(name = "hello-service", configuration = FeignConfiguration.class)
public interface DefaultFeignService {
@RequestLine("GET /hello")
String index();
}
@Import(FeignClientsConfiguration.class) //必须加上
@RestController
@RequestMapping("/custom")
public class CustomFeignController {
HelloService helloService;
@Autowired
public CustomFeignController(Client client, Decoder decoder, Encoder encoder, Contract contract) {
helloService = Feign.builder().client(client)
.decoder(decoder)
.encoder(encoder)
.contract(contract)
.target(HelloService.class, "http://hello-service/");
}
@RequestMapping(value = "/feign-consumer", method = RequestMethod.GET)
public String helloConsumer() throws InterruptedException {
return helloService.index();
}
}
这样就可以服务端把controller接口封装到interface里面,然后controller和FeignClient都继承这个interface,达到服务端和客户端共享接口的目的
public interface CommonInterface {
@RequestMapping("/hello")
String hello(@RequestParam String name, @RequestParam Integer age);
//@RequestParam在controller可以不写,但是在feign中要写
}
@RestController
public class HelloController implements CommonInterface {
@Autowired
private DiscoveryClient client;
public String hello(String name, Integer age) {
ServiceInstance instance = client.getLocalServiceInstance();
return "/hello, service_id:" + instance.getServiceId() + ", host:" + instance.getHost() + ", port:" + instance.getPort();
}
}
@FeignClient(name = "hello-service") //name对应要调用服务的spring.application.name
public interface CommonService extends CommonInterface {
}
feign.compression.request.enable=true
feign.compression.response.enable=true
feign.compression.request.mime-types=text/html,application/xml,application/json
feign.compression.request.min-request-size=1
@Bean
public Logger.Level loggerLevel() {
return Logger.Level.FULL;
}
由于feign打印的日志是debug等级,修改日志打印等级为debug
%-4relative [%thread] %-5level %logger{35} - %msg %n
feign默认已经集成了hystrix,只要发现hystrix在classpath中,就会使用断路器包裹feign客户端方法,只需在@FeignClient上指定fallback属性即可指定回退方法
@FeignClient(value = "HELLO-SERVICE", fallback = HelloFeignFallbackService.class)
public interface HelloFeignService {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
String hello();
@RequestMapping(value = "/param", method = RequestMethod.GET)
String param(@RequestParam("name") String name, @RequestParam("age") Integer age) throws InterruptedException;
}
@Component
public class HelloFeignFallbackService implements HelloFeignService {
@Override
public String hello() {
return "hello默认回退返回";
}
@Override
public String param(String name, Integer age) throws InterruptedException {
return "param默认回退返回";
}
}
feign.hystrix.enabled=false //禁用hystrix
org.springframework.cloud
spring-cloud-starter-zuul
@EnableZuulProxy
@SpringCloudApplication
public class ZuulApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ZuulApplication.class).web(true).run(args);
}
// @Bean
// public TestFilter createFilter() {
// return new TestFilter();
// }
}
spring.application.name=api-gateway
server.port=5555
zuul.routes.hello.path=/hello/**
zuul.routes.hello.url=http://localhost:8080/hello/
zuul.routes.feign.path=/feign-consumer
zuul.routes.feign.service-id=feign-consumer
zuul.routes.ribbon.path=/ribbon-consumer
zuul.routes.ribbon.service-id=ribbon-consumer
eureka.client.serviceUrl.defaultZone=http://localhost:1110/eureka/
/routes 端点返回配置的路由信息
zuul.ignored-services=service1,service2
zuul.ignored-services='*' //禁用所有服务
zuul.ignored-patterns=**/admin/** //全局忽略代理指定的路径
zuul.prefix=/api
zuul.strip-prefix=true //全局指定是否切除前缀
zuul.routes.hello.path=/hello/**
zuul.routes.hello.url=http://localhost:8080/hello/
zuul.routes.hello.strip-prefix=false //局部指定是否切除前缀
logging.level.com.netflix=debug //修改zuul的日志等级,方便调试
//header配置
//敏感header,即只会在服务内部传输,不会外泄
zuul.sensitive-headers=Cookie,Set-Cookie,Authorization //全局设置敏感header,这三个也是默认值
zuul.service-id.sensitive-headers=header1,header2 //局部设置
//忽略header
zuul.ignored-headers=header1,header2 //默认为空,如果有security则为Cache-Control,Expires
zuul.ignored-secutiry-headers=false //关闭security禁用的header
使用/zuul前缀上传大文件,并增加超时时间
spring:
application:
name: hello-service
http:
multipart:
max-file-size: 2000mb //默认1mb
max-request-size: 2000mb //默认10mb
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
ribbon:
ConnectionTime: 3000
ReadTimeout: 60000
类型 | 说明 |
---|---|
pre | 这种过滤器在请求被路由之前调用 |
routing | 这种过滤器将请求路由到微服务 |
post | 这种过滤器在请求路由到微服务之后执行 |
error | 在其他阶段发生错误执行过滤器 |
public class TestFilter extends ZuulFilter {
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
// Map> requestQueryParams = requestContext.getRequestQueryParams();
// System.out.println(requestQueryParams);
HttpServletRequest request = requestContext.getRequest();
// System.out.println(request.getQueryString());
Map parameterMap = request.getParameterMap();
System.out.println(parameterMap);
// try {
// ServletInputStream inputStream = request.getInputStream();
// BufferedReader bufferedInputStream = new BufferedReader(new InputStreamReader(inputStream));
// String line = null;
// System.out.println("参数:");
// while ((line = bufferedInputStream.readLine()) != null) {
// System.out.println(line);
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
}
默认的过滤器:spring-cloud-netflix-core.jar包的org.springframework.cloud.netflix.zuul.filters包下面
zuul...disable=true
@Component
public class HelloFallback implements ZuulFallbackProvider {
@Override
public String getRoute() {
return "hello-service";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return this.getStatusCode().value();
}
@Override
public String getStatusText() throws IOException {
return this.getStatusCode().getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("微服务不可能用".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
MediaType mediaType = new MediaType("application", "json", Charset.forName("utf-8"));
headers.setContentType(mediaType);
return headers;
}
};
}
}
org.springframework.cloud
spring-cloud-starter-sleuth
logging:
level:
root: INFO
org.springframework.web.servlet.DispatchServlet: DEBUG
org.springframework.cloud.sleuth: DEBUG
net.logstash.logback
logstash-logback-encoder
4.6
DEBUG
${CONSOLE_LOG_PATTERN}
utf8
${LOG_FILE}
${LOG_FILE}.%d{yyyy-MM-dd}.gz
7
${CONSOLE_LOG_PATTERN}
utf8
${LOG_FILE}.json
${LOG_FILE}.json.%d{yyyy-MM-dd}.gz
7
UTC
{
"severity": "%level",
"service": "${springAppName:-}",
"trace": "%X{X-B3-TraceId:-}",
"span": "%X{X-B3-SpanId:-}",
"parent": "%X{X-B3-ParentSpanId:-}",
"exportable": "%X{X-Span-Export:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"rest": "%message"
}
logstash -f logstash.conf
logstash.conf配置
input {
file {
codec => json
path => "/Users/mac/Downloads/*.json"
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
}
}
output {
elasticsearch {
hosts => "localhost:9200"
}
}
io.zipkin.java
zipkin-autoconfigure-ui
io.zipkin.java
zipkin-server
@SpringBootApplication
@EnableZipkinServer
public class ZipkinApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinApplication.class, args);
}
}
3、配置
server:
port: 7777
org.springframework.cloud
spring-cloud-sleuth-zipkin
spring:
zipkin:
base-url: http://localhost:7777/
sleuth:
sampler:
percentage: 1.0
http://localhost:7777/