基于springcloud构建一个web项目

日子还很长,技术沉淀得一步步的来。先会用,然后再看实现原理

本篇博客有点长,个人觉得还是比较细致,希望对入手spring cloud的朋友能有所帮助

本来一直都想实践一下zookeeper的,但是看了一篇关于CAP的讨论之后,我还是选择Eureka作为服务发现与服务治理的软件。一个微服务项目需要的基础组件有Eureka/Config/Ribbon/Hystrix/Zuul和消息队列。不过ribbon和hystrix提供的服务可以由Feign代替。权衡之下,还是先使用ribbon加hystrix,弄明白其中的原理,在之后的项目中再去实践Feign。

服务注册中心搭建

用idea ,利用spring 官方提供的 spring initialzar 创建一个包含 EurekaServer 组件的spring boot项目。
然后在主程序中加入 @ E n a b l e E u r e k a S e r v e r @EnableEurekaServer 的注解,表示 启用 Eureka注册中心模块,本spring boot提供注册中心的服务。然后在配置中写入一下配置:

# 服务的端口号
server.port=8500
# 服务名称:在服务发现中,服务名称是一个关键信息,如果同一个服务名称有多个实例,那么,消费者在调用的时候就可以使用ribbon提供的负载均衡来调用
spring.application.name=server-register
# 是否向服务中心注册自己
eureka.client.register-with-eureka=false
# 是否需要检索服务
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
# web端访问地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

然后启动项目,访问 serviceUrl得到如下界面,现在里面的服务是空的,因为我们目前还没有向里面注册任何服务
在这里插入图片描述

根据我自己的项目需求,我创建了7个服务,商城服务、用户服务、数据库服务、商品推荐服务、交易服务、缓存服务、评价服务等 ,可能还会有消息队列的服务,数据库服务可能需要氛围 mysql的和 cockroachDB这两种,cockroachDB是分布式的,用于存储用户的浏览记录等,主要做后面的推荐做数据支撑。把创建好的服务全部定义到服务中心上面。所以再用 spring initialzar的方式创建七个服务,创建好之后,在每一个服务的主程序上面,加上注解 @ E n a b l e D i s c o v e r C l i e n t @EnableDiscoverClient 。表示启用 Eureka客户端模块。目前spring cloud无法直接支持 cockroachdb,所以建一个spring boot的默认项目,然后构建项目就可以了。在每个客户端的配置文件中,设置如下:

spring.application.name=wupingtuijian-service
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/
server.port=8608

配置完成之后,首先打开 服务中心的服务,然后逐步打开其他服务。可以在服务中心的日志文件中查看到如下信息
在这里插入图片描述

这就是其他服务向服务中心注册的情况,打开web端管理界面
在这里插入图片描述

现在,我们来将 Eureka单机 -> Eureka 集群,实现高可用性。

利用 spring.profiles.active 属性 来构建集群,idea可以同时启动多个相同的服务,只需要在edit服务中取消单例即可,如图
在这里插入图片描述

具体的做法是,新建两个配置文件,命名为 application-xxx.properties的格式,
分别填入

server.port=8501
spring.application.name=server-register
#eureka.client.register-with-eureka=false
#eureka.client.fetch-registry=false
eureka.instance.hostname=peer1
eureka.client.serviceUrl.defaultZone=http://peer2:8502/eureka/,http://localhost:8500/eureka/

反正和原配置一样,差不多改改端口之类的就行。
然后在 application.properties中设置 spring.propety.active 属性就可以了,如果不设置,默认加载 application.properties ,如果设置了,将打开设置的配置文件。于是,我创建了三个 Eureka服务,如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

然后现在修改其他所有服务的配置项,使之能够注册到注册中心集群

eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/

打开全部项目之后的效果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

服务注册中心搭好了。经过上面的配置,可以感受到改变一个地方,就需要改变大量的配置文件,为了避免这种不方便的方式,引入 spring-cloud 的 Config 服务。

引入配置服务

用 spring initialzar创建一个具有 configserver组件和 EurekaServer组件的spring boot项目,在主程序中加入 @ E n a b l e D i s c o v e r y C l i e n t @EnableDiscoveryClient @ E n a b l e C o n f i g S e r v e r @EnableConfigServer 这两个注释分别表示启用服务注册客户端组件和启用配置服务组件。为了本地开发需要,我不使用默认的git配置的方式,而采取本地文件系统的方式。具体的例子如下:

@EnableDiscoveryClient
@EnableConfigServer
@SpringBootApplication
public class ConfigmanagerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigmanagerApplication.class, args);
    }
}

application.properties

server.port=8400
spring.application.name=configmanager
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/
# 用 spring.profiles.active=native指明是用native的方式来构建的config的
spring.profiles.active=native
# 本地config的地址
spring.cloud.config.server.native.search-locations=D:/workspace/xinzu/nativeproperties

然后在其他服务中添加配置文件 bootstrap.properties

spring.application.name=user-service
server.port=8607
spring.cloud.config.uri=http://localhost:8400/
spring.cloud.config.label=master
spring.cloud.config.profile=dev
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/

对配置文件有特殊的命名要求,以我的模块为例子,应该在 D:/workspace/xinzu/nativeproperties 下面创建一个名为:
user-service-dev.properties 的配置文件,dev是标志,用 spring.cloud.config,profile 进行标记的。
在这里插入图片描述
在文件里面输入以下测试配置

nickName=minqixing

然后在 user项目中创建controller,来查询这个 nickName。项目代码如下
先来看看结构
在这里插入图片描述
config里面定义的swagger2的启动配置,关于swagger可以关注我的其他文章。

//UserApplication.class
@ServletComponentScan
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
@ComponentScan({"com.xinzu.user"})
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

}

//TestController.class
@Api(value = "测试分布式环境是否可用", tags = {"测试springcloud环境"})
@Controller
@RefreshScope
public class TestController {

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

    @ApiOperation(value = "测试 springcloud config", notes = "测试 springcloud config")
    @RequestMapping(value = Path.TESTCONFIG, method = RequestMethod.GET)
    @ResponseBody
    public TestConfigDto getNickName(){
        TestConfigDto dto = new TestConfigDto();
        dto.setCode(200);
        dto.setInfo(nickName);
        return dto;
    }
}

// TestConfigDto.class
public class TestConfigDto {
    private String info;
    private int code;

    public int getCode() {
        return code;
    }

    public String getInfo() {
        return info;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

题外话
spring boot有个很好的特性,省去了很多配置,我个人感觉可以让全民编程成为可能,哈哈。学会只要学会各种注释的使用方法就可以了。置于实现原理,才是真正的编程人员需要了解的。所以,我个人目前的打算也是先学会用,然后一步步的弄明白实现原理。

然后打开服务应该就成功了,注意,此处我省略了swagger的部分。
来看看现在Eureka中注册的服务:
在这里插入图片描述
我只打开了user-service这个服务,其他的服务现在测试就不需要打开了
下面是我的测试过程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

springcloud config主要是能够帮助同一种服务能够统一配置,配置mysql用户名之类的东西。

实现了配置服务单点,肯定也要实现高可用。下面来说说如何实现高可用的配置服务中心
我们在 Eureka中通过服务名来访问到配置服务,而不是指定 ip:port 的方式,就可以实现配置服务中心高可用化了。
修改 User服务的配置文件

spring.application.name=user-service
server.port=8607

# 配置服务相关
#spring.cloud.config.uri=http://localhost:8400/
#spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=configmanager
# 服务发现相关
eureka.client.serviceUrl.defaultZone=http://localhost:8500/eureka/,http://peer1:8501/eureka/,http://peer2:8502/eureka/

这里我注释掉了通过url访问配置中心的方式,而是采取利用 Eureka 做服务发现,利用 configmanager 这个配置服务的服务名来做访问的。其他都不用改。修改待查找的配置文件里面的nickname的值
在这里插入图片描述然后测试,结果如下
在这里插入图片描述

看起来现在咱们还是单点的,其实不然,只要使用 spring.profile.active 多创建几个configmananger的实例就可以了,目前我不这样做是因为,接下来将要介绍的是 负载均衡的内容,在没有讨论负载均衡的时候节点弄多了,效果不太好。

不过,目前我们的配置是只能加载一次,如果在运行的过程中想要改变配置,需要做以下配置
在项目中引入 actuator ,对 spring boot进行监控

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然后在配置文件中加入:

# actuator
management.server.port=9001
#修改访问路径  2.0之前默认是/   2.0默认是 /actuator  可以通过这个属性值修改
management.endpoints.web.base-path=/monitor
#开放所有页面节点  默认只开启了health、info两个节点
management.endpoints.web.exposure.include=*
#显示健康具体信息  默认不会显示详细信息
management.endpoint.health.show-details=always

这个模块的作用主要就是监听我们的spring boot项目,维护项目的运行情况,根据这样的配置,我们就可以使用 http://localhost:9001/monitor/health 来查看系统的健康状况。使用 http://localhost:9001/monitor/refresh来动态修改配置文件的更新。
测试一下
先测试一下 nickName当前的值
在这里插入图片描述
然后修改
在这里插入图片描述
使用 http://localhost:9001/monitor/refresh 的 post请求方法来动态加载更新
在这里插入图片描述
返回nickName说明nickName已经重新加载了,然后再在客户端查询nickName的值,发现已经改了
在这里插入图片描述
为了给大家做一个励志的榜样,我动态的把这句话补充完整
在这里插入图片描述

现在基本的架构已经有了,但是我们的Eureka的功能还没有用起来,除了configmanager使用了服务发现功能,其他服务都没有使用服务发现的功能,服务发现、负载均衡和服务治理是springcloud的关键之处。接下来先来说说服务发现。

在项目中加入ribbon,这是服务发现的时候,使用负载均衡的算法

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

然后,在主程序中这样写:

@ServletComponentScan
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
@ComponentScan({"com.xinzu.user"})
public class UserApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

}

@LoadBalanced 这个注解就是使用了负载均衡
然后,我们改造 pingjiaservice这个服务,改造的代码如下,实际上就是实现了一个rest接口,让userservice来调用。

@RefreshScope
@Controller
public class TestController {
    @Value("${nickName}")
    private String nickName;

    @Value("${passWord}")
    private String passWord;
    @RequestMapping(value = Path.TEST_FUWUFAXIAN, method = RequestMethod.GET)
    @ResponseBody
    public Integer getnickName(){
        int ans1 = Integer.parseInt(nickName);
        int ans2 = Integer.parseInt(passWord);
        return ans1 + ans2;
    }
}

在userservice中创建一个方法来调用上面的controller

@ApiOperation(value = "测试服务发现", notes = "测试服务发现")
    @RequestMapping(value = Path.TESTCONSUMER, method = RequestMethod.GET)
    @ResponseBody
    public TestConfigDto getPingJia(){
        TestConfigDto dto = new TestConfigDto();
        dto.setCode(400);
        dto.setInfo("没有获取到");
        try {
            String tmp = restTemplate.getForEntity("http://PINGJIA-SERVICE/testfuwufaxian", String.class).getBody();
            tmp = tmp.replace("<Integer>","");
            tmp = tmp.replace("</Integer>","");
            Integer ans1 = Integer.parseInt(tmp);
            String nickName1 = nickName + ans1;
            dto.setCode(200);
            dto.setInfo(nickName1);
        }catch (Exception e){
            System.out.println("出现了异常");
        }
        return dto;
    }

启动被调用的服务,打开三个实例
在这里插入图片描述
然后在user这个服务的swagger ui界面上进行测试,发现结果如下。

在这里插入图片描述
至于那两个加起来的数字是多少,这是一个悬念,哈哈。

由于篇幅有限,关于服务容错保护,api网管服务这里就不进行配置了。等我项目做完了再来补坑。

猜你喜欢

转载自blog.csdn.net/xielinrui123/article/details/85329790