spring cloud 教程

spring-cloud 与dubbo 比较

spring-cloud 比dubbo 更松耦合

不再需要打service的 jar

基本相当于http请求,但不需要知道http请求的ip或域名,用每个服务注册的服务名调用

直接把请求结果转成对象


cloud 部署步骤

1)服务注册服务器   因为所有的其他服务都要注册到这里,获得从这里发现服务 

(2)分布式配置管理服务器       用来部署远程的配置文件
(3)分布式配置管理服务端(微服务应用)   相当于业务逻辑服务端,通过web接口暴露
(4)spring boot风格的web前端应用             调用业务逻辑服务端
(5)使用docker发布应用

eureka注册服务器

服务注册与发现对于微服务系统来说非常重要。有了服务发现与注册,你就不需要整天改服务调用的配置文件了,你只需要使用服务的标识符,就可以访问到服务。

  • cloud-eureka-server:eureka注册服务器
  • cloud-simple-service:一个使用mybatis的数据库应用,服务端

  服务注册管理器原理如下图所示:

      spring cloud 教程  

  所有的服务端及访问服务的客户端都需要连接到注册管理器(eureka服务器)。服务在启动时会自动注册自己到eureka服务器,每一个服务都有一个名字,这个名字会被注册到eureka服务器。使用服务的一方只需要使用该名字加上方法名就可以调用到服务。

  Spring cloud的服务注册及发现,不仅仅只有eureka,还支持Zookeeper和Consul。默认情况下是eureka,spring 封装了eureka,使其非常简单易用,只需要比传统应用增加一行代码就可以使用了,这一行代码就是一个注解。我们按以下步骤实现服务注册和发现功能。

  1)首选需要建立eureka服务器

  创建spring cloud eureka服务器和创建之前那个配置文件服务器类似,你只需要创建一个空的maven工程,并引入spring boot的相关starter即可,然后创建一个近乎空的执行类,工程如下图:

 spring cloud 教程

  在EurekaServer类中我们加入如下代码:

  @SpringBootApplication

  @EnableEurekaServer

  public class EurekaServer {

    public static void main(String[] args) {

    SpringApplication.run(EurekaServer.class, args);

      }

  }

  可以看到只需要使用@EnableEurekaServer注解就可以让应用变为Eureka服务器,这是因为spring boot封装了Eureka Server,让你可以嵌入到应用中直接使用。至于真正的EurekaServer是Netflix公司的开源项目,也是可以单独下载使用的。

  在application.properties配置文件中使用如下配置:

  server.port=8761

  eureka.instance.hostname=localhost

  eureka.client.registerWithEureka=false

  eureka.client.fetchRegistry=false

  eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

  其中server.port配置eureka服务器端口号。Eureka的配置属性都在开源项目spring-cloud-netflix-master中定义(spring boot连文档都没有,只能看源码了),在这个项目中有两个类EurekaInstanceConfigBean 和EurekaClientConfigBean,分别含有eureka.instance和eureka.client相关属性的解释和定义。从中可以看到,registerWithEureka表示是否注册自身到eureka服务器,因为当前这个应用就是eureka服务器,没必要注册自身,所以这里是false。fetchRegistry表示是否从eureka服务器获取注册信息,同上,这里不需要。defaultZone就比较重要了,是设置eureka服务器所在的地址,查询服务和注册服务都需要依赖这个地址。

  做完这些后当然,还要改一下pom文件,增加eureka-server的starter即可:

  <dependency>

                            <groupId>org.springframework.cloud</groupId>

                            <artifactId>spring-cloud-starter-eureka-server</artifactId>

  </dependency>

  如此eureka服务器就完成了,在命令行启动就可以了。

  2)让服务使用eureka服务器

  让服务使用eureka服务器,只需添加@EnableDiscoveryClient注解就可以了。回到我们在上篇文章中实现的cloud-simple-service微服务应用。在main方法所在的Application类中,添加@EnableDiscoveryClient注解。然后在配置文件中添加:

  eureka.client.serviceUrl.defaultZone=http\://localhost\:8761/eureka/

  spring.application.name=cloud-simple-service

  其中defaultZone是指定eureka服务器的地址,无论是注册还是发现服务都需要这个地址。application.name是指定进行服务注册时该服务的名称。这个名称就是后面调用服务时的服务标识符(这是服务发现的功能,我们在后面章节具体介绍)。当然,pom文件也需要增加:

  <dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-eureka</artifactId>

  </dependency>

  如此以来该服务启动后会自动注册到eureka服务器。如果在该服务中还需要调用别的服务,那么直接使用那个服务的服务名称加方法名构成的url即可,具体我们将在下章结合ui端的应用具体介绍。

分布式管理


  • cloud-config-repo:配置文件存放的文件夹
  • cloud-simple-service:一个使用mybatis的数据库应用

   分布式配置管理应该是分布式系统和微服务应用的第一步。想象一下如果你有几十个服务或应用需要配置,而且每个服务还分为开发、测试、生产等不同维度的配置,那工作量是相当大的,而且还容易出错。如果能把各个应用的配置信息集中管理起来,使用一套机制或系统来管理,那么将极大的提高系统开发的生产效率,同时也会提高系统开发环境和生产环境运行的一致性。

  spring cloud 教程

  在传统开发中我们往往需要自己开发“配置管理服务器”,你可以使用redis、ldap、zookeeper、db等来存放统一配置信息,然后开发一个管理界面来进行管理。传统的做法没什么问题,和spring cloud所提供的配置管理方案相比,就是前者需要自己开发,而后者直接简单使用现成的组件即可。当然还有很重要的一点,spring 配置管理模块由于是spring boot核心来实现的,因此做了大量的工作,可以把一些启动参数进行外部配置,这在传统的方案中是很难办到的,因为涉及到要改写第三方组件的问题,难度很大。比如web应用的绑定端口,传统应用只能在tomcat配置文件里改,而spring cloud却可以放到远程,类似的还有数据库连接、安全框架配置等。

  要使用spring cloud分布式配置文件总体上分为3个大的步骤,首选你需要创建存放配置文件的仓库,然后创建一个配置文件服务器,该服务器将配置文件信息转化为rest接口数据,然后创建一个应用服务,该服务演示使用分布式配置文件信息。

  1)创建配置文件存放仓库

  Spring cloud使用git或svn存放配置文件,默认情况下使用git,因此你需要安装git私服或者直接使用互联网上的github或者git.oschina,这里推荐使用git.oschina。本文示例使用的是git.oschina,创建好git工程后,也就是文章开头所提到的工程,在此工程再创建一个文件夹cloud-config-repo来存放配置文件。然后创建两个配置文件:

  • cloud-config-dev.properties
  • cloud-config-test.properties

      这两个文件分别对应开发环境和测试环境所需要的配置信息,配置信息如下:

  mysqldb.datasource.url=jdbc\:mysql\://10.0.12.170\:3306/test?useUnicode\=true&characterEncoding\=utf-8

  mysqldb.datasource.username=csst

  mysqldb.datasource.password=csst

  logging.level.org.springframework.web:DEBUG

  配置信息提供了数据库连接参数等,这是因为后面的应用服务中使用到了数据库。

  2)创建spring cloud配置服务器

  配置文件仓库创建好了后,就需要创建配置管理服务器,如前所述该服务器只是将配置文件转换为rest接口服务,不做其它用途。这个服务器的功能也是spring cloud提供的,所以我们只需要引入相关jar包,稍微设置一下即可。创建该服务应用,你需要首选创建一个空的maven工程:

        spring cloud 教程

  然后在这个工程中增加一个类,命名为:ConfigServerApplication,代码如下:

  @SpringBootApplication

  @EnableConfigServer

  public class ConfigServerApplication {

           public static void main(String[] args) {

            SpringApplication.run(ConfigServerApplication.class, args);

           }

  }

  可以看到,我们只需要用@EnableConfigServer**该应用为配置文件服务器即可。如此以来该应用启动后就会完成前面提到的功能,即:读取远程配置文件,转换为rest接口服务。

当然,需要配置远程配置文件读取路径,在application.properties中:

  server.port=8888

  spring.cloud.config.server.git.uri=https://git.oschina.net/zhou666/spring-cloud-7simple.git

  spring.cloud.config.server.git.searchPaths=cloud-config-repo

  其中server.port是配置当前web应用绑定8888端口,git.uri指定配置文件所在的git工程路径,searchPaths表示将搜索该文件夹下的配置文件(我们的配置文件放在spring-cloud-7simple这个工程的cloud-config-repo文件夹下)。

  最后,还需要在pom文件中增加配置服务器的相关依赖:

  <dependency>

                     <groupId>org.springframework.cloud</groupId>

                     <artifactId>spring-cloud-config-server</artifactId>

  </dependency>

  如此以来,配置文件服务器就建立好了,可以直接启动了,服务端口是8888,应用只需要绑定改服务器的uri和端口号就可以拿到配置信息了。



cloud服务端

现在可以创建一个服务使用该远程配置了,你可以在远程配置中定义一个简单的自定义信息,比如:

  my.message=helloword

  然后使用前面我们提到的spring boot helloworld应用来读取这个信息。当然,限于篇幅我们直接使用比较复杂的一个服务来演示这个配置管理器的使用,这个服务需要用到数据库访问,数据库访问层我们使用的是mybaits,数据表只有一个,DDL如下:

  CREATE TABLE `user` (

       `id` varchar(50) NOT NULL DEFAULT '',

       `username` varchar(50) DEFAULT NULL,

       PRIMARY KEY (`id`)

  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  创建好数据表后,回到我们的应用服务:

 spring cloud 教程

  该服务使用DataSourceProperties封装了mybatis加载配置信息。要拿到远程配置信息,需要设置配置管理服务器地址,该配置设置在:

  bootstrap.properties

  该配置文件信息如下:

  spring.cloud.config.uri=http://127.0.0.1:${config.port:8888}

  spring.cloud.config.name=cloud-config

  spring.cloud.config.profile=${config.profile:dev}

  其中config.uri指定远程加载配置信息的地址,就是前面我们刚建立的配置管理服务器的地址,绑定端口8888,其中config.port:8888,表示如果在命令行提供了config.port参数,我们就用这个端口,否则就用8888端口。config.name表示配置文件名称,查看我们前面创建配置文件,是这个名称:

  cloud-config-dev.properties

  可以分成两部分: {application}- {profile}.properties

  所以我们配置config.name为cloud-config,config.profile为dev,其中dev表示开发配置文件,配置文件仓库里还有一个测试环境的配置文件,切换该配置文件只需要将dev改为test即可,当然这个参数也可以由启动时命令行传入,如:

  java -jar cloud-simple-service-1.0.0.jar --config.profile =test

  此时应用就会加载测试环境下的配置信息。



cloud 客户端及断路器

断路器是指当远程服务断掉后,调用元成都武出错会自动转到其他自定义方法上。

  • cloud-config-server:配置服务器
  • cloud-eureka-server:eureka注册服务器
  • cloud-simple-service:一个使用mybatis的数据库应用,服务端
  • cloud-simple-ui:webui客户端

  我们先来看看如何实现webui客户端。在spring boot中,已经不推荐使用jsp,所以你如果使用jsp来实现webui端,将会很麻烦。这可能跟现在的开发主流偏重移动端有关,跟微服务有关,跟整个时代当前的技术需求有关。单纯以html来作为客户端,有很多好处,比如更利于使用高速缓存;使后台服务无状态话,更利于处理高并发;更利于页面作为服务,小服务组合成大服务等。

  我们首选来创建webui应用,参考git cloud-simple-ui工程:

   spring cloud 教程

         这个应用包括前端html页面,还包括一个后台controller浅层。这是一个前端应用,为什么要包括controller浅层?这是因为这个controller浅层是用来做服务组合的,因为一个页面可能涉及到调用多个服务,而这些服务又有可能涉及事务和并发问题,所以还是需要靠java来完成。当然,也可以单独编写一个api gateway来实现这一层,可以使用go、node.js语言等,也可以使用java/netty(主流还是java,因为开发部署效率高)。

       Controller层的WebApplication就是这个应用的入口,代码如下:

  @SpringBootApplication

  @EnableEurekaClient

  @EnableHystrix

  public class WebApplication {

         public static void main(String[] args) throws Exception {

               SpringApplication.run(WebApplication.class, args);

    }

  }

  这些注解大都在前面提到过用法:

  @SpringBootApplication相当于@Configuration、@EnableAutoConfiguration、@ComponentScan三个注解合用。

  @EnableEurekaClient配置本应用将使用服务注册和服务发现,注意:注册和发现用这一个注解。

  @EnableHystrix表示启用断路器,断路器依赖于服务注册和发现。

  Controller层的service包封装了服务接口访问,UserService类代码如下:

  @Service

  public class UserService {

          @Autowired

    RestTemplate restTemplate; 

    final String SERVICE_NAME="cloud-simple-service";        

     @HystrixCommand(fallbackMethod = "fallbackSearchAll")

    public List<User> searchAll() {

      return restTemplate.getForObject("http://"+SERVICE_NAME+"/user", List.class);

    }   

    private List<User> fallbackSearchAll() {

               System.out.println("HystrixCommand fallbackMethod handle!");

               List<User> ls = new ArrayList<User>();

               User user = new User();

               user.setUsername("TestHystrix");

               ls.add(user);

               return ls;

    }

  }

  这里使用了断路器,就是@HystrixCommand注解。断路器的基本作用就是@HystrixCommand注解的方法失败后,系统将自动切换到fallbackMethod方法执行。断路器Hystrix具备回退机制、请求缓存和请求打包以及监控和配置等功能,在这里我们只是使用了它的核心功能:回退机制,使用该功能允许你快速失败并迅速恢复或者回退并优雅降级。

  这里使用restTemplate进行服务调用,因为使用了服务注册和发现,所以我们只需要传入服务名称SERVICE_NAME作为url的根路径,如此restTemplate就会去EurekaServer查找服务名称所代表的服务并调用。而这个服务名称就是在服务提供端cloud-simple-service中spring.application.name所配置的名字,这个名字在服务启动时连同它的IP和端口号都注册到了EurekaServer。

  封装好服务调用后,你只需要在Controller类里面注入这个服务即可:

  @RestController

  public class UserController {       

       @Autowired

       UserService userService;      

       @RequestMapping(value="/users")

       public ResponseEntity<List<User>> readUserInfo(){

              List<User> users=userService.searchAll();         

              return new ResponseEntity<List<User>>(users,HttpStatus.OK);

       }

  }

  至此这个webui应用的java端就开发完了,我们再来看页面模块。

  可以看到,页面文件都放在resources\static目录下面,这是spring boot默认的页面文件主文件夹,你如果在里面放一个index.html,那么直接访问根路径http://localhost:8080/会直接定位到这个页面。所以这个static就相当于传统web项目里面的webapp文件夹。

  在这里包括两个页面index.html和user-page.html,用户访问首页时将会加载user-page.html子页面。

  首页index.html页面核心代码如下:

  <html ng-app="users">

  <head>   

    <script src="js/app.js"></script>

  </head>

  <body>

  <div ng-view class="container">

  </div>

  </body>

  </html>

  页面user-page.html代码如下:

  <div>

  <ul ng-controller="userCtr">

    <li ng-repeat="item in userList">

  {{item.username}}   

  </li>

  </ul>

  </div>

  app.js页面代码如下:

  angular.module('users', ['ngRoute']).config(function ($routeProvider) {

  $routeProvider.when('/', {

        templateUrl: 'user-page.html',

        controller: 'userCtr'

  })

  }).controller('userCtr', function ($scope, $http) {

  $http.get('users').success(function (data) {

           //alert(data+"");

        $scope.userList = data;

  });

  });

  这里使用了angularJS库。Angular可以绑定模型数据到页面变量,在user-page.html看到的{{item.username}}就是它的绑定语法,这个语法根jsp或freemarker这些模板技术都类似,只不过Angular是用在客户端的,而前者是用在服务端的。

  至此这个webui应用就开发完了,改一下配置文件和pom文件就可以运行了。配置文件包括配置管理服务器地址,注册服务器地址等,在bootstrap.properties文件中:

  spring.cloud.config.uri=http://127.0.0.1:${config.port:8888}

  spring.cloud.config.name=cloud-config

  spring.cloud.config.profile=${config.profile:dev}

  eureka.client.serviceUrl.defaultZone=http\://localhost\:8761/eureka/

  spring.application.name=simple-ui-phone

  这些配置我们在上一章已经提到过了,这里不再解释。因为使用了断路器,所以相比上一章的cloud-simple-service项目,需要加入hystrix依赖,只有一个starter依赖:

  <dependency>

    <groupId>org.springframework.cloud</groupId>

  <artifactId>spring-cloud-starter-hystrix</artifactId>

  </dependency>

  Spring把事情做的如此简单,不管是服务注册还是断路器,连同注解加配置文件再加上依赖总共不超过十行代码。如此简单就可以使用一个分布式应用,也难怪国内外业内人员都高度重视这个框架,在简单和速度就是硬道理的今天,这个框架有着重要的意义。

   剩下最重要的事情就是进行部署了,我们以此使用命令启动这些服务及应用:

  1)  java -jar cloud-config-server-0.0.1.jar,启动配置服务器,固定绑定端口8888;

  2)  java -jar cloud-eureka-server-1.0.0.jar,启动注册服务器,固定绑定端口8671;

  3)  java -jar cloud-simple-service-1.0.0.jar --server.port=8081 >log8081.log,启动后台服务,绑定端口8081

  4)  java -jar cloud-simple-service-1.0.0.jar --server.port=8082 >log8082.log,启动后台服务,绑定端口8082

  5)  java -jar cloud-simple-ui-1.0.0.jar --server.port=8080 >log8080.log,启动前端ui应用,绑定端口8080

  运行http://localhost:8080/即可看到运行的结果。其中“>log8080.log”表示输出日志到文件。

  这里运行了两个cloud-simple-service实例,主要是为了演示ribbon负载均衡。默认情况下使用ribbon不需要再作任何配置,不过它依赖于注册服务器。当然也可以对ribbon进行一些自定义设置,比如配置它的超时时间、重试次数等。启用了负载均衡后,当我们关掉前端页面上次指向的服务时(从日志中看),比如我们刷新页面看到它调用的是8081服务,那么我们关掉这个服务。关掉后再刷新会发现执行了断路器,过几秒再刷新,它已经切换到了8082这台服务器,这说明负载均衡起作用了。


创建docker 应用

本文涉及到的项目:

  cloud-simple-docker:一个简单的spring boot应用

  Docker是一种虚拟机技术,准确的说是在linux虚拟机技术LXC基础上又封装了一层,可以看成是基于LXC的容器技术。可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。容器是用来装东西的,Docker可以装载应用本身及其运行环境进容器,这是一个很小的文件,然后把这个文件扔到任何兼容的服务器上就可以运行,也是基于这一点,Docker可以同时让应用的部署、测试和分发都变得前所未有的高效和轻松!

   下面例子参考“Spring Boot with Docker”官方例子。

  1)建立一个简单的应用,只有一个类,包含main方法,代码如下:

  @SpringBootApplication

  @RestController

  public class Application {

  @RequestMapping("/")

  public String home() {

        return "Hello Docker World";

  }

  public static void main(String[] args) {

        SpringApplication.run(Application.class, args);         

  }

  }

  2)建立Dockerfile

  # 基于那个镜像

  FROM daocloud.io/java:8

  # 将本地文件夹挂载到当前容器(tomcat使用)

  VOLUME /tmp

  # 拷贝文件到容器

  ADD cloud-simple-docker-1.0.0.jar /app.jar

  # 打开服务端口

  EXPOSE 8080

  # 配置容器启动后执行的命令

  ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

  这里特别要注意,这里的FROM采用国内的docker镜像,如果连国外的docker镜像下载,基本是不太可能下载下来的,原因大家都知道。

  有了Dockerfile,就可以部署docker了。

  3)部署docker示例

  部署分为2步,分别是创建镜像、运行。

  • 创建镜像

  将编译后的jar文件考到服务器某个目录,这里是tmp目录。然后将Dockerfile也考到该目录,最后进入到该目录下运行命令:

  docker build  -t  local/cloud-docker-hello .

  别掉了后面的“.”符号,这个符号表示目录,这个命令执行成功,你会看到以下界面:

   spring cloud 教程

  运行成功后,就创建了一个镜像,可以使用docker images来查看该镜像。

  • 运行镜像

  有了镜像就可以运行了,使用下面命令运行:

  docker run -p 8080:8080 –t  local/cloud-simple-docker

  其中8080:8080表示本机端口映射到Docker实例端口。如果本机端口没有打开,还需要打开该端口,打开端口在centos 7中使用firewall-cmd命令:

  firewall-cmd --zone=public --add-port=8080/tcp --permanent

  firewall-cmd –reload

  成功后可以使用docker ps –a查看镜像运行情况:

  local/cloud-docker-hello | latest | 3ef51d55eb27 | 22 minutes ago | 667.2 MB

  可以看到这个包括了java运行环境的web应用镜像是667MB。

  该步骤运行结果如下:

   spring cloud 教程

  最后使用curl命令或者直接在浏览器打开,可以直接测试该应用。使用curl命令如下:

  curl http://localhost:8080

  返回:Hello Docker World

  docker应用,水比较深,这里只是举一个hello world级别的例子。Spring Boot with Docker例子还提供了一个maven插件docker-maven-plugin,这个插件可以直接将项目编译为docker镜像。另外这个插件还可以让你结合jenkins完成项目的持续集成和自动部署。具体来说就是jenkins自动通过git或svn拉到工程代码,然后使用maven进行编译,再调用项目中的Dockerfile生成镜像。如此以来不管是什么应用,只需要部署docker就可以了,那些配置,那些乱七八糟的环境搭建都不需要了。

原文:http://www.cnblogs.com/skyblog/p/5127690.html