SpringCloud-微服务使用入门

传统java编程中如果想要在程序中发起http请求有哪些做法?开源的http工具包有很多,OkHttp、HttpClient、jdk自带的等等,使用这些工具并不方便,需要程序员手动封装一些请求参数,构造请求,手动调用发送请求,处理响应。。。

因此在spring对这些工具类进行了封装,对外只提供RestTemplate类,开发人员使用RestTemplate可以很方便的发送http请求,只需要指定http请求的服务器地址及端口号。

父项目依赖配置:

父项目pom配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<properties>
<spring.boot.version>2.2.0.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.RELEASE</spring.cloud.version>
...
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

boot版本号 2.2.x.RELEASE 应当使用的cloud版本序列为Hoxton.RELEASE

父pom中这样配置,子模块中引入boot和cloud的依赖不再需要填写版本号信息,统一了系统的依赖版本

服务器配置:

主类上注解@EnableEurekaServer,表示是服务器

1
2
3
4
5
6
7
8
9
10
11
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false #是否要注册到eureka
fetchRegistry: false #表示是否从Eureka Server获取注册信息
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置

eureka服务器不需要注册注册中心让别人发线,所以配置registerWithEureka为false

也不需要获取其他服务的注册信息所以registerWithEureka 也为false

安全访问

eureka服务器可以配置安全访问,需要引入依赖spring-boot-stater-security,并配置user和password

1
2
3
4
5
spring:
security:
user:
name: admin
password: 123456

所有的客户端对的client.serviceUrl.defaultZone 都需要使用user:passwod@host 的形式进行配置

eg: http://admin:123456@localhost:8761/erueka/

注册服务

主类注解@EnableEurekaClient,表示是客户端

基本配置:

1
2
3
4
5
6
7
8
9
10
11
spring:
application:
name: user-provider
eureka:
client:
healthcheck:
enabled: true #开启健康检查,需要引入actuator依赖
service-url:
defaultZone: http://localhost:8761/eureka/ #告诉服务提供者要把服务注册到哪儿
instance:
prefer-ip-address: true #显示客户端真实ip

如果是eureka服务器集群,defaultZone可以写个url,用“,”隔开

若同一个服务需要部署多个实例,配置文件中服务名称srping.application.name需要一致

调用服务

服务调用方也需要引入eureka-client依赖,但需设置不注册到服务中心

1
2
3
eureka:
client:
register-with-eureka: false

服务调用可以使用ribbon或者feign进行负载均衡

使用ribbon:

eureka-client包中已经引入了netflix-ribbon,所以不用单独添加依赖。

注册一个RestTemplate Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
@EnableEurekaClient
public class ConsumerApp{
public static void main(String[] args){
SpringApplication.run(ConsumerApp.class);
}

@Bean
@LoadBalanced
public RestTemplater restTemplate(){
return new RestTemplate();
}
}

根据服务名称调用服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class UserController {
public static final String URL_PREFIX = "http://USER-PROVIDER";
private RestTemplate restTemplate;
@Autowired
public void setRestTemplate(RestTemplate template){
this.restTemplate = template;
}

@GetMapping("/user/{id}")
public User getUser(@PathVariable("id")Long id){
//调用远程服务 http请求
String url = URL_PREFIX+"/provider/user/"+id;
return restTemplate.getForObject(url,User.class);
}
}

缺点是需要拼接字符串。

使用feign

feign底层也是使用的ribbon

主类添加注解@EnableEurekaClient表示服务消费者是Eurrka客户端

主类添加注解@EnableFeignClients表示使用Fegin进行负载

首先定义fegint访问接口:

1
2
3
4
5
6
@FeignClient(value="user-provider")//需要调用的服务名称
public interface UserServiceFeignClient{
//此处为服务提供者提供的url
@GetMapping("provider/user/{id}")
public User getUser(@PathVariable("id")Long id);
}

在Controller中访问

1
2
3
4
5
6
7
8
9
10
@RestController
public class UserController{
@Autowired
private UserServiceFeignClient client;
//此处为服务消费者提供的url
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
return client.getUser(id);
}
}

比直接使用ribbon优雅多了

这样使用Feign还有一个问题,开发者需要了解服务提供者提供的所有rest接口并编写FeignClient接口来调用服务,还是会产生一些模块间的耦合问题,有什么方法可以解决这个问题吗?

如果FeignClient接口由服务提供者来编写,并打成jar包发布到仓库中,服务调用者只需要依赖提供者提供的api jar包,就能直接调用远程服务了。

下面演示一下具体用法: