步骤 2 : 模仿和排错 步骤 3 : 模拟回测微服务 步骤 4 : 拓扑图点亮 步骤 5 : 创建子模块 步骤 6 : pom.xml 步骤 7 : application.yml 步骤 8 : IndexData.java 步骤 9 : IndexDataClient 步骤 10 : IndexDataClientFeignHystrix 步骤 11 : BackTestService 步骤 12 : BackTestController 步骤 13 : TrendTradingBackTestServiceApplication 步骤 14 : 测试
老规矩,先下载右上角的可运行项目,配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。
先启动 EurekaServerApplication 然后启动 IndexDataApplication 最后启动 TrendTradingBackTestServiceApplication 注: 记得运行redis-server.exe 以启动 redis 服务器 访问地址: http://127.0.0.1:8051/simulate/000300
在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。
模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较正确答案 ( 可运行项目 ) 和自己的代码,来定位问题所在。 采用这种方式,学习有效果,排错有效率,可以较为明显地提升学习速度,跨过学习路上的各个槛。 推荐使用diffmerge软件,进行文件夹比较。把你自己做的项目文件夹,和我的可运行项目文件夹进行比较。 这个软件很牛逼的,可以知道文件夹里哪两个文件不对,并且很明显地标记出来 这里提供了绿色安装和使用教程:diffmerge 下载和使用教程
在模拟回测视图那里需要很多的数据,这些数据都是从这个模拟回测服务里产生的。 虽然现在看上去只有单纯的指数原数据,但是随着业务的增加,功能的迭代,会有越来越丰富的数据产生出来啦。
创建子模块: trend-trading-backtest-service
比起以前的多了一个 spring-cloud-starter-openfeign jar 用于启动 Feign 方式访问其他微服务。
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.how2j.trend</groupId>
<artifactId>trendParentProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>trend-trading-backtest-service</artifactId>
<dependencies>
<!-- springboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 断路器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
</project>
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: trend-trading-backtest-service
feign.hystrix.enabled: true
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ spring: application: name: trend-trading-backtest-service feign.hystrix.enabled: true package cn.how2j.trend.pojo;
public class IndexData {
String date;
float closePoint;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public float getClosePoint() {
return closePoint;
}
public void setClosePoint(float closePoint) {
this.closePoint = closePoint;
}
}
package cn.how2j.trend.pojo; public class IndexData { String date; float closePoint; public String getDate() { return date; } public void setDate(String date) { this.date = date; } public float getClosePoint() { return closePoint; } public void setClosePoint(float closePoint) { this.closePoint = closePoint; } }
使用 feign 模式从 INDEX-DATA-SERVICE 微服务获取数据。
与之前使用的 RestTemplate 方式不同,这里是声明式的。 fallback = IndexDataClientFeignHystrix.class) 这句话表示访问不了的时候,就去找 IndexDataClientFeignHystrix 要数据了。 package cn.how2j.trend.client;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import cn.how2j.trend.pojo.IndexData;
@FeignClient(value = "INDEX-DATA-SERVICE",fallback = IndexDataClientFeignHystrix.class)
public interface IndexDataClient {
@GetMapping("/data/{code}")
public List<IndexData> getIndexData(@PathVariable("code") String code);
}
package cn.how2j.trend.client; import java.util.List; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import cn.how2j.trend.pojo.IndexData; @FeignClient(value = "INDEX-DATA-SERVICE",fallback = IndexDataClientFeignHystrix.class) public interface IndexDataClient { @GetMapping("/data/{code}") public List<IndexData> getIndexData(@PathVariable("code") String code); }
IndexDataClientFeignHystrix 实现了 IndexDataClient,所以就提供了对应的方法,当熔断发生的时候,对应的方法就会被调用了。
这里的方法就是指如果 INDEX-DATA-SERVICE 不可用或者不可访问,就会返回个 0000-00-00 出去啦。 package cn.how2j.trend.client;
import java.util.List;
import org.springframework.stereotype.Component;
import cn.how2j.trend.pojo.IndexData;
import cn.hutool.core.collection.CollectionUtil;
@Component
public class IndexDataClientFeignHystrix implements IndexDataClient {
@Override
public List<IndexData> getIndexData(String code) {
IndexData indexData = new IndexData();
indexData.setClosePoint(0);
indexData.setDate("0000-00-00");
return CollectionUtil.toList(indexData);
}
}
这就是用于提供所有模拟回测数据的微服务了。 当然,现在比较简单,随着业务的增加和功能的迭代,就会越来愈丰富起来了。
站长用这种由浅入深的方式来把这个复杂的服务逐渐发展起来,大家通过这个过程参与进来会更加容易理解和消化。 package cn.how2j.trend.service;
import cn.how2j.trend.client.IndexDataClient;
import cn.how2j.trend.pojo.IndexData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class BackTestService {
@Autowired IndexDataClient indexDataClient;
public List<IndexData> listIndexData(String code){
List<IndexData> result = indexDataClient.getIndexData(code);
Collections.reverse(result);
for (IndexData indexData : result) {
System.out.println(indexData.getDate());
}
return result;
}
}
控制器,返回的数据是放在一个 Map 里的,而目前的key是 indexDatas。
因为将来会返回各种各样的数据,通过这种方式才好区分不同的数据。 package cn.how2j.trend.web;
import cn.how2j.trend.pojo.IndexData;
import cn.how2j.trend.service.BackTestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class BackTestController {
@Autowired BackTestService backTestService;
@GetMapping("/simulate/{code}")
@CrossOrigin
public Map<String,Object> backTest(@PathVariable("code") String code) throws Exception {
List<IndexData> allIndexDatas = backTestService.listIndexData(code);
Map<String,Object> result = new HashMap<>();
result.put("indexDatas", allIndexDatas);
return result;
}
}
启动类,注意一下:
@EnableFeignClients 这个注解用与启动 Feign 方式。 package cn.how2j.trend;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class TrendTradingBackTestServiceApplication {
public static void main(String[] args) {
int port = 0;
int defaultPort = 8051;
int eurekaServerPort = 8761;
if(NetUtil.isUsableLocalPort(eurekaServerPort)) {
System.err.printf("检查到端口%d 未启用,判断 eureka 服务器没有启动,本服务无法使用,故退出%n", eurekaServerPort );
System.exit(1);
}
if(null!=args && 0!=args.length) {
for (String arg : args) {
if(arg.startsWith("port=")) {
String strPort= StrUtil.subAfter(arg, "port=", true);
if(NumberUtil.isNumber(strPort)) {
port = Convert.toInt(strPort);
}
}
}
}
if(0==port) {
Future<Integer> future = ThreadUtil.execAsync(() ->{
int p = 0;
System.out.printf("请于5秒钟内输入端口号, 推荐 %d ,超过5秒将默认使用 %d ",defaultPort,defaultPort);
Scanner scanner = new Scanner(System.in);
while(true) {
String strPort = scanner.nextLine();
if(!NumberUtil.isInteger(strPort)) {
System.err.println("只能是数字");
continue;
}
else {
p = Convert.toInt(strPort);
scanner.close();
break;
}
}
return p;
});
try{
port=future.get(5,TimeUnit.SECONDS);
}
catch (InterruptedException | ExecutionException | TimeoutException e){
port = defaultPort;
}
}
if(!NetUtil.isUsableLocalPort(port)) {
System.err.printf("端口%d被占用了,无法启动%n", port );
System.exit(1);
}
new SpringApplicationBuilder(TrendTradingBackTestServiceApplication.class).properties("server.port=" + port).run(args);
}
}
先启动 EurekaServerApplication
然后启动 IndexDataApplication 最后启动 TrendTradingBackTestServiceApplication 访问地址: http://127.0.0.1:8051/simulate/000300
HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。
提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
|