今天写一个自己提供服务自己消费服务的项目
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<scope>import</scope>
<type>pom</type>
</dependency>
项目目录
首先是注册中心Eureka
server:
port: 7001
# 服务名称, 在Spring Cloud非常重要, 可以使用它查找其它服务
spring:
application:
name: eureka-server
eureka:
server:
# 关闭自我保护模式
enable-self-preservation: false
client:
# 单机情况下不需要在eureka server上获取注册信息
fetch-registry: false
# 单机的eureka server不需要向注册中心注册
register-with-eureka: false
service-url:
# 如果是集群, 这里需要写其它几个节点的地址
defaultZone: http://localhost:7001/eureka
启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class, args);
}
}
启动注册中心
提供者(主要干活的人)
提供者的Controller->Service->Dao其实和之前SpringBoot的那一套流程是一样的,主要是让注册中心发现这个服务,@EnableDiscoveryClient把服务搞到注册中心中
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<!-- 添加Hystrix依赖 一会要用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
server:
port: 8080
servlet:
context-path: /user_sys
# 注册到Eureka Server的服务名称
spring:
application:
name: user-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///et2009?serverTimezone=UTC
username: root
password: etoak
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.etoak.bean
logging:
level:
com.etoak.mapper: debug
启动类注意我刚才说的@EnableDiscoveryClient,@EnableHystrix两个注解
@SpringBootApplication
@EnableDiscoveryClient // 应用于Eureka、zookeeper、Nacos...
@MapperScan(basePackages = "com.etoak.mapper")
@EnableCircuitBreaker // 启动断路器
public class UserServiceApp {
public static void main(String[] args) {
SpringApplication.run(UserServiceApp.class, args);
}
}
启动项目看注册中心
消费方(皮包公司)
feign
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-openfeign</artifactId>
</dependency>
server:
port: 8081
servlet:
context-path: /order_sys
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
Controller+启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 启动OpenFeign的自动配置
@RestController
public class OrderServiceApp {
@Autowired
UserService userService;
@GetMapping("/user/{id}")
public Result<User> getUser(@PathVariable int id) {
return userService.getUser(id);
}
@GetMapping("postkv")
public Result<User> postkv(User user) {
return userService.addUser(user.getName(),
user.getEmail(),
user.getAge());
}
@GetMapping("postjson")
public Result<User> postjson(User user) {
return userService.addUser2(user);
}
public static void main(String[] args) {
SpringApplication.run(OrderServiceApp.class, args);
}
}
接口 (核心)–>负责去调服务提供者的服务 @FeignClient,没有实现类 相当于直接去映射提供方的Controller中的方法
@FeignClient("user-service") //spring name
@RequestMapping("/user_sys/user")//context-path/类
public interface UserService {
@GetMapping("/getUser")//服务提供者controller中的方法
Result getUser(@RequestParam int id);
@PostMapping("/addUser")//服务提供者controller中的方法
Result addUser(@RequestParam("name")String name);
@PostMapping("/add")//服务提供者controller中的方法
Result addUser2(@RequestBody User user);
}
我们执行以下比如我们访问/user/{id}这个路由下的方法localhost8081:order_sys/user/1
ok 没什么问题
但是在提供端加上断点你会发现真正干活的还是提供段,他会指派提供端真正的去操作数据库
resttemplate
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
目录结构
server:
port: 8083
servlet:
context-path: /goods_sys
spring:
application:
name: goods-service
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
启动类+Controller
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class GoodsServiceApp {
@Autowired
RestTemplate restTemplate;
private static final String USER_SERVICE_URL="http://user-service/user_sys";
@GetMapping("/user/{id}")
public Result getUser(@PathVariable int id){
//请求地址 请求方法 请求参数
String url =USER_SERVICE_URL +"/user/getUser?id="+id;
return restTemplate.getForObject(url,Result.class);
}
@GetMapping("/postjson")
public Result postJson(User user){
String url =USER_SERVICE_URL+"/user/add";
//默认发json
return restTemplate.postForObject(url,user,Result.class);
}
@GetMapping("/postkv")
public Result postkv(User user){
String url =USER_SERVICE_URL+"/user/addUser";
MultiValueMap<String,Object> param =new LinkedMultiValueMap<>();
param.add("name",user.getName());
return restTemplate.postForObject(url,param,Result.class);
}
@Bean
@LoadBalanced //RestTemplate添加负载均衡功能
public RestTemplate restTemplate(){
//发起请求的工具
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(GoodsServiceApp.class,args);
}
}
启动看注册中心是否有我们注册的消费方
运行localhost:8083:goods_sys/user/1
ok也是没有任何问题的
网关zuul(中转站)
- 跳过消费者直接中转到提供者
依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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-zuul</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9002
servlet:
context-path: /zuul
spring:
application:
name: zuul
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ZuulApp {
public static void main(String[] args) {
SpringApplication.run(ZuulApp.class,args);
}
}
启动之后的注册中心zuul也是没有问题的
访问url的路径 http://localhost:9002/zuul/user-service/user_sys/user/getUser?id=1直接绕过消费者直接去调提供方的controller
网关地址:端口号/contextpath/提供方springname/contextpath/类url/方法url+参数
熔断器
当一时间访问某个接口的访问量过大,那我们用一个熔断器去做一个熔断,熔断这个操作一定是在提供方的Conrtoller的某些方法上,在提供方的启动类上需要@EnableHystrix这个注解来开启熔断
@HystrixCommand(fallbackMethod = "getUserFallback", commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), // 在一个滑动窗口内,开启熔断器检查统计条件,默认为20/10s。需要注意,如果在十秒内,有19个请求,都出现错误,也不会,触发熔断。
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"), // 失败率达到多少百分比后熔断。默认50%
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "20000") // 熔断多久以后开始尝试是否恢复。默认5s
})
如果的请求老是出异常 那这个方法就会被熔断,5秒后在自动修复
以下是今天写的所有东西的一个概况
总结
一个SpringCloud的小例子带着大家写一遍,主要还是摸流程,后面会带着大家实际操练的
最后总结一下SpringCloud用到的注解:
- @EnableEurekaServer :加在注册中心的启动类
- @EnbaleDiscoverClient:加在所有服务的启动类,让注册中心发现这个服务
- @EnableHystrix:加在服务提供者的启动类,表示开启熔断器
- @EnableFeignClients:加在FeignClients类型的消费方的启动类
- @LoadBalanced :RestTemplate添加负载均衡功能
- @EnableZuulProxy:网关对象的启动类上,开启网关动态代理