SpringCloud
项目搭建
准备一个maven项目,pom.xml中写入springboot和cloud约束的版本
<!--springboot约束子项目的版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<!--指定编码集和java版本-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
<springboot.version>2.0.5.RELEASE</springboot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
准备springboot子项目
子项目pom.xml依赖
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
Eureka注册中心配置
依赖
<!--Eureka服务端支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
application.yml配置:
server:
port: #服务端口
spring:
application:
name: #服务名称
eureka:
instance:
hostname: eureka-server #访问uri eureka-server
client:
registerWithEureka: true #是否要注册到eureka
fetchRegistry: false #表示是否从Eureka Server获取注册信息
service-url:
defaultZone: http://eureka-server+端口号/eureka/ #注册地址 多个用,隔开
在springboot启动类上加上
@EnableEurekaServer //标识为Eureka服务类
Eureka客户端配置
依赖
<!--注册客服端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml配置:
server:
port: #服务端口
spring:
application:
name: #服务名称
eureka:
client:
service-url:
defaultZone: #对应服务端注册地址 多个用,隔开
instance:
prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
在springboot启动类上
@EnableEurekaClient //标识为客户端
Ribbon负载均衡
客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
yml配置
ribbon:
ReadTimeout: 3000 #读取超时时间
ConnectTimeout: 3000 #链接超时时间
MaxAutoRetries: 1 #重试机制:同一台实例最大重试次数
MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数
OkToRetryOnAllOperations: false #是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改
eager-load:
enabled: true #开启饥饿加载
clients: user-comsumer #针对于哪些服务需要饥饿加载
在调用javaHttp请求类上:
@LoadBalanced 注解就可以开启Ribbon负载平衡
例如:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate(); //发起http的springboot集成的类
}
@Bean #改变均衡策略
public IRule rule(){
return new RandomRule();
}
}
在填写跳转地址时ip地址修改为服务名称,例如
@RestController
@RequestMapping("/consumer/user")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id){
User user = restTemplate.getForObject("http://user-provider/provider/user/" + id, User.class);
return user;
}
}
Feign配置
他底层是集成了ribbon 和hystrix
依赖pom.xml
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
application.yml配置
ribbon:
ReadTimeout: 1000 #读取超时时间
ConnectTimeout: 1000 #链接超时时间
MaxAutoRetries: 1 #重试机制:同一台实例最大重试次数
MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数
OkToRetryOnAllOperations: false #是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改
eager-load:
enabled: true #开启饥饿加载
clients: user-provider #针对于哪些服务需要饥饿加载
feign:
hystrix:
enabled: true #开启熔断支持
client:
config:
remote-service: #服务名,填写default为所有服务
connectTimeout: 1000
readTimeout: 1000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000
需要在springboot启动类上加载注解:
@EnableFeignClients(basePackages = “配置feign对应接口类的包全限定名”) //如果包与启动类平级可以省略
配置feign接口类:
需要加上@FeignClient 注解,value的值=要请求的服务名称,fallbackFactory有hystrix时才填写,选择回调类的字节码文件.
@FeignClient(value = "USER-PROVIDER",fallbackFactory = HystrixUserConfig.class)
@RequestMapping("/provider")
public interface IUserClient {
@GetMapping("/user/{id}")
public User getUser(@PathVariable Long id);
}
消费类使用hystrix
配置文件
@Component
public class HystrixUserConfig implements FallbackFactory<IUserClient> {
@Override
public IUserClient create(Throwable cause) {
return new IUserClient() {
@Override //准备访问服务的对应的方法
public User getUser(Long id) {
return new User(null,"没有找到");
}
};
}
}
Hystrix断路器
服务类(生产者)添加
依赖pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
例如:
需要在请求地址的对应的方法上使用 @HystrixCommand注解 fallbackMethod是回调指定的方法
@RestController
@RequestMapping("/provider/user")
public class ProviderController {
@GetMapping("/{id}")
@HystrixCommand(fallbackMethod = "getFallBack") //开启hystrix
public void getUser(@PathVariable Long id){}
//回调方法
public User getFallBack(Long id){
return new User(null,"用户不存在");
}
}
Zuul路由网关
依赖pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
application.yml配置
server:
port: 6020
spring:
application:
name: zuul-gateway
eureka:
client:
service-url:
defaultZone: http://eureka1:1010/eureka
instance:
instance-id: zuul:6020
prefer-ip-address: false
zuul:
retryable: true
routes:
myUser.serviceId: user-provider # 服务名
myUser.path: /myUser/** # 把myUser打头的所有请求都转发给user-provider
ignored-services: "*" #所有服务都不允许以服务名来访问
prefix: "/services" #加一个统一前缀
ribbon:
ConnectTimeout: 1000 # 连接超时时间(ms)
ReadTimeout: 1000 # 通信超时时间(ms)
OkToRetryOnAllOperations: true # 是否对所有操作重试
MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMillisecond: 1000 # 熔断超时时长:3000ms
配置springboot启动类
需要@EnableZuulProxy 注解
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class Zuul_App {
public static void main(String[] args) {
SpringApplication.run(Zuul_App.class);
}
}
配置过滤器
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return false;
}
@Override
public Object run() throws ZuulException {
//获取上下文对象
RequestContext context = RequestContext.getCurrentContext();
//获取请求头
HttpServletRequest request = context.getRequest();
//得到请求
String token = request.getHeader("token");
if(token==null||"".equals(token.trim())){
//拦截
context.setSendZuulResponse(false);
//返回信息
context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
}
springConfig配置中心
配置中心服务:
不需要注册中心注册 pom.xml依赖
<dependencies>
<!--springboot支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--配置中心支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
application.yml配置
server:
port: 3010
spring:
application:
name: spring-cloud-config-server #配置服务名
profiles:
active: git
cloud:
config:
server:
git:
uri: #远程仓库uri
username: #登入账户
password: #登入密码
native: #本地
search-locations: file:地址
需要在springboot启动类上使用 @EnableConfigServer 注解.
其他需要配置的服务配置:
pom.xml依赖
<!--configclient端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
需要bootstrap.yml全局配置
spring:
cloud:
config:
name: application-zull #gitee上面名称
profile: dev #环境
label: master #分支
uri: http://127.0.0.1:3010 #配置本机服务器
自动刷新
配置服务中心
导入pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
application.yml配置中添加
spring:
rabbitmq: #集成RabbitMQ如果配置是默认,可以省略
host: localhost #mq连接地址
port: 5672 #mq端口
username: guest #登入账户
password: 123456 #登入密码
#actuator配置
management:
endpoint:
health:
show-details: always #打印日志
endpoints:
web:
exposure:
include: "*" #向外暴露的接口,这里*则表示所有的actuator接口都可以被访问
enabled-by-default: true #开启actuator监控
配置客户端
客户端的pom.xml添加配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yml追加配置:
spring:
rabbitmq: #集成RabbitMQ如果配置是默认,可以省略
host: localhost #mq连接地址
port: 5672 #mq端口
username: guest
password: guest
cloud:
config:
name: application-zuul #gitee上面名称
profile: dev #环境
label: master #分支
bus: #这行代码很重要,根据官方定义的标准来的 ,就是为了产生一个bus.id
id: ${spring.application.name}:${spring.cloud.config.profile}:${random.value}
如果仓库请求报格式无法解析
在服务段配置一个WebConfig 类
/**
* 扩展MVC组件
*/
@Component
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter httpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setCharset(StandardCharsets.UTF_8);
//禁止循环引用
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
httpMessageConverter.setFastJsonConfig(config);
//所有序列化组件均保存在converters集合中
//添加扩展的组件到索引0的位置,便于Spring首先尝试
converters.add(0, httpMessageConverter);
}
}