SpringCloud入门手册
一.项目结构
1.搭建父工程
2.父工程继承springboot
<parent>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
3.父工程管理SpringCloud依赖
<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>
</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>
二.EurekaServer搭建
1.搭建子模块集成 父工程
<parent>
<artifactId>springcloud</artifactId>
<groupId>cn.xh</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
2.导入依赖:eureks-server, web包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.主配置类添加注解:
@SpringBootApplication
@EnableEurekaServer
4.application.yml配置: 端口 , 注册中心地址 ,禁止向自己注册,禁止拉取注册列表
单个服务器配置:
server:
port: 1010 #端口
eureka:
instance:
hostname: localhost #主机名
client: #客户端配置
registerWithEureka: false #EurekaServer自己不要注册到EurekaServer自己 ,只有EurekaClient才注册
fetchRegistry: false #EurekaServer不要拉取服务的通信地址列表 ,只有EurekaClient才拉取地址列表
serviceUrl: #注册中心的注册地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #http://localhost:1010/eureka/
server:
enable-self-preservation: false #关闭自我保护警告
spring:
application:
name: eureka-server #服务器名
三.EurekaClient集成
1.搭建子模块集成父工程
<parent>
<groupId> org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
2.导入依赖 eureks-client, web包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.在主配置类添加注解
@SpringBootApplication
@EnableEurekaClient //可以不加
4.配置application.yml
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1011/eureka/,http://peer2:1012/eureka/,http://peer3:1013/eureka/
#defaultZone: http://peer1:1011/eureka 单个服务器配置
instance:
instance-id: order-server:1030
prefer-ip-address: true
spring:
application:
name: order-server
server:
port: 1030
5.启动项目
红色字体为自我保护警告,可通过yml配置关闭。实际开发中建议开启。
四.EurekaServer集群
1.模拟三个服务器,修改system32/driver/etc/host文件:
127.0.0.1 peer1
127.0.0.1 peer2
127.0.0.1 peer3
2.修改Run/Debug Configuration配置如下,使单个主配置类可以多次启动
3.服务器集群配置:
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1011/eureka/,http://peer2:1012/eureka/,http://peer3:1013/eureka/
instance:
prefer-ip-address: true
spring:
application:
name: eurela-server
profiles:
active: peer1
---
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
ip-address: peer1:1011
server:
port: 1011
---
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
ip-address: peer1:1012
server:
port: 1012
---
spring:
profiles: peer3
eureka:
instance:
hostname: peer3
ip-address: peer1:1013
server:
port: 1013
4通过修改active分别启动三个Eureka服务器端
五.服务通信RestTemplate
通过Eureka客户端去调用另一个客户端的资源使用RestTemplate通过http请求实现
1.创建子模块,创建一个domain实体类作为jar包来封装公共数据
springcloud-user-common
2.导入依赖的jar包
<dependency>
<groupId>cn.xh</groupId>
<artifactId>springboot-user-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.配置RestTemplate的bean
在主配置类中配置
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
4.在调用端创建controller通过RestTemplate向被调用端发http请求
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/order/{id}",method = RequestMethod.GET)
public User getUser(@PathVariable Long id){
String url = "http://peer1:1011/user/"+id;
User forObject = restTemplate.getForObject(url, User.class);
return forObject;
}
}
5.被调用端接收到RestTemplate发送的请求后,获取资源返回给调用端
//获取当前被调用客户端的端口号
@Value("${server.port}")
private int port;
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
public User getUser(@PathVariable Long id){
//模拟数据
User user = new User(1L,"thor","666666","雷神,prot"+port);
return user;
}
6.启动调用客户端和被调用客户端,调用客户端通过浏览器发送请求得到模拟的数据:
六.Ribbon集成
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2.在只配置类的RestTemplate配置上加@loadBalance注解
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
3.将调用端请求url中的ip+端口号该为被调用端的服务名
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/order/{id}",method = RequestMethod.GET)
public User getUser(@PathVariable Long id){
String url = "http://user-server/user/"+id;
User forObject = restTemplate.getForObject(url, User.class);
return forObject;
}
4.在被调用端controller类加上一个当前被调用客户端端口号字段,在返回值中加上该字段的值
@Value("${server.port}")
private String port;
5.在浏览器中通过调用端访问资源
可以得到模拟的资源,并且ribbon的默认均衡负载模式为轮询。
可以通过在调用端主配置类中添加@Bean来改变负载均衡模式:
RoundRobinRule(默认) 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
代码如下:
//随机模式
@Bean
public RandomRule randomRule(){
return new RandomRule();
}
七.Feign的集成
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.主配置类添加注解开启Feign
@EnableFeignClients
3.在调用端创建FeignClient的接口,接口中的方法与被调用客户端的方法名,参数,请求,返回类型完全一致,添加@FeignClient(value = “user-server”),value为要调用的服务名
@FeignClient(value = "user-server")
public interface UserFeignClient {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
User getUserById(@PathVariable("id") Long id);
}
5.在浏览器中通过调用端访问资源
八.Ribbon+Hystrix使用
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.在主配置类上添加@EnableCircuitBreaker注解开启Hystrix
@EnableCircuitBreaker
3.在controller类方法@RequestMapping注解中添加属性fallbackMethid指向降级方法
@HystrixCommand(fallbackMethod = "getUserFallbackMethod")
4.申明降级方法: 参数和返回值必须和被熔断的方法一致 ,方法名要和 fallbackMethod 的值一致
@HystrixCommand(fallbackMethod = "getUserFallbackMethod")
@RequestMapping(value = "/order/{id}",method = RequestMethod.GET)
public User getUser(@PathVariable Long id){
String url = "http://user-server/user/"+id;
User forObject = restTemplate.getForObject(url, User.class);
return forObject;
}
public User getUserFallbackMethod(@PathVariable Long id){
User user = new User(-1L,"无法找到该用户","系统繁忙!请稍后再试!");
return user;
}
5.重启客户端,关闭被调用客户端,在浏览器中通过调用端访问资源
九.Feign开启Hystrix
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.主配置类添加注解@EnableCircuitBreaker开启Hystrix
@EnableCircuitBreaker
3.application.yml配置开启Hysrix
feign:
hystrix:
enabled: true #开启熔断支持
4.配置熔断
方式1:
托底类实现FeignClient接口方式
①申明一个托底类实现FeignClient接口,添加@Component注解,将托底类交给Spring管理
@Component
public class UserFeignClientFallback implements UserFeignClient{
@Override
public User getUserById(Long id) {
User user = new User(-1L,"无法找到该用户","系统繁忙!请稍后再试!");
return user;
}
}
②在FeignClient接口的@FeignClient注解中添加fallback属性,值为托底类.class
@FeignClient(value = "user-server",fallback = UserFeignClientFallback.class)
public interface UserFeignClient {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
User getUserById(@PathVariable("id") Long id);
}
③重启客户端,关闭被调用客户端,在浏览器中通过调用端访问资源
方式2:
托底类实现FeignClient接口方式
①申明一个托底类实现FallbackFactory接口,添加@Component注解将托底类交给Spring管理
@Component
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> {
@Override
public UserFeignClient create(Throwable throwable) {
return new UserFeignClient() {
@Override
public User getUserById(Long id) {
User user = new User(-1L,"无法找到该用户","系统繁忙!请稍后再试!");
return user;
}
};
}
}
②在FeignClient接口的@FergnClient注解中添加属性fallbackFactory值为托底工厂类.class
@FeignClient(value = "user-server",fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
User getUserById(@PathVariable("id") Long id);
}
③重启客户端,关闭被调用客户端,在浏览器中通过调用端访问资源
十.zuul
1.创建子模块导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2.添加注解
@EnableZuulProxy
3.配置application.yml
eureka:
client:
serviceUrl:
defaultZone: http://peer1:1011/eureka/,http://peer2:1012/eureka/,http://peer3:1013/eureka/
instance:
instance-id: zuul-server:1060
prefer-ip-address: true
spring:
application:
name: zuul-server
server:
port: 1060
zuul:
prefix: "/servers" #统一访问前缀
ignoredServices: '*' #禁用掉使用浏览器通过服务名的方式访问服务
routes:
user-server: /user/** #给服务名取别名
pay-server: /pay/**
order-server: /order/**
4.创建前置过滤器,做登录认证
@Component
public class MyZuulFilter extends ZuulFilter{
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.SEND_ERROR_FILTER_ORDER;
}
@Override
public boolean shouldFilter() {
//获取请求对象
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String uri = request.getRequestURI();
if (uri.contains("/login") || uri.contains("/register")){
return false;
}
return true;
}
@Override
public Object run() throws ZuulException {
//获取请求对象
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
//获取响应对象
HttpServletResponse response = currentContext.getResponse();
//设置编码
response.setContentType("application/json;charset=utf-8");
//获取请求头的toke
String token = request.getHeader("token");
//判断是否登录
if (StringUtils.isEmpty(token)){
Map<String,Object> result = new HashMap<>();
result.put("success",false);
result.put("msg","未登陆,没有权限访问");
String s = JSON.toJSONString(result);
try {
response.getWriter().write(s);
} catch (IOException e) {
e.printStackTrace();
}
//响应状态403
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
//程序不再往后执行
currentContext.setSendZuulResponse(false);
}
return null;
}
}
5.启动客户端,用idea自带的工具测试
请求头没有添加token的结果
请求头添加token后的结果
十一.ConfigServer
1.创建码云仓库
2.创建子模块导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
3.主配置类添加注解开启配置中心
@EnableConfigServer
4.配置application.yml
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: 码云仓库地址
username: 码云账号
password: 密码
eureka:
instance:
prefer-ip-address: true
instance-id: config-server:1070
client:
serviceUrl:
defaultZone: http://peer1:1011/eureka/,http://peer2:1012/eureka/,http://peer3:1013/eureka/
5创建本地文件夹克隆
6将项目中的application.yml文件复制到该文件夹中,注意命名application-服务名,提交并推送
查看码云仓库,上传成功
7启动客户端,在浏览器中访问资源,得到对应配置文件
十二.ConfigClient
1集成ConfigClient,在应用客户端添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
2.配置bootstrap.yml
#配置中心的地址
spring:
cloud:
config:
uri: http://localhost:1070 #order要从配置中心拉取文件
#你要拉取具体的哪个配置文件
name: application-order #配置文件名字
label: master #主分支
3将application文件修改名字使springcloud无法自动识别该服务的application.yml
4重启客户端,端口为1030则表示拉去成功,若为8080则拉去失败,需要重新检查配置
5.通过浏览器访问,得到结果,配置成功