看了别人的案例,发现spring cloud 接口调用都是用 http地址来调用,即使使用RestTemplate,我也觉得太傻,所以我决定使用Feign模式来搭建spring boot+ spring cloud微服务集群。而且实现了使用类传参数。另外还使用类接口编程的模式。下面来用最简单的代码,搭建最完善的框架。
1.为什么要用Feign模式
懒,我不想每调用一个接口,要拼url那么傻的方式。
面向对象,我希望像调用本地一个方法一样,我不想管地址,参数怎么组成拼接什么的,我只管调用
Feign是一个声明式WebService客户端
Spring Cloud 的声明式调用, 可以做到使用 HTTP 请求远程服务时能就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。
它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的Http Client 构造请求再解析返回数据。
它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。
2.项目结构
demo: 父项目
eureka: spring cloud 注册中心
consumer:消费者调用接口
producer:生产者 提供接口实现
commonApi:定义要暴露的接口,consumer只需要引用commonApi,注入接口就能调用spring cloud 提供的接口。
3.demo父项目配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/>
</parent>
<groupId>net.itxw.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>eureka</module>
<module>commonApi</module>
<module>consumer</module>
<module>producer</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<!--引入spring cloud版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RC1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--spring cloud版本很多,和spring boot 匹配也不同,所以指定官方仓库-->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
公用包都在父项目pom已经引入
4.eureka注册中心搭建
4.1 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.itxw.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>net.itxw.demo</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
</project>
4.2启动类
package net.itxw.demo.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
4.3 application.properties
spring.application.name=eureka-server
server.port=8000
eureka.client.service-url.defaultZone=http://127.0.0.1:8000/eureka/
#表示是否将自己注册在EurekaServer上,默认为true。由于当前应用就是EurekaServer,所以置为false
eureka.client.register-with-eureka=false
#表示表示是否从EurekaServer获取注册信息,默认为true。单节点不需要同步其他的EurekaServer节点的数据
eureka.client.fetch-registry=false
4.4 启动eureka注册中心
http://localhost:8000/
5.commonApi 编写接口
5.1接口
package net.itxw.demo.commonApi.api;
import net.itxw.demo.dto.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
/**
* feign接口 name对应 服务提供方的 spring.application.name
* @Author: houyong
* @Date: 2019/11/1
*/
@FeignClient(name= "producer")
public interface IUser {
/**
* 获取学生信息
* @param user
*/
@RequestMapping("/getUser")
String getUser(@RequestBody User user);
}
5.2 User 类
注意使用了lombok,需要使用lombok插件
package net.itxw.demo.commonApi.dto;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* 学生信息
* @Author: houyong
* @Date: 2019/11/1
*/
@Getter
@Setter
public class User implements Serializable {
private String id;
private String name;
private String schoolId;
private String schoolName;
private String classId;
private String className;
}
5.3 pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.itxw.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>net.itxw.demo</groupId>
<artifactId>commonApi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--不需要使用spring boot打启动包,否则引用失败,打普通jar包就可以-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
6.producer项目 (实现接口)
6.1 pom (引入 commonApi项目)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.itxw.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>net.itxw.demo</groupId>
<artifactId>producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<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>
<dependency>
<groupId>net.itxw.demo</groupId>
<artifactId>commonApi</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</project>
6.2 实现接口IUser
package net.itxw.demo.producer.service.impl;
import net.itxw.demo.commonApi.api.IUser;
import net.itxw.demo.commonApi.dto.User;
/**
* RestController表示这个实现是要暴露接口的
* @Author: houyong
* @Date: 2019/11/4
*/
@Slf4j
@RestController
public class UserImpl implements IUser {
@Override
public String getUser(User user){
log.warn("我producer被其他服务调用了");
return "我是producer,您的名字是:"+user.getName();
}
}
6.3 application.properties
spring.application.name=producer
server.port=8001
#允许多个同名的@FeignClient 同时存在
spring.main.allow-bean-definition-overriding=true
#调用接口超时设置
ribbon.ReadTimeout=60000
ribbon.ConnectTimeout=60000
ribbon.MaxAutoRetries=0
ribbon.MaxAutoRetriesNextServer=1
eureka.client.service-url.defaultZone=http://127.0.0.1:8000/eureka/
6.4 启动类
package net.itxw.demo.producer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
//能扫描到整个项目的Feign注解
@EnableFeignClients(basePackages = "net.itxw.demo")
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class, args);
}
}
6.5 启动producer
启动成功后 在 eureka界面下的 Instances currently registered with Eureka 可以看到producer项目,已经注册进来
7.consumer项目 (调用接口)
7.1 pom 引用commonApi
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.itxw.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>net.itxw.demo</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<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>
<dependency>
<groupId>net.itxw.demo</groupId>
<artifactId>commonApi</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</project>
7.2 controller调用IUser接口
package net.itxw.demo.consumer.action;
import net.itxw.demo.commonApi.api.IUser;
import net.itxw.demo.commonApi.dto.User;
@RestController
public class TestController {
@Autowired
private IUser iuser;
@RequestMapping("/test")
public String test() {
User user=new User();
user.setName("IT学问网");
return iuser.getUser(user);
}
}
7.3 启动类
package net.itxw.demo.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
//能扫描到整个项目的Feign注解
@EnableFeignClients(basePackages = "net.itxw.demo")
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication .class, args);
}
}
7.4 application.properties
spring.application.name=consumer
server.port=8002
#允许多个同名的@FeignClient 同时存在
spring.main.allow-bean-definition-overriding=true
#调用接口超时设置
ribbon.ReadTimeout=60000
ribbon.ConnectTimeout=60000
ribbon.MaxAutoRetries=0
ribbon.MaxAutoRetriesNextServer=1
eureka.client.service-url.defaultZone=http://127.0.0.1:8000/eureka/
7.5 启动consumer
启动成功后 在 eureka界面下的 Instances currently registered with Eureka 可以看到consumer项目,已经注册进来
8.测试
浏览器访问:localhost:8002/test
我使用的postman:
OK,很顺利,spring boot + spring cloud + Feign+接口编程模式 的框架搭建成功!