项目简介:
- SpringBoot 2.1.6
- spring-cloud Greenwich.SR5
- …
前言
ssm项目重构springboot项目后,在我们项目中各个模块之前充斥着如下使用http相互调用的应用,写一个两个还行,写多了麻烦而且不爽,由此产生使用springcloud的想法
/**
* 查询用户id和用户名的映射
* @param userIds
* @return
* @throws Exception
*/
public Map<Long, String> selectUserIdAndNameMap(List<Long> userIds) throws Exception{
Map<String, String> queryParam = new HashMap<>();
String userIdsJonsStr = JSONArray.toJSONString(userIds);
queryParam.put("userIds", userIdsJonsStr);
String baseHost = selectHostAddress(baseIp,basePort,basePath);
String responseStr = SimpleHttpClient.doPost(baseHost, "/sysYh/selectUserNameList", queryParam);
Response response = JSONObject.parseObject(responseStr, Response.class);
if(response != null && Objects.equals(response.getServerResult().getResultCode(), TkResponseCode.SUCCESS)){
Map<String,String> tempMap = (Map)response.getResponseEntity();
Map<Long, String> userIdAndNameMap = new HashMap<>();
for (Map.Entry<String, String> entry : tempMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
userIdAndNameMap.put(Long.valueOf(key), value);
}
return userIdAndNameMap;
}else{
return new HashMap<>();
}
}
Begin开始
Springcloud官网(https://spring.io/projects/spring-cloud)
springboot与不同版本cloud存在兼容性问题必须严格匹配避免不需要的麻烦,官网上有详细兼容介绍,项目中springboot版本为2.1.6,由此springcloud选择兼容的最新正式版本Greenwich.SR5
1.1 引入Maven依赖
使用兼容正式发布版本Greenwich.SR5,相关组件版本无需自己配置会自动选择,现阶段选择eureka feign 和hystrix组件,预留gateway服务,有必要时再研究研究
<!-- cloud 版本 -->
<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
<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>
<!-- cloud 相关组件依赖 -->
<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-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway</artifactId>
<version>2.1.4.RELEASE</version>
<type>pom</type>
<optional>true</optional>
</dependency>-->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>-->
1.2 配置eureka服务端客户端
没有新建项目单独作为服务端,选择base服务作为服务端,添加配置和相关注解就可以注册
1.2.1 服务端启动类添加@EnableEurekaServer
@EnableEurekaServer
public class BaseApp extends SpringBootServletInitializer {
...
}
1.2.2 服务端配置
# 服务端
eureka:
instance:
prefer-ip-address: true
# 消费端访问服务的ip,默认为部署服务端的ip
ip-address: ${EUREKA_IP_ADDRESS}
# 服务实例名称:端口
instance-id: ${spring.application.name}:${server.port}
# 每隔30s发送一次心跳
lease-renewal-interval-in-seconds: 30
# 告知服务端60秒还未收到心跳的话,就将该服务移除列表
lease-expiration-duration-in-seconds: 60
client:
registerWithEureka: true
fetchRegistry: false
# 注册中心地址
serviceUrl:
defaultZone: ${base.defaultZone}
server:
# 自我保护模式
enable-self-preservation: false
# 清理无效节点的时间间隔, 默认60s
eviction-interval-timer-in-ms: 60000
# eureka服务信息可有可无
info:
app.name: bigdata-base
build.artifactId: @project.artifactId@
build.version: @project.version@
ribbon:
eager-load:
# 饥饿加载模式
enabled: true
# 需要饥饿加载的服务名
clients: bigdata-base,.......
eureka:
enabled: true
1.2.3 客户端启动类添加@EnableDiscoveryClient
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class ModelApp extends SpringBootServletInitializer {
......
}
1.2.4 客户端配置eureka feign hystrix
eureka:
instance:
prefer-ip-address: true
ip-address: ${EUREKA_IP_ADDRESS}
instance-id: ${spring.application.name:bigdata-model}:${server.port}
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 60
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: ${model.defaultZone}
ribbon:
eager-load:
enabled: true
clients: bigdata-base...........
eureka:
enabled: true
feign 和 hystrix 配置
feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000
1.3 feign调用和熔断设置
1.3.1 注册类排除eureka静态资源
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public AuthenticateInterceptor authenticateInterceptor(){
return new AuthenticateInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(authenticateInterceptor());
registration.addPathPatterns("/**");
registration.excludePathPatterns("/login","/logout","/session","/");
registration.excludePathPatterns("/swagger-ui.html","/doc.html","/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**","/eureka/**");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html","doc.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
1.3.2 配置feign拦截器
登录沿用老的Springsession,请求头中添加Cookie信息
/**
* @Description: feigh拦截器
* @Date: 2020/4/30
*/
@Configuration
public class FeignClientInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
HttpServletRequest request = requestAttributes.getRequest();
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if(cookie.getName().equals("SESSION")){
StringBuffer cookieSbf = new StringBuffer();
cookieSbf.append(cookie.getName())
.append("=")
.append(cookie.getValue());
requestTemplate.header("Cookie", cookieSbf.toString());
break;
}
}
}
}
}
}
1.3.3 模块之前的feign调用
1.4 注册页面及测试
注册中心如图类似,测试feign正常调用及超时错误调用,流程正常,不用再一个个http调用了,就是很舒服~