springcloud项目

前言

springcloud搭建记录

一、建立父项目

1、新建mavem quicklystart项目,为父项目。

2、删除src目录,把项目iml文件放到.idea下。

 修改.idea下的workspace.xml,添加以下代码,以便于使用services,运行多服务:

<component name="RunDashboard">
   <option name="configurationTypes">
     <set>
       <option value="SpringBootApplicationConfigurationType" />
     </set>
   </option>
 </component>

3、pom引入依赖(自name之下,全部替换):

<!-- 父项目的打包方式 -->
<packaging>pom</packaging>

<!-- 使用springboot2.0.3版本 -->
<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.0.3.RELEASE</version>
 <relativePath/>
</parent>

<!-- 使用springcloud的finchley版本 -->
<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>
 <!-- 测试类,包含了junit -->
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
 </dependency>

 <!-- 工具类 -->
 <dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>4.3.1</version>
 </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

1、new一个module,使用maven,不用任何模板。

2、引入pom依赖:

   <dependencies>
        <!-- 构建服务注册中心 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
   </dependencies>

3、创建启动类(注意是properties)

@SpringBootApplication //表示它是一个启动类
@EnableEurekaServer //表示它是注册中的  服务器
public class EurekaServer {
 public static void main(String[] args) {
     //判断端口号是否被占用
     int port=8761; //这个是注册中心 服务器的默认端口。
     if(!NetUtil.isUsableLocalPort(port)){
         System.err.printf("注册中心服务器端口%d已被占用,无法启动",port);//打印端口不可用信息
         System.exit(1); //退出控制台
     }
     //使用springapplicationbuilder启动应用(并设置启动的端口号)
     new SpringApplicationBuilder(EurekaServer.class).properties("server.port="+port).run(args);
 }
}

4、编写application.yml配置文件

#配置这个微服务的名称
spring:
  application:
    name: eureka-server

#配置eureka server注册中心服务的相关信息
#hostname(主机名称),register-with-eureka(不注册到服务器,因为它本身就是服务器),
#fetch-registry(是否获取注册信息,为服务器不注册),
#service-url(自己作为服务器公布出来的地址,后续的微服务注册到服务中心,就是要用这个地址)
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

三、创建子项目:第三方数据(看需求,数据在第三方或数据库)

1、pom引入依赖

<dependencies>
        <!--spring mvc。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>
    </dependencies>

2、启动类

@SpringBootApplication
@EnableEurekaClient //注册为微服务
public class ThirdPartData {
    public static void main(String[] args) {
        int eurekaServerPort=8761;
        int port=8090;
        //判断eureka是否已经启动
        if(NetUtil.isUsableLocalPort(eurekaServerPort)){
            System.err.printf("端口%d未启用,判断是eureka-server服务未启动,本服务无法使用,故退出%n",eurekaServerPort);
            System.exit(1);
        }

        //看启动是否带了参数,带参则使用此参数(端口号),使得在启动时,使用不同参数就可以了。
        if(args!=null && args.length!=0){
            for (String arg : args) {
                if(arg.startsWith("port=")) {
                    String strPort= StrUtil.subAfter(arg, "port=", true);
                    if(NumberUtil.isNumber(strPort)) {
                        port = Convert.toInt(strPort);
                    }
                }
            }
        }

        //判断启动端口是否可用
        if(!NetUtil.isUsableLocalPort(port)) {
            System.err.printf("端口%d被占用了,无法启动%n", port );
            System.exit(1);
        }
        //使用springapplicationbuilder启动应用
        new SpringApplicationBuilder(ThirdPartData.class).properties("server.port=" + port).run(args);
    }

}

3、pom

spring:
  application:
    name: third-part-data
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

四、创建子项目:数据采集和存储

1、RestTemple数据采集

(1)引入依赖

<!-- 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>

(2)service中获取数据

	public List<Index> fetch_data_from_third(){
        List<Map> maps_data=restTemplate.getForObject("http://127.0.0.1:8090/datas/codes.json",List.class);
        return transfromMapToIndex(maps_data);
    }
     public List<Index> transfromMapToIndex(List<Map> thirdMap){
        List<Index> lists=new ArrayList<>();
        for(Map map:thirdMap){
            Index index=new Index();
            String code=map.get("code").toString();
            String name=map.get("name").toString();
            index.setCode(code);
            index.setName(name);
            lists.add(index);
        }
        return lists;
    }

(3)启动类注入RestTemple的bean

/注入resttemple
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

(4)配置文件

spring:
  application:
    name: index-collection-store-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

2、断路器:当采集数据为空,或采集出错。

(1)引入pom依赖

<!-- 断路器,调用的微服务,不可用时的处理 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

(2)启动类开启断路器注解

@EnableHystrix //启用断路器
public class CollectionWithStoreData {

(3)service采集数据的方法使用熔断注解,编写熔断方法(返回值和参数须一致)

 @HystrixCommand(fallbackMethod = "third_part_not_connected")
    public List<Index> fetch_data_from_third(){
        List<Map> maps_data=restTemplate.getForObject("http://127.0.0.1:8090/datas/codes.json",List.class);
        return transfromMapToIndex(maps_data);
    }
    public List<Index> thrid_part_no_connect(){
        System.out.println("第三方数据未连接,断路器启用");
        Index index=new Index("0000","无效代码");
        return CollectionUtil.toList(index);
    }

3、数据缓存:redis查询使用

(1)下载redis,并启动服务端。下载redis desk manager启动服务端,用于查看数据。
(2)pom引入依赖

 <!-- redis -->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis</artifactId>
       </dependency>  

(3)启动类使用启动缓存注解

@EnableCaching //开启缓存,使用redis
public class CollectionWithStoreData {
    public static void main(String[] args) {  

(4)services使用缓存注解,将数据保存到redis。

@Service
@CacheConfig(cacheNames = "indexes") //存储到redis的缓存名称是indexes
public class IndexService {  
 	
 	//保存到redis,方法返回的所有数据都会被保存
    @Cacheable(key="'all_codes'") //保存到redis使用的key值,是all_codes
     public List<Index> fetch_data_from_third(){
     }

(5)编写redis的配置类

/*
redis的配置类
 */
@Configuration
@EnableRedisRepositories
public class RedisConfig {
    private Duration timeToLive = Duration.ZERO;
    public void setTimeToLive(Duration timeToLive) {
        this.timeToLive = timeToLive;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

4、redis中数据的刷新

(1)编写工具类,获得一个service的对象(一个在使用中,去再获取一个)

/*
工具类,用于获取Service
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    private SpringContextUtil() {
        System.out.println("SpringContextUtil()");
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("applicationContext:"+applicationContext);
        SpringContextUtil.applicationContext = applicationContext;
    }
}

(2)数据刷新:思路,先清空,再去保存

/*
redis数据保存说明:
fresh刷新方法:先从另一个微服务获得对应地址参数code的数据,
——》然后将code和得到的所有数据 保存到一个map对象中
——》如果redis中有这个map对象,删除
——》使用store方法将这个map对象更新到redis中
 */
@Service
@CacheConfig(cacheNames = "index_datas") //在redis中的分组
public class IndexDataService {
    @Autowired
    RestTemplate restTemplate;
    Map<String,List<IndexData>> allIndexDataList=new HashMap<>();//存放所有的指数数据,使用

    //三方获取指数数据
    public List<IndexData> fetch_third_indexData(String code){
        List<Map> mapList=restTemplate.getForObject("http://127.0.0.1:8090/datas/"+code+".json",List.class);
        /*JSONArray jsonArray=new JSONArray();//转换的中间量
        jsonArray.addAll(mapList);
        List<IndexData> list=jsonArray.toJavaList(IndexData.class);*/
        return transformMapToT(mapList);
    }
    //数据转换
    public List<IndexData> transformMapToT(List<Map> maps){
        List<IndexData> indexDataList=new ArrayList<>();
        for(Map map:maps){
            IndexData indexData=new IndexData();
            String date=map.get("date").toString();
            float  closePoint= Convert.toFloat(map.get("closePoint"));
            indexData.setDate(date);
            indexData.setClosePoint(closePoint);
            indexDataList.add(indexData);
        }
        return indexDataList;
    }
    //保存数据。对应key。更新
    @CachePut(key = "'indexdata-code-'+ #p0")//前缀+参数
    public List<IndexData> store(String code){
        return allIndexDataList.get(code);//将code对应的所有数据保存redis
    }

    //获取数据
    @Cacheable(key = "'indexdata-code-'+ #p0")
    public List<IndexData> get(String code){
        return CollUtil.toList(); //从缓存中拿到数据
    }

    //清空redis分组index_datas中对应键值对的数据缓存数据
    @CacheEvict(key = "'indexdata-code-'+ #p0")
    public void remove(String code){

    }

    //刷新数据
    @HystrixCommand(fallbackMethod = "third_part_no_connect")
    public List<IndexData> fresh(String code){
        //通过地址拿到对应指数的数据
        List<IndexData> indexDataCode=fetch_third_indexData(code);//拿到对应code的数据
        allIndexDataList.put(code,indexDataCode);//存入一个code对应的所有数据
        System.out.println("code"+code);
        System.out.println("数据长度:"+allIndexDataList.get(code).size());

        IndexDataService indexDataService= SpringContextUtil.getBean(IndexDataService.class);
        indexDataService.remove(code);
        return indexDataService.store(code);
    }

    //熔断方法需要与被注解方法,有一致类型的参数和返回值
    public List<IndexData> third_part_no_connect(String code){
        System.out.println("third_part_no_connect");
        IndexData index= new IndexData();
        index.setClosePoint(0);
        index.setDate("n/a");
        return CollectionUtil.toList(index);
    }
}

5、定时器:定时去刷新redis中的数据(作用:定时任务)

(1)引入pom依赖

<!-- 定时器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

(2)编写任务类,指明=定时执行方法

public class DataSynJob extends QuartzJobBean {

    @Autowired
    IndexDataService indexDataService;

    @Autowired
    IndexService indexService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("定时启动:"+ DateUtil.now());
        List<Index> indexList=indexService.fresh();//刷新指数数据
        for(Index index:indexList){
            indexDataService.fresh(index.getCode());
        }
        System.out.println("定时器结束:"+DateUtil.now());
    }
}

(3)编写定时器配置,指明启动的任务类和时间

/*
定时器配置
 */
@Configuration
public class QuartzConfig {
    //时间。类常量
    private static final int interval=8;

    //注入bean
    @Bean
    public JobDetail weatherDataSyncJobDetail() {
        return JobBuilder.newJob(DataSynJob.class).withIdentity("dataSynJob")
                .storeDurably().build();
    }

    @Bean
    public Trigger weatherDataSyncTrigger() {
        SimpleScheduleBuilder schedBuilder = SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInHours(interval).repeatForever();
                //.withIntervalInMinutes(interval).repeatForever(); //使用时间间隔--分钟,小时

        return TriggerBuilder.newTrigger().forJob(weatherDataSyncJobDetail())
                .withIdentity("indexDataSyncTrigger").withSchedule(schedBuilder).build();
    }
}

五、创建子项目:指数代码获取集群

1、引入pom

 <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>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
 
    </dependencies>

2、配置yml

spring:
 application:
   name: index-codes-service
eureka:
 client:
   serviceUrl:
     defaultZone: http://localhost:8761/eureka/

3、配置类(获取当前端口号、redis配置类)

(1)获取当前端口

@Component
public class IpConfiguration implements ApplicationListener<WebServerInitializedEvent> {
 
    private int serverPort;
 
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.serverPort = event.getWebServer().getPort();
    }
 
    public int getPort() {
        return this.serverPort;
    }
}

(2)redis配置类

@Configuration
@ConfigurationProperties(prefix = "spring.cache.redis")
public class RedisCacheConfig {
  
    private Duration timeToLive = Duration.ZERO;
    public void setTimeToLive(Duration timeToLive) {
        this.timeToLive = timeToLive;
    }
 
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
         
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
  
        // 配置序列化(解决乱码的问题)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(timeToLive)
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
  
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

4、实体类、service、controller

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Index implements Serializable {
    String code;
    String name;
}
@Service
@CacheConfig(cacheNames = "indexes")
public class IndexService {
    List<Index> indexList;

    //从redis中去获取数据
    @Cacheable(key = "'all_codes'")
    public List<Index> get(){
        Index index=new Index();
        index.setName("无效指数");
        index.setCode("0/0");
        return CollUtil.toList(index);
    }
}
@RestController
@CrossOrigin //允许跨域
public class IndexController {
    @Autowired
    IndexService indexService;

    @Autowired
    IpConfig ipConfig;

    @GetMapping("/codes")
    public List<Index> get(){
        System.out.println("当前的端口号:"+ipConfig.getPort());
        return indexService.get();
    }
}

六、创建子项目:指数数据获取集群(同五)

七、创建网关服务zuul

1、引入pom

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

2、配置文件配置

zuul:
  routes:
    api-a:
      path: /api-codes/**
      serviceId: INDEX-CODES-SERVICE

3、启动类开启端口

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableDiscoveryClient
public class IndexZuulServiceApplication {
//  http://127.0.0.1:8031/api-codes/codes
    public static void main(String[] args) {

八、模拟回测服务模块 (为回测视图提供数据)

1、引入pom(使用feign从指数数据服务获取数据)

 <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>

2、配置文件开启feign

eureka:
client:
  serviceUrl:
    defaultZone: http://localhost:8761/eureka/
spring:
application:
  name:  trend-trading-backtest-service

feign.hystrix.enabled: true 

3、创建指数实体类(略),编写feign客户端端口(从指数服务获取数据)和实现类(熔断)

@FeignClient(value = "INDEX-DATA-SERVICE",fallback = IndexDataClientFeignHystrix.class)
public interface IndexDataClient {
    @GetMapping("/data/{code}")
    public List<IndexData> getIndexData(@PathVariable("code") String code);
}
@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);
    }

4、service调用客户端获取数据,controller调用service

5、启动类开启feign,调用服务(发现客户端)

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class TrendTradingBackTestServiceApplication {

6、将这个服务通过网关去映射

api-b:
      path: /api-backtest/**
      serviceId: TREND-TRADING-BACKTEST-SERVICE

九、模拟回测视图(vue、charj、thymeleaf)—略

十、周边服务(与业务功能并无关系)

1、服务链路追踪

(1)父项目piom下添加依赖

 <!--zipkin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

(2)每个微服务aplication配置添加zipkin的地址

  spring:
  		zipkin:
	    	base-url: http://localhost:941

(3)每个微服务的启动类增加simpler,表示一直取样。

  @Bean
    public Sampler defaultSampler() {
        return Sampler.ALWAYS_SAMPLE;
    }	  

(4)cmd启动链路服务器

java -jar zipkin-server-2.10.1-exec.jar

注:后面步骤配置了消息总线rabbitmq后,启动命令,要带上参数,才能看到配置客户端服务的链路

java -jar zipkin-server-2.10.1-exec.jar --zipkin.collector.rabbitmq.addresses=localhost

(5)启动每一个微服务,访问:http://localhost:9411/zipkin/dependency/,查看微服务调用。

2、配置服务器

(1)新建模块(配置服务器模块)
(2)引入依赖

 <dependencies>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-config-server</artifactId>
       </dependency>

   </dependencies>

(3)启动类开启配置服务

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableConfigServer
public class ConfigServer {
}

(4)在github上新建和编写配置文件
注意:这里编写的配置文件的文件名前缀必须于[步骤3]配置客户端的spring-application-name一致,否则报错。

(5)配置文件配置git地址和所属目录

spring:
  application:
    name: index-config-server
  cloud:
    config:
      label: master
      server:
       git:
         #git地址
         uri: https://github.com/zhuyanxue/sudyconfig.git
         #文件所属目录
         search-paths: qinyan
         #git使用main,而不是master
         default-label: main

(6)访问地址(key值和文件后缀dev):http://localhost:8060/version/dev

3、配置客户端(与配置服务器合用)

(1)在要使用git上配置的微服务添加pom依赖

 <!--config-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

(2)resource目录下添加bootstrap.yml(先于appication.yml启动,通常是不变的系统信息)配置文件。
注意:

spring:
  application:
  #这里的名称与github上的文件名前缀要一致对应。github文件名只能是:trend-trading-backtest-view-dev.properties
    name: trend-trading-backtest-view

  bootstrap.yml

spring:
  cloud:
    config:
      label: main
      profile: dev
      discovery:
        enabled:  true
        #配置服务器的eureka名称
        serviceId:  index-config-server

#从application移到这里做配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

(3)类中使用@Value("${version}")获取配置信息,进行一些操作。

@Value("${version}")
private String version;

4、消息总线bus (实时刷新:不需要重启微服务,只要git上信息改变,页面上的信息也就会改变)

(1)安装rabbitmq,启动rabiitmq。
cmd命令:

net start RabbitMQ

访问:http://127.0.0.1:15672/,即可看到管理界面。
(2)配置客户端引入依赖

<!-- 用于访问路径:/actuator/bus-refresh -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- 支持mq -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

(3)bootstrap新增bus配置和rabbitmq配置

spring:
  cloud:
    config:
      label: main
      profile: dev
      discovery:
        enabled:  true
        #配置服务器的eureka名称
        serviceId:  index-config-server
    #消息总线bus配置,
    bus:
      enabled: true
      trace:
        enabled: true
#rabbitmq配置
rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest
#从application移到这里做配置
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/        

(4)application新增management配置,这样才能访问 /actuator/bus-refresh

#跨域,访问 /actuator/bus-refresh,
management:
  endpoints:
    web:
      exposure:
        include: "*"
      cors:
        allowed-origins: "*"
        allowed-methods: "*"

(5)使用配置文件的类(如控制类,使用注解允许刷新)

@Controller
@RefreshScope
public class ViewController {
    @Value("${version}")
   private String version;

(6)新增一个工具类,使用post方式访问:http://localhost:8041/actuator/bus-refresh(端口号与配置客户端端口号一致)。(不用会有405错误,get访问不到)

//这个工具类,实际部署时,是放在本地运行,修改了git之后,就可以运行此工具类,刷新配置
public class FreshConfig {
    public static void main(String[] args) {
        HashMap<String,String> headers =new HashMap<>();
        headers.put("Content-Type", "application/json; charset=utf-8");
        System.out.println("因为要去git获取,还要刷新config-server, 会比较卡,所以一般会要好几秒才能完成,请耐心等待");

        String result = HttpUtil.createPost("http://localhost:8041/actuator/bus-refresh").addHeaders(headers).execute().body();
        System.out.println("result:"+result);
        System.out.println("refresh 完成");
    }
}

5、断路器(RestTemple和feign两种方式实现)

6、断路器监控(监控数据什么时候可用,什么时候不可用。配合使用断路器的微服务使用)

(1)新建断路器监控模块
(2)pom引入依赖

<dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
       </dependency>

(3)启动类开启监控注解

@SpringBootApplication
@EnableHystrixDashboard
public class IndexHystrixDashboardApplication {
    public static void main(String[] args) {
        int port = 8070;        

(4)配置文件,配置服务名

spring:
  application:
    name: hystrix-dashboard  

(5)使用断路器的微服务(例如:从数据服务获取数据的视图服务),启动类开启注解,将信息共享给监控中心。

@EnableFeignClients
//共享信息给监控中心
@EnableCircuitBreaker
public class ProductViewServiceFeignApplication {  

(6)测试类(测试监控中心)【实际项目,发布时,可用去掉。这里只是为了查看效果,不断进行数据访问】

public class AccessViewService {
 
    public static void main(String[] args) {
         
        while(true) {
            ThreadUtil.sleep(1000);
            try {
                String html= HttpUtil.get("http://127.0.0.1:8012/products");
                System.out.println("html length:" + html.length());
            }
            catch(Exception e) {
                System.err.println(e.getMessage());
            }
 
        }
         
    }
}

(7)启动项目
访问http://localhost:8020/hystrix——》输入地址http://localhost:8012/actuator/hystrix.stream
——》monitor stream ,就可查看监控信息。

7、断路器聚合监控(断路器监控只是对一个微服务实例;当微服务成为集群时,需要使用断路器聚合监控将多个实例聚合到turbine中)

(1)创建聚合监控模块
(2)引入依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
        </dependency>

(3)启动类是turbine注解

@SpringBootApplication
@EnableTurbine
public class ProductServiceTurbineApplication {  

(4)配置文件application.yml配置要监控的微服务(会发生熔断的微服务集群)

spring:
  application.name: turbine
turbine:
  aggregator:
    clusterConfig: default  
  appConfig: product-view-service-feign  ### 配置Eureka中的serviceId列表,表明监控哪些服务
  clusterNameExpression: new String("default")
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/      

(5)编写测试类访问

public class AccessViewService {
  
    public static void main(String[] args) {
          
        while(true) {
            ThreadUtil.sleep(1000);
            access(8012);
            access(8013);
        }
          
    }
  
    public static void access(int port) {
        try {
            String html= HttpUtil.get(String.format("http://127.0.0.1:%d/products",port));
            System.out.printf("%d 地址的视图服务访问成功,返回大小是 %d%n" ,port, html.length());
        }
        catch(Exception e) {
            System.err.printf("%d 地址的视图服务无法访问%n",port);
        }
    }
}

(6)启动项目:访问http://localhost:8070/hystrix,输入参数http://localhost:8080/turbine.stream,即可查看聚合监控效果。

End、结尾

1、端口号总结:

(1)微服务

 
eureka-server: 8761
product-data-service: 8001,8002,8003
product-view-service-ribbon: 8010
product-view-service-feign: 8012, 8013, 8014
hystrix-dashboard: 8020
turbine: 8021
config-server: 8030
zuul: 8040

(2)第三方

zipkin:9411
rabbitMQ: 5672

2、项目导图


在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值