spring cloud微服务架构(一):服务的注册与相互调用

1 写在前面

之前在做的业务系统,大概有10多个大业务模块,每个大业务模块下面差多有接近20个小业务模块,代码量惊人。

这还不是重点,因为我司是做定制化软件的,根据客户具体的业务需求开发不同的系统,每当要开发一个新系统前,就从已经开发过的系统中选择一个业务接近的系统拷贝一份,然后进行修改。假如A客户需要的业务模块是a、b、c、d、e,新客户B需要的业务模块是a、c、e、f、g,我们只需要把A客户的系统删除b、d模块,新增f模块就可以了,但是这样就会出现一个问题,A、B两个客户的系统存在严重的代码耦合(耦合a、c、e模块)。

有同事提出了解决方案,“我们做一个标准版的系统吧,包括a、b、c、d、e、f、g、…所有的业务模块!”这就是我司目前的做法。看似是一个不错的想法,但是把所有模块都集中在一个系统中,导致war包过大,代码过多,运维困难,一个错误可能导致系统无法运行。

我一直在思考,能不能把业务模块单独拿出来做成系统,单独部署,假如又有新客户C需要的业务模块是c、d、f,那么我们就可以从中选择这几个系统进行组合,能够达到组合的效果。这就是我学习spring could的动机(虽然我给公司这样建议了没被采纳!)。

这里写图片描述

在我的方案中,主要解决两个问题:

1)模块之间的耦合
2)模块的复用

2 微服务架构原理

2.1 传统开发模式——单应用架构

先来看一下传统的开发模式,也就是现在我司的开发模式:所有的模块都打包在一个war包里,部署在tomcat里,基本没有外部依赖,这就导致了很多缺点,例如:

1)效率低:开发都在同一个项目改代码,相互等待,冲突不断
2)维护难:代码功功能耦合在一起,新人不知道何从下手
3)不灵活:构建时间长,任何小修改都要重构整个项目,耗时
4)稳定性差:一个微小的问题,都可能导致整个应用挂掉
5)扩展性不够:无法满足高并发下的业务需求

这里写图片描述

2.2 微服务架构——多应用架构

微服务架构是将一个大型复杂软件分成多个子软件,或者称为子服务。各个子软件可被独立部署,这样就解决了模块之间耦合的问题,每一个子软件仅仅关注于完成一件任务,并提供服务,不去关注其他业务模块。模块与模块之间只通过接口进行关联,只关注接口,开发人员只对接口负责。
优点可以总结为:

1)每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求
2)一个团队的新成员能够更快投入生产
3)微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合
4)每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库

这里写图片描述

3 spring-cloud-Netflix-Eureka实现多服务注册及服务之间的相互调用

spring cloud提供了一个服务注册管理中心Eureka,每一个服务(子软件)都可将自己提供的服务在注册中心登记,如果想要寻找某一个服务,在服务注册中心就能够轻松的找到。以点买卖为例:饿了吗客户端就相当于一个餐厅注册中心,客户通过饿了吗查找特定的餐厅(寻找服务),每个餐厅提供一种服务。

3.1 创建服务注册中心

spring cloud是基于spring boot的,所以我们创建一个spring boot项目,命名为elema-eureka,pom文件如下:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

在src/main/resources目录下新建配置文件application.yml,并在其中配置启动端口,有一点需要特别注意,其实eureka服务注册中心其实也是一个服务,默认情况下,eureka会把自己当成一个服务去注册,我们可以在配置文件中禁止这个行为,application.yml文件内容如下:

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

接下来创建spring boot项目启动类,ServerApp.java,使用@EnableEurekaServer注解把该项目标记为eureka注册中心,内容如下:

@SpringBootApplication
@EnableEurekaServer
public class ServerApp {

    public static void main(String[] args) {
        new SpringApplicationBuilder(ServerApp.class).web(true).run(args);
    }

}

启动项目后,我们就可以访问eureka服务中心可视化界面了。localhost:8761,能够在该页面中清楚的看到哪些服务已经注册了。
这里写图片描述

3.2 创建服务,注册服务

同样是先创建一个spring boot项目,命名为restaurantA,pom文件内容如下:

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
    </dependencies>

在src/main/resources目录下新建配置文件application.yml,并在其中配置启动端口,服务名称,及服务注册地址。服务注册地址就写eureka的地址即可,内容如下:

spring:
  application:
    name: restaurantA
server:
  port: 8081
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

然后编写一个服务提供类,命名为RestaurantController.java,并使用@RestController注解向外提供服务,内容如下:

@RestController
public class RestaurantController {

    @RequestMapping(value = "/call", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public String call() {
        return "restaurantA is open!";
    }
}

编写启动类后,然后启动,我们发现在eureka服务中心多了一个名为restaurantA的服务。
这里写图片描述

3.3 创建用户,调用restaurantA服务

有很多博客区分了服务提供者和服务使用者,其实在某种意义上来说,服务提供者和使用者是没有明确界限的,一个项目既可以做服务提供者也可以做使用者。

同样创建一个spring boot项目,pom文件内容如下,增加了对JSP支持的依赖:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.7</java.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</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>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- JSP support -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

    </dependencies>

配置文件application.yml,虽然userA不向外提供服务,但仍然可以向eureka注册,其实也为了能够调用在eureka上注册的其他服务。同时也增加了对JSP文件的支持,可参考spring mvc的配置,内容如下:

spring:
  application:
    name: userA
  mvc:
    view:
      prefix: /WEB-INF/jsp/
      suffix: .jsp
  http:
    encoding:
      force: true
      charset: UTF-8
      enabled: true
server:
  port: 8089
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

下面编写订餐OrderController.java,并提供JSP订餐页面,代码如下:

@Controller
@Configuration
public class OrderController {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    /**
     * 跳转到订餐页面
     * @param request
     * @return
     */
    @RequestMapping("/toPage")
    public String toList(HttpServletRequest request){
        return "page/orderDinner/list";
    }

    @GetMapping("/order")
    @ResponseBody
    public String router() {
        RestTemplate tpl = getRestTemplate();
        String result = tpl.getForObject("http://restaurantA/call", String.class);
        return result;
    }

}

编写启动类,然后启动,访问订餐页面:http://localhost:8089/toPage,然后点击“调用订餐按钮”即可调用restaurantA提供的服务!
这里写图片描述

这里写图片描述

3.4 小节

上面一共创建了3个项目, elema-eureka:服务注册中心, restaurantA、userA:服务提供者,三者之间的关系如下:

这里写图片描述

参考:
【 微服务架构设计】https://www.cnblogs.com/wintersun/p/6219259.html
【微服务架构】https://www.cnblogs.com/imyalost/p/6792724.html

猜你喜欢

转载自blog.csdn.net/disiwei1012/article/details/80027909
今日推荐