前言
最近项目改造,采用微服务架构,学到了如何使用Spring Cloud的注册中心以及Feign服务调用服务机制
关于介绍等等的就不说明了,网上资料很多,说的也很清楚
推荐文章服务发现和注册和Eureka
一共需要四个项目,一个是用来创建注册中心的,收发机制,服务消费者和服务注册者向服务发现组件注册,服务消费者要调用的时候会从服务发现组件中进行查询;第二个是服务客户端,第三个是提供服务的,第四个是用来测试的
1. 创建注册中心
- 创建Spring Boot项目,在pom文件中引入
eureka
依赖包
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<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.RELEASE</spring-cloud.version>
</properties>
<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-server</artifactId>
</dependency>
</dependencies>
<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>
- 配置文件写入
eureka
需要的依赖
spring.application.name=eureka-server
#服务注册中心端口号
server.port=1111
#服务注册中心实例的主机名,也就是自己的IP地址,这里是我虚拟机服务器地址,因为要部署
eureka.instance.hostname=192.168.85.129
#是否向服务注册中心注册自己
eureka.client.register-with-eureka=false
#是否检索服务
eureka.client.fetch-registry=false
#服务注册中心的配置内容,指定服务注册中心的位置
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
- 在启动类上加上注册中心注解
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动项目,访问地址:自己的IP地址:端口号
,就能看到一个注册中心的界面
2. 创建服务提供者
- 创建Spring Boot项目,在pom文件中引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 在配置文件中加入所需配置
server.port=8100
# feign配置
spring.application.name=app-service
#注册中心地址
eureka.client.service-url.defaultZone = http://192.168.85.129:1111/eureka/
#注册时使用ip而不是主机名
#一般其他模块调用服务都是通过hostname来访问的,本机IP地址
eureka.instance.hostname=192.168.1.104
#指定此实例注册到eureka的ip
eureka.instance.ip-address=${eureka.instance.hostname:${spring.cloud.client.ipAddress}}
#优先使用eureka.instance.ip-address
eureka.instance.instance-id=${eureka.instance.ip-address:${spring.cloud.client.ipAddress}}:${spring.application.name}:${server.port}
#请求处理的超时时间
ribbon.ReadTimeout= 30000
#请求连接的超时时间
ribbon.ConnectTimeout= 30000
- 在启动类上加上注解
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动项目,去注册中心上查看一下自己是否注册成功,成功会看到一个表单
Application | AMIs | Availability | Zones |
---|---|---|---|
APP-SERVICE | n/a (1) | (1) | UP (1) - 192.168.85.129:app-service:8100 |
- 随便写一个Controller
@RestController
@RequestMapping("/app")
public class TextController {
@GetMapping("/hello")
public TextDTO hello(){
TextDTO textDTO = new TextDTO();
textDTO.setName("测试数据");
textDTO.setSex("测试数据");
return textDTO;
}
}
3. 创建Feign服务客户端
- 创建Spring Boot项目,引入POM文件依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<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>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
<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>
- 创建一个数据传输DTO
public class TextDTO implements Serializable{
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
- 创建一个Service接口
@FeignClient(name = "app-service", path = "/app")
public interface TextService {
@GetMapping("/hello")
TextDTO hello();
}
细心的会发现,这个Service接口上的注解中name
属性,对应的其实是刚才提供者配置文件中的spring.application.name
,path
属性对应的是提供者Controller类上的@RequestMapping("/app")
,而接口的方法就是提供者的方法,调用服务的时候,Feign就是通过这两个去注册中心查询的,找到name叫app-service
的服务,找到这个服务下的一个方法,再由注册中心把这个找到的数据通过数据传输DTO返回给消费者
注意: Get或者Post请求一定要两边同步,方法也是,另外最重要的一点,也是一个坑,这里演示的是无参的方法,调用有参的方法时,一定要在参数上加上@RequestParam
注解,并且明确name
属性,至于required
随意,不然会报错,正确示例:
@FeignClient(name = "app-service", path = "/app")
public interface TextService {
@GetMapping("/hello")
TextDTO hello(@RequestParam(name = "id", required = true) String id);
}
4. 测试
- 创建一个Spring Boot项目,pom文件引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.eureka</groupId>
<artifactId>eureka-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Edgware.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 配置文件加入所需的配置
server.port=8200
# feign配置
spring.application.name=app-demo
#注册中心地址
eureka.client.service-url.defaultZone = http://192.168.85.129:1111/eureka/
#注册时使用ip而不是主机名
#一般其他模块调用服务都是通过hostname来访问的,本机IP地址
eureka.instance.hostname=192.168.1.104
#指定此实例注册到eureka的ip
eureka.instance.ip-address=${eureka.instance.hostname:${spring.cloud.client.ipAddress}}
#优先使用eureka.instance.ip-address
eureka.instance.instance-id=${eureka.instance.ip-address:${spring.cloud.client.ipAddress}}:${spring.application.name}:${server.port}
#请求处理的超时时间
ribbon.ReadTimeout= 30000
#请求连接的超时时间
ribbon.ConnectTimeout= 30000
- 在启动类上加上注解
@EnableDiscoveryClient
//basePackages 一定要加,不然会启动报错,加的这个是Feign服务客户端包名
@EnableFeignClients(basePackages = {"com.eureka"})
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 测试调用,可以在Service实现类里,也可以在Controller里做测试
@RestController
@RequestMapping
public class DemoController {
@Resource
private TextService textService;
@GetMapping("/")
public TextDTO hello(){
return textService.hello();
}
}
启动项目,先查看有没有在注册中心中找到自己,注册成功才行,然后调用接口,之前要是配置没出错就能看到,Feign已经成功帮我们服务调服务拿到了数据
{
"name": "测试数据",
"sex": "测试数据"
}
这样的好处是,我不需要知道这个服务的表结构,也不需要他们的数据库类型,需要什么接口,让提供者开一个,然后消费者调用就好,当所有服务都在注册中心的时候,一个大的项目跑起来,不会说一个地方挂了全部都挂了,一个服务挂了,项目正常跑,只是某些功能没有了,这个时候等服务修好了再启动,就能正常使用