一. 启动Eureka Server集群
准备二台云主机,二个eureka server服务互相进行复制。准备二个application.yml配置,分别如下:
application-server1.yml
spring:
application:
name: eurekaServer1
server:
port: 8761
eureka:
instance:
hostname: eurekaServer1
appname: eurekaServer1
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://eurekaServer2:${server.port}/eureka/
application-server2.yml
spring:
application:
name: eurekaServer2
server:
port: 8761
eureka:
instance:
hostname: eurekaServer2
appname: eurekaServer2
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://eurekaServer1:${server.port}/eureka/
启动时利用springboot 的 profile机制分别进行启动:java -jar eureka-server.jar --spring.profiles.active={profile名} 方式让不同的 application-{profile名}.yml文件生效
二. 启动服务Provider (此处以发送手机验证码的服务为例)
简单提供一个Controller
@RestController @RequestMapping(value = "/ecshop/api/1.0") public class SmsController { @Autowired private SmsUtil smsUtil; @RequestMapping(value = "sendMobileCode", method = RequestMethod.GET) public Result sendMobileCode(String mobile, String bizType) { smsUtil.sentMobileCode(mobile, bizType); Result result = new Result(true, "0", "手机验证码发送成功", false); return result; } }
需要pom中添加
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
配置文件 application.yml
spring:
application:
name: commonservices //此处必须要配置,否则会导致ribbon找不到服务
http:
encoding:
force: true
charset: UTF-8
enabled: true
server:
tomcat:
uri-encoding: UTF-8
port: 1001
eureka:
instance:
appname: commonservices
client:
serviceUrl:
defaultZone: http://eurekaServer1:8761/eureka/,http://eurekaServer2:8761/eureka/
启动类
@SpringBootApplication @EnableDiscoveryClient public class CommonsApplication { public static void main( String[] args ) { SpringApplication.run(CommonsApplication.class, args) ; } }
三. 设置服务调用接口
@FeignClient("commonservices") //注解中应填写相应服务的spring.application.name对应的值 public interface SmsApi { @RequestMapping(value = "/ecshop/api/1.0/sendMobileCode", method = RequestMethod.GET) //访问路径要和真实服务的路径一致 public Result sendMobileCode(@RequestParam("mobile") String mobile, @RequestParam("bizType") String bizType) ; //参数前一定要有@RequestParam注解 }
注:1. 返回类型 Result 一定要有无参的构造函数,否则 Feign 会 无法 根据 传递 过来 的 JSON 字符串 转换 为 User 对象, 从而 抛出 异常, 造成 调用 不成功。
2. 如果请求参数是个对象,则使用@RequestBody注解,例:User register(@RequestBody User user);
四. 启动服务Consumer (假设现在有一个注册服务需要调用短信服务)
RegistService代码
@Service public class RegistService { @Autowired private SmsApi smsApi ; //注入服务接口,实际注入的是OpenFeign框架通过字节码生成的包装类对象 public void sendSmsCode(String mobile) { try { Result result = smsApi.sendMobileCode(mobile, bizType) ; //调用服务 } catch (AttemptLimitException e) { throw new UserCenterException(errorObj); } } }
RegistController代码
@RestController @RequestMapping(value = "/ecshop/api/1.0/registry") public class RegistController { @Autowired private RegistService registService; // 发送验证码 @RequestMapping(value = "/sendSmsCode", method = RequestMethod.GET) public Result sendSmsCode(String mobile) { //核对手机格式是否正确 RegistUtils.checkMobileFormat(mobile); registService.sendSmsCode(mobile); return new Result(true, "R004", "发送验证码成功~", false); }
}
启动类
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
配置文件
spring: application: name: registerservices server: tomcat: uri-encoding: UTF-8 port: 1001 eureka: instance: appname: registerservices prefer-ip-address: true client: serviceUrl: defaultZone: http://eurekaServer1:8761/eureka/,http://eurekaServer2:8761/eureka/ //此处也可以只注册一个注册中心
五. 测试
1. 通过浏览器访问 http://xxx/ecshop/api/1.0/registry
2.通过单元测试方式
@RunWith(SpringRunner.class) @SpringBootTest(classes = App.class) public class RegistServiceTest { @Autowired private RegistService registService ; @Test public void sendSmsCode() { String mobile = "xxxx7222222" ; registService.sendSmsCode(mobile); }